
HTTPS是HTTP开启TLS传输协议,客户端要拿到服务端的公钥,用公钥加密数据后再进行传输,防止数据泄露后背篡改。它要解决两个问题:
怎么保证公钥可信
怎么加密数据
公钥可信问题
客户端从服务端获取公钥的时候,存在请求被拦截,攻击者把公钥替换成自己的公钥的风险。这样客户端再用公钥加密,攻击者就可以用自己的私钥解密,篡改内容后再用服务端公钥加密传给服务器。这时,客户端拿到公钥后就要验证公钥的可信度。
保证公钥可信
HTTPS通过数据认证中心(CA)签发的证书证明自己的公钥可信。证书里主要信息包括:认证机构公钥、机构的数字签名、有效期、持证人标识符、签名算法、序列号、版本等。客户端拿着认证机构的公钥和其他信息来验证数据前面的有效性,验证通过就代表客户端拿到的公钥是属于持证人的。
怎么保证认证机构的公钥是可信的?使用同样的验证方式,拿到认证机构公钥的数字证书去验证机构的公钥。最终会验证到根证书,根证书是预置在操作系统里,默认是可信的。
加密数据
HTTPS通过混合加密技术,既对称加密和非对称加密。
非对称加密用作“秘钥协商”,用来传输对称加密的秘钥
对称加密来加密明文
对称加密性能高,无法保证密钥传输安全;非对称加密传输安全,但无法加密性能差。
SpringBoot配置HTTPS
获取证书
用java自带的keytool自生成证书
keytool -genkey -alias tomcat -dname "CN=localhost,OU=kfit,O=kfit,L=HaiDian,ST=BeiJing,C=CN" -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore keystore.p12 -validity 365
将证书放到resources/certs/文件夹下,在application.yml添加证书配置信息,就可以以HTTPS访问服务
server:
port: 443
ssl:
key-alias: "tomcat"
key-store: "classpath:certs/keystore.p12"
key-store-password: "123456"
key-store-type: "PKCS12"
SpringBoot将HTTP重定向到HTTPS
方式一,基于tomcat的重定向
在tomcat上添加了Connector监听http的端口,然后在”/*” 路径下添加SecurityConstraint=CONFIDENTIAL,要求所有请求都走SSL协议。
@Bean
public TomcatServletWebServerFactory tomcatServletWebServerFactory() {
TomcatServletWebServerFactory tomcatServletWebServerFactory = new TomcatServletWebServerFactory() {
@Override
protected void postProcessContext(Context context) {
SecurityConstraint securityConstraint = new SecurityConstraint();
// CONFIDENTIAL要求使用SSL协议
securityConstraint.setUserConstraint("CONFIDENTIAL");
SecurityCollection securityCollection = new SecurityCollection();
securityCollection.addPattern("/*");
securityConstraint.addCollection(securityCollection);
context.addConstraint(securityConstraint);
}
};
tomcatServletWebServerFactory.addAdditionalTomcatConnectors(connector());
return tomcatServletWebServerFactory;
}
private Connector connector() {
Connector connector = new Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL);
connector.setPort(8080);
// 默认值就是443,可以不填
connector.setRedirectPort(443);
return connector;
}
方式二,基于SpringSecurity的请求路由
不同tomcat的SecurityConstraint实现重定向,但是Connector还是要添加。
在httpSecurity中通过portMapper()配置端口映射,再配置requiresChannel()要求所有请求都走安全的协议。
@Bean
public TomcatServletWebServerFactory tomcatServletWebServerFactory() {
TomcatServletWebServerFactory tomcatServletWebServerFactory = new TomcatServletWebServerFactory();
tomcatServletWebServerFactory.addAdditionalTomcatConnectors(connector());
return tomcatServletWebServerFactory;
}
private Connector connector() {
Connector connector = new Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL);
connector.setPort(8080);
// 默认值就是443,可以不填
connector.setRedirectPort(443);
return connector;
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.portMapper(it -> it.http(8080).mapsTo(443))
.requiresChannel(
channel -> channel.anyRequest().requiresSecure()
)
.formLogin();
return httpSecurity.build();
}