首页 > 代码库 > Spring Boot工程支持HTTP和HTTPS,HTTP重定向HTTPS

Spring Boot工程支持HTTP和HTTPS,HTTP重定向HTTPS

本文试图以通俗易通的方式介绍Https的工作原理,不纠结具体的术语,不考证严格的流程。我相信弄懂了原理之后,到了具体操作和实现的时候,方向就不会错,然后条条大路通罗马。阅读文本需要提前大致了解对称加密、非对称加密、信息认证等密码学知识。如果你不太了解,可以阅读Erlang发明人Joe Armstrong最近写的Cryptography Tutorial。大牛出品,通俗易懂,强力推荐。

Https涉及到的主体

  1. 客户端。通常是浏览器(Chrome、IE、FireFox等),也可以自己编写的各种语言的客户端程序。
  2. 服务端。一般指支持Https的网站,比如github、支付宝。
  3. CA(Certificate Authorities)机构。Https证书签发和管理机构,比如Symantec、Comodo、GoDaddy、GlobalSign。

下图里我画出了这几个角色:技术分享

发明Https的动机

  1. 认证正在访问的网站。什么叫认证网站?比如你正在访问支付宝,怎样确定你正在访问的是阿里巴巴提供的支付宝而不是假冒伪劣的钓鱼网站呢?
  2. 保证所传输数据的私密性和完整性。众所周知,Http是明文传输的,所以处在同一网络中的其它用户可以通过网络抓包来窃取和篡改数据包的内容,甚至运营商或者wifi提供者,有可能会篡改http报文,添加广告等信息以达到盈利的目的。

Https的工作流程

这一节通过介绍Https协议的工作流程,来说明Https是如何达成自己的两个目的的。下图我画出了Https的工作流程,注意,这只是原理示意图,并不是详细的协议解析。技术分享

可以看到工作流程,基本分为三个阶段:

  1. 认证服务器。浏览器内置一个受信任的CA机构列表,并保存了这些CA机构的证书。第一阶段服务器会提供经CA机构认证颁发的服务器证书,如果认证该服务器证书的CA机构,存在于浏览器的受信任CA机构列表中,并且服务器证书中的信息与当前正在访问的网站(域名等)一致,那么浏览器就认为服务端是可信的,并从服务器证书中取得服务器公钥,用于后续流程。否则,浏览器将提示用户,根据用户的选择,决定是否继续。当然,我们可以管理这个受信任CA机构列表,添加我们想要信任的CA机构,或者移除我们不信任的CA机构。

  2. 协商会话密钥。客户端在认证完服务器,获得服务器的公钥之后,利用该公钥与服务器进行加密通信,协商出两个会话密钥,分别是用于加密客户端往服务端发送数据的客户端会话密钥,用于加密服务端往客户端发送数据的服务端会话密钥。在已有服务器公钥,可以加密通讯的前提下,还要协商两个对称密钥的原因,是因为非对称加密相对复杂度更高,在数据传输过程中,使用对称加密,可以节省计算资源。另外,会话密钥是随机生成,每次协商都会有不一样的结果,所以安全性也比较高。

  3. 加密通讯。此时客户端服务器双方都有了本次通讯的会话密钥,之后传输的所有Http数据,都通过会话密钥加密。这样网路上的其它用户,将很难窃取和篡改客户端和服务端之间传输的数据,从而保证了数据的私密性和完整性。

使用Https的流程

如果你是一个服务器开发者,想使用Https来保护自己的服务和用户数据安全,你可以按照以下流程来操作。技术分享

总结

    1. 说是讨论Https,事实上Https就是Http跑在SSl或者TLS上,所以本文讨论的原理和流程其实是SSL和TLS的流程,对于其它使用SSL或者TLS的应用层协议,本文内容一样有效。
    2. 本文只讨论了客户端验证服务端,服务端也可以给客户端颁发证书并验证客户端,做双向验证,但应用没有那么广泛,原理类似。
    3. 由于采用了加密通讯,Https无疑要比Http更耗费服务器资源,这也是很多公司明明支持Https却默认提供Http的原因。

 

1- 使用HTTPS连接器,需要生成一份Certificate keystore,用于加密和机密浏览器的SSL沟通

# windows:

keytool -genkeypair -alias "tomcat" -keyalg "RSA" -keystore "d:\\1.keystore"

# linux:

keytool -genkey -alias tomcat -keyalg RSA

# 执行完上述命令后在home目录下多了一个新的.keystore文件

2- 新增属性文件 tomcat.https.properties

类比

<!-- Define an SSL HTTP/1.1 Connector on port 443 --><Connector className="org.apache.catalina.connector.http.HttpConnector" port="443" minProcessors="5" maxProcessors="75"keystoreFile="path.to.keystore"enableLookups="true"acceptCount="10" debug="0" scheme="https" secure="true"><Factory className="org.apache.catalina.net.SSLServerSocketFactory"clientAuth="false" protocol="TLS" keystorePass="keystore.password"/></Connector>
custom.tomcat.https.port=443custom.tomcat.https.secure=truecustom.tomcat.https.scheme=httpscustom.tomcat.https.ssl=truecustom.tomcat.https.keystore=d:\\1.keystorecustom.tomcat.https.keystore-password=xinli2016
import java.io.File;import org.apache.catalina.Context;import org.apache.catalina.connector.Connector;import org.apache.tomcat.util.descriptor.web.SecurityCollection;import org.apache.tomcat.util.descriptor.web.SecurityConstraint;import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.boot.context.properties.EnableConfigurationProperties;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.PropertySource;import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;@Configuration@PropertySource("classpath:/tomcat.https.properties")@EnableConfigurationProperties(WebConfiguration.TomcatSslConnectorProperties.class)public class WebConfiguration extends WebMvcConfigurerAdapter {    @Bean    public EmbeddedServletContainerFactory servletContainer(TomcatSslConnectorProperties properties) {        TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory() {            @Override            protected void postProcessContext(Context context) {                // SecurityConstraint必须存在,可以通过其为不同的URL设置不同的重定向策略。                SecurityConstraint securityConstraint = new SecurityConstraint();                securityConstraint.setUserConstraint("CONFIDENTIAL");                SecurityCollection collection = new SecurityCollection();                collection.addPattern("/*");                securityConstraint.addCollection(collection);                context.addConstraint(securityConstraint);            }        };        tomcat.addAdditionalTomcatConnectors(createSslConnector(properties));        return tomcat;    }    private Connector createSslConnector(TomcatSslConnectorProperties properties) {        Connector connector = new Connector();        properties.configureConnector(connector);        return connector;    }    @ConfigurationProperties(prefix = "custom.tomcat.https")    public static class TomcatSslConnectorProperties {        private Integer port;        private Boolean ssl = true;        private Boolean secure = true;        private String scheme = "https";        private File keystore;        private String keystorePassword;        // 省略 get set                public void configureConnector(Connector connector) {            if (port != null) {                connector.setPort(port);            }            if (secure != null) {                connector.setSecure(secure);            }            if (scheme != null) {                connector.setScheme(scheme);            }            if (ssl != null) {                connector.setProperty("SSLEnabled", ssl.toString());            }            if (keystore != null && keystore.exists()) {                connector.setProperty("keystoreFile", keystore.getAbsolutePath());                connector.setProperty("keystorePass", keystorePassword);            }        }    }}

https://my.oschina.net/freegarden/blog/609975

import org.apache.catalina.Context;import org.apache.catalina.connector.Connector;import org.apache.tomcat.util.descriptor.web.SecurityCollection;import org.apache.tomcat.util.descriptor.web.SecurityConstraint;import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.util.SocketUtils;/** * Created by tangcheng on 5/28/2017. */@Configurationpublic class SslConfig {    @Bean    public EmbeddedServletContainerFactory servletContainer() {        TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory() {            @Override            protected void postProcessContext(Context context) {                // SecurityConstraint必须存在,可以通过其为不同的URL设置不同的重定向策略。                SecurityConstraint constraint = new SecurityConstraint();                constraint.setUserConstraint("CONFIDENTIAL");                SecurityCollection collection = new SecurityCollection();                collection.addPattern("/*");                constraint.addCollection(collection);                context.addConstraint(constraint);            }        };        tomcat.addAdditionalTomcatConnectors(httpConnector());        return tomcat;    }    @Bean    public Connector httpConnector() {        Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");        connector.setScheme("http");        //Connector监听的http的端口号        connector.setPort(80);        connector.setSecure(false);        //监听到http的端口号后转向到的https的端口号        connector.setRedirectPort(8443);        return connector;    }    @Bean    public Integer port() {        return SocketUtils.findAvailableTcpPort();    }}

http://www.cnblogs.com/xxt19970908/p/6736370.html

 

浏览器的地址栏中显示不安全:因为这个证书是不收信任的,传统一般都企业都是需要购买此证书的

http://www.cnblogs.com/xxt19970908/p/6736370.html


https://github.com/spring-projects/spring-boot/blob/v1.5.3.RELEASE/spring-boot-samples/spring-boot-sample-tomcat-multi-connectors/src/main/java/sample/tomcat/multiconnector/SampleTomcatTwoConnectorsApplication.java

 

http://docs.spring.io/spring-boot/docs/1.5.3.RELEASE/reference/htmlsingle/#howto-configure-ssl

 

http://www.cnblogs.com/xinzhao/p/4952856.html

 

http://www.cnblogs.com/xinzhao/p/4950689.html

证书颁发机构

  • CA机构私钥
openssl genrsa -out ca.key 2048
  • CA证书
openssl req -x509 -new -key ca.key -out ca.crt

注意生成过程中需要输入一些CA机构的信息

服务端

  • 生成服务端私钥
openssl genrsa -out server.key 2048
  • 生成服务端证书请求文件
openssl req -new -key server.key -out server.csr

注意生成过程中需要你输入一些服务端信息

  • 使用CA证书生成服务端证书
openssl x509 -req -sha256 -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -days 3650 -out server.crt

关于sha256,默认使用的是sha1,在新版本的chrome中会被认为是不安全的,因为使用了过时的加密算法。

  • 打包服务端的资料为pkcs12格式(非必要,只是换一种格式存储上一步生成的证书)
openssl pkcs12 -export -in server.crt -inkey server.key -out server.pkcs12

生成过程中,需要创建访问密码,请记录下来。

  • 生成服务端的keystore(.jks文件, 非必要,Java程序通常使用该格式的证书)
keytool -importkeystore -srckeystore server.pkcs12 -destkeystore server.jks -srcstoretype pkcs12

生成过程中,需要创建访问密码,请记录下来。

  • 把ca证书放到keystore中(非必要)
keytool -importcert -keystore server.jks -file ca.crt

客户端

  • 导入根证书ca.crt到浏览器受信任的根证书颁发机构列表中

不管通过什么浏览器吧,总之你要找到下面这个页面,点击导入,将上面生成的CA机构的ca.crt导入到收信任的根证书颁发机构列表中。技术分享

注意,收信任的根证书颁发机构列表是操作系统级的,不管通过哪个浏览器进入配置,都是只需要配置一次,再使用其它浏览器时,无需重复配置。

http://www.cnblogs.com/xinzhao/p/4950689.html

 

Spring Boot工程支持HTTP和HTTPS,HTTP重定向HTTPS