Java中数据传输加密与签名那些事

引言 
在日常开发中我们对HTTP数据传输并不陌生,前端需要与后端进行数据交互往往需要调用后端某个API,然而在前端与后端的请求过程中数据真的安全吗?下面了解一件关于0.01购买phone事件;
事件在之前报导一个新闻,某个电商App应用因为程序Bug,被灰色产业0.01元撸走千台iphone手机,损失近千万,后来了解到也并非高手所为,其实就是该APP在购买接口中对数据传输缺少安全防范,通过HTTP抓包工具对传输中的数据进行修改,将原本几千元的iPhone手机价格修改为0.01进行购买;
案例看完以上事件部分人可能还是不太抓包的概念,所谓抓包就是依赖某个工具,对客户端与服务端进行请求、或者对服务端对客户端响应时过程中进行拦截,可以将其请求数据或响应数据进行篡改;
为了能更好了解,这里我准备了一个模拟购买接口:

Java中数据传输加密与签名那些事

文章插图
 
这里模拟前端正常调用购买接口;
http://localhost:8080/test?money=6000按理后端应该会输出6000,这里我利用fiddle抓包工具对该请求进行拦截,将money参数改为1;
Java中数据传输加密与签名那些事

文章插图
 

Java中数据传输加密与签名那些事

文章插图
【Java中数据传输加密与签名那些事】 
成功将合法价格改为非法价格,如果后端接口验证不注意即会按照该金额生成订单,则支付1元即可买到高额商品;
 
原由导致以上事件发生无非就两种情况:
1.对敏感数据使用明文传输;
2.在前端进行校验后,后端接口并未对数据第二次校验;
 
如何解决?在数据传输过程中对敏感数据进行加密,即使请求被截获,也只能获取到密文信息,无法篡改具体需要修改的数据;
传输过程中使用的加密方式通常分为两类:对称加密/非对称加密;
对称加密:市场上用的比较多的对称加密有DES、AES、3DES等,对称加密的流程是通过生成一把秘钥,分别存储客户端以及服务端各自一份,客户端在请求服务端前先将传输的数据通过该秘钥进行加密,服务端接收到请求之后,先将数据用该秘钥进行解密再进行处理,从而避免数据在传输中被篡改;
Java中数据传输加密与签名那些事

文章插图
 
缺点:该秘钥在客户端加密与服务端解密使用的是同一把,而存储在客户端的秘钥并无法避免泄漏的风险,通过反编译等手段获取到秘钥,那么传输过程中拦截请求则照样可以解密密文数据进行篡改;
Des加密案例:
 
public class DesDecrypt {//加密字段private static String src = https://www.isolves.com/it/cxkf/yy/JAVA/2020-03-10/"JAVA资料社区";public static void main(String[] args) {jdkDES();bcDES();}/*JDK实现*/public static void jdkDES() {try {//生成KEYKeyGenerator keyGenerator = KeyGenerator.getInstance("DES");keyGenerator.init(56);SecretKey secretKey = keyGenerator.generateKey();byte[] bytesKey = secretKey.getEncoded();//KEY转换DESKeySpec desKeySpec = new DESKeySpec(bytesKey);SecretKeyFactory factory = SecretKeyFactory.getInstance("DES");Key convertSecretKey = factory.generateSecret(desKeySpec);//加密Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");cipher.init(Cipher.ENCRYPT_MODE, convertSecretKey);byte[] result = cipher.doFinal(src.getBytes());System.out.println("jdk des encrypt : " + new String(Hex.encode(result)));//解密cipher.init(Cipher.DECRYPT_MODE, convertSecretKey);result = cipher.doFinal(result);System.out.println("jdk des decrypt : " + new String(result).toString());} catch (Exception e) {e.printStackTrace();}}/*BC实现*/public static void bcDES() {try {Security.addProvider(new BouncyCastleProvider());//生成KEYKeyGenerator keyGenerator = KeyGenerator.getInstance("DES", "BC");keyGenerator.getProvider();keyGenerator.init(56);SecretKey secretKey = keyGenerator.generateKey();byte[] bytesKey = secretKey.getEncoded();//KEY转换DESKeySpec desKeySpec = new DESKeySpec(bytesKey);SecretKeyFactory factory = SecretKeyFactory.getInstance("DES");Key convertSecretKey = factory.generateSecret(desKeySpec);//加密Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");cipher.init(Cipher.ENCRYPT_MODE, convertSecretKey);byte[] result = cipher.doFinal(src.getBytes());System.out.println("bc des encrypt : " + new String(Hex.encode(result)));//解密cipher.init(Cipher.DECRYPT_MODE, convertSecretKey);result = cipher.doFinal(result);System.out.println("bc des decrypt : " + new String(result).toString());} catch (Exception e) {e.printStackTrace();}}}//运行结果//jdk des encrypt : ab6afc9a81584573cf2f50ceccd28628bd10885ebd84f37c//jdk des decrypt : Java资料社区//bc des encrypt : 34fd3ed3d0b6d5ab7baf6db300420f3c4094a2061bb2dd34//bc des decrypt : Java资料社区


推荐阅读