Http请求加密规则(3DES、Base64、HMAC SHA256)

Http请求加密规则(3DES、Base64、HMAC SHA256)
如果使用了Https请求,那么大多数情况下就无需双方再制定一套加密规则,所以本人讲述的是使用Http请求时,对于一些安全性较高的业务场景,需要对请求进行加密的实现方式。

  1. 首先总结一下http请求的密钥和参数加密规则,可以根据自己项目进行修改:
    -关键词解释:

    • app-key和app-token:两个请求头,app-key是用户自己定义的,主要是用来进行请求权限控制,app-token采用JWT实现,不了解的可以去查一下JWT。
    • 参数密钥、签名密钥、AppKey密钥:参数密钥是对请求参数进行加密的;签名密钥是在生成JWT通讯令牌(即请求头中的app-token)时采用HMAC SHA256散列算法所用到的;App-Key密钥是对请求头中的app-key进行加密的。

    在这里插入图片描述
    在这里插入图片描述

  2. 下面开始讲述具体加密的实现方式:

    • 如第一步中所讲,参数加密是采用先3DES加密,然后再进行Base64编码,代码实现如下:
/**
* 
* @Description:先3des加密,然后base64编码
* @param key
* @param data
* @return
*/
public static String encrypt3DESAndBase64(String key, String data){
	byte[] result3Des = encrypt3DES(build3DesKey(key),data,"GBK");
	String result = encryptBASE64(result3Des);
	return result;
}

/**
* 不满足24位的数据补充到24位
* @param key
* @return
*/
private static String build3DesKey(String key) {
	return String.format("%-24s", key).replace(' ', '0');
}

/**
* @Description:使用3DES算法加密
* @param key 密钥
* @param data 待加密数据
*  @param charset 字符编码
* @return
*/
public static byte[] encrypt3DES(String key, String data, String charset){ 

	try { 
		byte[] keyByte = key.getBytes(charset);
		byte[] dataByte = data.getBytes(charset);

		//生成密钥 
		SecretKey deskey = new SecretKeySpec(keyByte, "DESede");
		//加密 
		Cipher c1 = Cipher.getInstance("DESede");
		c1.init(Cipher.ENCRYPT_MODE, deskey); 
		return c1.doFinal(dataByte); 

	} catch (Exception e) {
		logger.error("encrypt3DES occur error",e);
	} 
	return null; 
} 

/**
* 
* @Description:对数据进行base64编码
* @param data
* @return
*/
public static String encryptBASE64(byte[] data) {
	try {
		return Base64Utils.encodeToUrlSafeString(data);
	} catch (Exception e) {
		logger.error("encryptBASE64 occur error",e);
		return null;
	}
}
  • 对应的解密实现方式如下:
/**
* 
* @Description:先base64解码,然后再3des解密
* @param key
* @param data
* @return
*/
public static String decrypt3DESAndBase64(String key, String data) {
	String result = "";
	if(null != data && !data.isEmpty()) {
		byte[] resultDecryBase64 = decryptBASE64(data);
		result = decrypt3DES(build3DesKey(key),resultDecryBase64,"GBK");
	}
	return result;
}

/**
* 
* @Description:使用3DES算法解密
* @param key 密钥
* @param data 待解密数据
* @return
*/
public static String decrypt3DES(String key, byte[] data, String charset){

	try { 
		byte[] keyByte = key.getBytes(charset);
		//生成密钥 
		SecretKey deskey = new SecretKeySpec(keyByte, "DESede"); 
		Cipher cipher = Cipher.getInstance("DESede");
		cipher.init(Cipher.DECRYPT_MODE,deskey);
		byte[] resultByte = cipher.doFinal(data);
		return new String(resultByte, charset);
	} catch (Exception e) {
		logger.error("decrypt3DES occur error",e);
	} 
	return null;
}

/**
 - 
 - @Description:对数据进行base64解码
 - @param data 待解码数据
 - @return
*/
public static byte[] decryptBASE64(String data) {
	try {
		return Base64Utils.decodeFromUrlSafeString(data);
	} catch (Exception e) {
		logger.error("decryptBASE64 occur error");
		return null;
	}
}
  • 生成app-token即通讯令牌:生成app-token采用的是JWT提供的jar包来生成的,该jar包的maven依赖为:
 <dependency>
            <groupId>com.nimbusds</groupId>
            <artifactId>nimbus-jose-jwt</artifactId>
            <version>4.23</version>
</dependency>

对于JWT的原理下面简单介绍一下:
jwt主要由三部分构成,第一部分为头部(header),第二部分为载荷(payload,该次请求承载的一些非敏感数据),第三部分是签证(signature)。

jwt的头部承载两部分信息:
   声明类型,我们采用jwt
   声明加密的算法,HMAC SHA256, 
jwt的载荷构成: 
	iss: jwt签发者,根据自己的项目进行定义
   	sub: jwt所面向的用户,双方约定的地方三方平台代码 
	exp: jwt的过期时间,这个过期时间必须要大于签发时间(毫秒),两边服务器时间需要同步,我们约定为3秒 
	iat: jwt的签发时间(毫秒)
jwt的签名: 
	jwt的第三部分是一个签证信息,这个签证信息由三部分组成:
	 header   (base64后的) 
	 payload (base64后的) 
	 secret(双方共同约定的密钥)
	 这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行secret组合加密,然后就构成了jwt的第三部分。

示例:
Jwt Header头:
{“type”: “JWT”,“alg”: “HS256”}
Jwt payload:
{
“iss”:“epay”,
“sub”: “sinodata”,
“exp”: 1516239028,
“iat”: 1516239023
}
Jwt signature:
QowRE42QP3pMc-4fXzM1xouTnsGBYBw4EE0LNq-Dop0
生成Token :
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJlcGF5Iiwic3ViIjoic2lub2RhdGEiLCJleHAiOjE1MTYyMzkwMjIsImlhdCI6MTUxNjIzOTAyOH0.QowRE42QP3pMc-4fXzM1xouTnsGBYBw4EE0LNq-Dop0


生成jwt 的app-token代码如下:


/**
* 
* @Description: 生成jwt token
* @param secret
* @param header
* @param payload
* @return
*/
public static String createToken(byte[] secret,JWSHeader header,Payload payload) {

	String tokenString=null;
	// 创建一个 JWS object
	JWSObject jwsObject = new JWSObject(header,payload);
	try {
		// 将 jwsObject 进行 HMAC签名
		jwsObject.sign(new MACSigner(secret));
		tokenString=jwsObject.serialize();
	} catch (JOSEException e) {
		logger.error("jwt签名失败 !" ,e);
	}
	return tokenString; 
}

/**
*/
public static String generateToken() {

	try {
		Map<String,Object> headerMap=new HashMap<>();
		headerMap.put("type","jwt");
		headerMap.put("alg","HS256");
		Map<String,Object> payloadMap=new HashMap<>();
		payloadMap.put("iss","zhaoyi");
		payloadMap.put("sub","testCom");
		payloadMap.put("iat",System.currentTimeMillis());
		payloadMap.put("exp",((Long)payloadMap.get("iat"))+1800*1000);
		JWSHeader h = JWSHeader.parse(JSONObject.toJSONString(headerMap));
		Payload p = new Payload(JSONObject.toJSONString(payloadMap));
		return createToken("secret".getBytes("GBK"),h,p);
	} catch(Exception e) {
		logger.error("generateQfbToken occur error", e);
	return null;
	}
}
  • 在收到http请求后,校验token的有效性:
public static Map<String,Object> valid(String token, String secret){

Map<String, Object> resultMap = new HashMap<>();

try {

	//解析token
	JWSObject jwsObject = JWSObject.parse(token);
	
	//获取到载荷
	Payload payload=jwsObject.getPayload();
	
	//建立一个解锁密匙
	JWSVerifier jwsVerifier = new MACVerifier(secret);
	
	//判断token
	if (jwsObject.verify(jwsVerifier)) {
		resultMap.put("Result", 0);
	
		//把载荷的数据解析成json对象。
		JSONObject payLoadJsonStr = payload.toJSONObject();
		resultMap.put("data", payLoadJsonStr);
		System.out.println("---payLoadJsonStr--" + payLoadJsonStr);
		
		//判断token是否过期
		if (payLoadJsonStr.containsKey("exp")) {
			Long expTime = Long.valueOf(payLoadJsonStr.get("exp").toString());
			Long nowTime = System.currentTimeMillis();
			//判断是否过期
			if (nowTime > expTime) {
				//已经过期
				resultMap.clear();
				resultMap.put("Result", 2);
				return resultMap;
			}
		}
	
		//验证签发者
		if(payLoadJsonStr.containsKey("iss")) {
			if(!"zhaoyi".equals(payLoadJsonStr.get("iss"))) {
				resultMap.clear();
				resultMap.put("Result", 3);
				return resultMap;
			}
		}
		
		//验证面向的用户
		if(payLoadJsonStr.containsKey("sub")) {
			if(!"testCom".equals(payLoadJsonStr.get("sub"))) {
				resultMap.clear();
				resultMap.put("Result", 4);
				return resultMap;
			}
		}
	}else {
		resultMap.put("Result", 1);
	}
} catch (Exception e) {
	log.error("valid token occur error",e);
}
	return resultMap; 
}




  1. 最后,给大家额外提供HMAC SHA256的实现方式,因为生成app-token的时候是用到这种散列算法的,只不过我们用的是已封装好的jar包。
/**
* 
* @Description: 使用hmacSHA256进行加密
* @param data 加密数据
* @param key 密钥
* @return
* @throws Exception
*/
public static String encryptHmacSHA256(String key, String data) throws Exception { 

	SecretKey secretKey = new SecretKeySpec(key.getBytes(), "HmacSHA256"); 
	Mac mac = Mac.getInstance(secretKey.getAlgorithm()); 
	mac.init(secretKey); 
	
	return new String(mac.doFinal(data.getBytes())); 
}

最后,上述实现方式里的3DES为一种对称加密算法,当然也可以换成其它的对称加密算法,比如安全性更高的AES。如果大家实现过程中有什么问题,欢迎留言咨询。

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值