SpingBoot加解密项目spring-boot-starter-encrypt操作

Spring Boot封装了一个Starter, 内置了AES加密算法。GitHub地址如下:

spring-boot-starter-encrypt

先来看看怎么使用,可以下载源码,然后引入即可,然后在启动类上增加@EnableEncrypt注解开启加解密操作:

@EnableEncrypt
@SpringBootApplication
public class App {
	
    public static void main(String[] args) {
		SpringApplication.run(App.class, args);
    }
}

增加加密的key配置:

spring.encrypt.key=abcdef0123456789
spring.encrypt.debug=false
  • spring.encrypt.key:加密key,必须是16位
  • spring.encrypt.debug:是否开启调试模式,默认为false,如果为true则不启用加解密操作

为了考虑通用性,不会对所有请求都执行加解密,基于注解来做控制

响应数据需要加密的话,就在Controller的方法上加@Encrypt注解即可。

@Encrypt
@GetMapping("/list")
public Response queryNews(String city) {
	return Response.ok(city);
}

当我们访问/list接口时,返回的数据就是加密之后base64编码的格式。

还有一种操作就是前段提交的数据,分为2种情况,一种是get请求,这种暂时没处理,后面再考虑,目前只处理的post请求,基于json格式提交的方式,也就是说后台需要用@RequestBody接收数据才行, 需要解密的操作我们加上@Decrypt注解即可。

@Decrypt
@PostMapping("/save")
public Response savePageLog(@RequestBody PageLogParam logParam, HttpServletRequest request) {
	pageLogService.save(logParam);
	return Response.ok();
}

加了@Decrypt注解后,前端提交的数据需要按照AES加密算法,进行加密,然后提交到后端,后端这边会自动解密,然后再映射到参数对象中。

上面讲解的都是后端的代码,前端使用的话我们以js来讲解,当然你也能用别的语言来做,如果是原生的安卓app也是用java代码来处理。

前端需要做的就2件事情:

  1. 统一处理数据的响应,在渲染到页面之前进行解密操作
  2. 当有POST请求的数据发出时,统一加密

js加密文件请参考我GitHub中encrypt中的aes.js,crypto-js.js,pad-zeropadding.js

我们以axios来作为请求数据的框架,用axios的拦截器来统一处理加密解密操作

首先还是要封装一个js加解密的类,需要注意的是加密的key需要和后台的对上,不然无法相互解密,代码如下:

var key  = CryptoJS.enc.Latin1.parse('abcdef0123456789');
var iv   = CryptoJS.enc.Latin1.parse('abcdef0123456789');

// 加密
function EncryptData(data) {
	var srcs = CryptoJS.enc.Utf8.parse(data);
	var encrypted = CryptoJS.AES.encrypt(srcs, key, {
		mode : CryptoJS.mode.ECB,
		padding : CryptoJS.pad.Pkcs7
	});
	return encrypted.toString();
}

// 解密
function DecryptData(data) {
	var stime = new Date().getTime();
	var decrypt = CryptoJS.AES.decrypt(data, key, {
		mode : CryptoJS.mode.ECB,
		padding : CryptoJS.pad.Pkcs7
	});
	var result = JSON.parse(CryptoJS.enc.Utf8.stringify(decrypt).toString());
	var etime = new Date().getTime();
	console.log("DecryptData Time:" + (etime - stime));
	return result;
}

axios拦截器中统一处理代码:

// 添加请求拦截器
axios.interceptors.request.use(function (config) {
	// 对所有POST请加密,必须是json数据提交,不支持表单
	if (config.method == "post") {
		config.data = EncryptData(JSON.stringify(config.data));
	}
    return config;
  }, function (error) {
    return Promise.reject(error);
});

// 添加响应拦截器
axios.interceptors.response.use(function (response) {
	// 后端返回字符串表示需要解密操作
	if(typeof(response.data) == "string"){
		response.data = DecryptData(response.data);
	}
    return response;
  }, function (error) {
	return Promise.reject(error);
});

到此为止,我们就为整个前后端交互的通信做了一个加密的操作,只要加密的key不泄露,别人得到你的数据也没用,问题是如何保证key不泄露呢?

服务端的安全性较高,可以存储在数据库中或者配置文件中,毕竟在我们自己的服务器上,最危险的其实就时前端了,app还好,可以打包,但是要防止反编译等等问题。

如果是webapp则可以依赖于js加密来实现,下面我给大家介绍一种动态获取加密key的方式,只不过实现起来比较复杂,我们不上代码,只讲思路:

加密算法有对称加密和非对称加密,AES是对称加密,RSA是非对称加密。之所以用AES加密数据是因为效率高,RSA运行速度慢,可以用于签名操作。

我们可以用这2种算法互补,来保证安全性,用RSA来加密传输AES的秘钥,用AES来加密数据,两者相互结合,优势互补。

其实大家理解了HTTPS的原理的话对于下面的内容应该是一看就懂的,HTTPS比HTTP慢的原因都是因为需要让客户端与服务器端安全地协商出一个对称加密算法。剩下的就是通信时双方使用这个对称加密算法进行加密解密。

  1. 客户端启动,发送请求到服务端,服务端用RSA算法生成一对公钥和私钥,我们简称为pubkey1,prikey1,将公钥pubkey1返回给客户端。
  2. 客户端拿到服务端返回的公钥pubkey1后,自己用RSA算法生成一对公钥和私钥,我们简称为pubkey2,prikey2,并将公钥pubkey2通过公钥pubkey1加密,加密之后传输给服务端。
  3. 此时服务端收到客户端传输的密文,用私钥prikey1进行解密,因为数据是用公钥pubkey1加密的,通过解密就可以得到客户端生成的公钥pubkey2
  4. 然后自己在生成对称加密,也就是我们的AES,其实也就是相对于我们配置中的那个16的长度的加密key,生成了这个key之后我们就用公钥pubkey2进行加密,返回给客户端,因为只有客户端有pubkey2对应的私钥prikey2,只有客户端才能解密,客户端得到数据之后,用prikey2进行解密操作,得到AES的加密key,最后就用加密key进行数据传输的加密,至此整个流程结束。

spring-boot-starter-encrypt原理

最后我们来简单的介绍下spring-boot-starter-encrypt的原理吧,也让大家能够理解为什么Spring Boot这么方便,只需要简单的配置一下就可以实现很多功能。

启动类上的@EnableEncrypt注解是用来开启功能的,通过@Import导入自动配置类

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({EncryptAutoConfiguration.class})
public @interface EnableEncrypt {

}

EncryptAutoConfiguration中配置请求和响应的处理类,用的是Spring中的RequestBodyAdvice和ResponseBodyAdvice,在Spring中对请求进行统计处理比较方便。如果还要更底层去封装那就要从servlet那块去处理了。

@Configuration
@Component
@EnableAutoConfiguration
@EnableConfigurationProperties(EncryptProperties.class)
public class EncryptAutoConfiguration {

	/**
	 * 配置请求解密
	 * @return
	 */
	@Bean
	public EncryptResponseBodyAdvice encryptResponseBodyAdvice() {
		return new EncryptResponseBodyAdvice();
	}
	
	/**
	 * 配置请求加密
	 * @return
	 */
	@Bean
	public EncryptRequestBodyAdvice encryptRequestBodyAdvice() {
		return new EncryptRequestBodyAdvice();
	}
	
}

通过RequestBodyAdvice和ResponseBodyAdvice就可以对请求响应做处理了,大概的原理就是这么多了。


作者:猿天地
链接:https://juejin.im/post/5b149754f265da6e155d4748
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

你可能感兴趣的:(springboot,encrypt,加解密,JAVA)