SSL证书申请与Spring Boot集成

June 24, 2019
Backend DevSpring Boot运维Linux

MikeTech 由 Spring Boot 驱动,部署在我自己的服务器上。由于以前的 MikeTech 使用的是服务器空间搭建的,所以提供商帮我解决了SSL的问题,我没有管太多。这次,服务器和服务都是自己的,那么一切都需要靠自己了。

 

什么是 SSL 证书,为什么需要 SSL

SSL 全称为 Secure Sockets Layer,https协议中的s就代表ssl。你不需要知道ssl的具体原理,简而言之ssl可以让你的网站传输变得更加安全。

我以前的文章 论如何黑掉舍友的网络账号 有讨论过如何进行中间人攻击,因为原来的http协议使用的是明文传输,所以中间人黑客很容易去的你的传输信息,比如密码啊等等。但是有了https之后因为黑客没有你的传输公钥,那么即使他截获了传输的数据也是不能解密出来的。就和二战时期的电报一样,即使敌军截获了电报,没有那本密码本的话,截获的信息对他们来说相当于是天书。

从2019年初Google Chrome会把没有采用 https 协议的网站标记为危险,如果你的网站还在使用http协议的话访问的时候会报出来下图的警告,很不方便。

这样的措施使得网络诈骗变得困难了,即使有人仿造了某个网页,但是没有他们的ssl证书的话,还是比较容易被识破的。

为什么有了SSL证书就代表了安全?网络加密传输的大概过程就是:你生成了一个公钥和私钥,私钥你自己保留,公钥公开,用户对你的网站进行请求时会用这个公钥进行加密,公钥加密过的信息只能通过你个人的私钥解密,加密后的文件传输到你的服务器然后使用私钥解密。这样就能确保他人无法解密信息,因为第三方没有私钥。可是公钥的共享就出了一个问题,如果有中间人攻击的话,中间人攻击的时候可以伪造一个公钥,这样用户即使加密了信息也能被中间人解密,因为用户没有办法去验证这个公钥是不是真的。把公钥交给一个可信任的人保管则解决了公钥分发的问题,这就是SSL证书的思路,SSL证书都是由证书认证机构(CA)颁发的,证书认证机构则代表可信赖,签发的证书里面包含了你的传输公钥。他人传输数据到服务器时会从CA得到公钥并加密然后传输。这样的话中间人就无法伪造公钥了,除非CA那边沦陷。SSL证书就相当于现实世界开具重要文件时候的公章一样。

 

从哪里得到 SSL 证书呢

首先需要选择一个证书认证机构,市面上也有很多免费的SSL证书。我选择了收费不多的 Comodo Positive SSL ( https://comodosslstore.com/uk/positivessl.aspx ),选择 Comodo 是因为以前用Windows 的时候用过他们家的防火墙, 比较有好感。Positive SSL 也不是很贵,一年只要6.99英镑,换算成人民币的话70元不到。购买之后回收到一个邮件,就可以开始申请了。

 

Positive SSL 申请流程

进入邮件里给的链接就可以开始申请了

第一步是选择自动认证方式,因为你必须得证明域名是你个人的,要不然我就可以去申请一个 Google.com 的证书冒充 Google 了,我觉得CNAME认证最方便,如果你的域名可以进行CNAME解析(怎么可能不能。。。)的话就可以选这个认证方式。

第二步是生成CSR,也就是说要先生成一对秘钥交给他们,用来签名。

这个步骤也有比较详细的教程来应对不同的部署环境,我使用的 Mac 和 Linux 服务器所以指令通用,我是看着他们的教程来生成秘钥的, 不过这个教程是通用的,就是生成自签名秘钥的过程,没有什么特殊的。运行下面的指令即可,其中 your_domain_name 是输出的文件名,随便起个名字就行,运行之中会让你输入一些个人信息,有一个地方需要注意的是,当需要输 First 和 Last Name的时候,需要输入你的域名而不是你的真名,我的是miketech.it。完成后会生成一个jks文件,则是自签名证书。

  1. keytool -genkey -alias server -keyalg RSA -keysize 2048 -keystore your_domain_name.jks

然后执行这个语句来获得CSR,执行后会生成一个csr.txt 文件,内容即为CSR。粘贴到网站的输入框里。

  1. keytool -certreq -alias server -file csr.txt -keystore your_domain_name.jks

第三步选择服务器我选择的是 Tomcat 因为 Springboot是基于 Tomcat的,不过这个选项应该不会影响什么,只是生成的证书格式不同罢了。

之后就没有什么特别的需要说明的了,一路下去,最后一步就是要验证你的域名所有权了,网页会提示这样的一个说明,按照这个说明,在域名的控制面板设置一个别名解析,别名是下面Alias的内容,解析到第四步给的链接上。

如果成功的话就会收到一个邮件,里面包含了证书。

 

证书合并

附件里有一个 My_CA_Bundle.ca-bundle 文件,这个文件是 AddTrustExternalCARoot.crt,SectigoRSADomainValidationSecureServerCA.crt 和 USERTrustRSAAddTrustCA.crt的合并。首先我们需要把ca-bundle加入到 keystore 里面, keysotre就是一开始生成CSR时候用到的自签名证书jks文件。

  1. root@ubuntu:/home/miketech# keytool -import -trustcacerts -alias root -file My_CA_Bundle.ca-bundle -keystore miketech.jks
  2. Enter keystore password:
  3. Certificate was added to keystore

之后再把附件中的 miketech_it.crt 文件加入到 keystore里面即可。这时原本的jks文件就成了CA签名好的证书。

  1. root@ubuntu:/home/miketech# keytool -import -trustcacerts -alias server -file miketech_it.crt -keystore miketech.jks
  2. Enter keystore password:
  3. Certificate reply was installed in keystore

我的以上做法和Comodo给的做法不同,他们给的方案是使用附件中的PKCS7证书来合并,但是我感觉他们给的PKCS7是坏的,我试了很久都报错,问客服,他们的方法和我做的一样但还是不行,客服也不会,还给我推荐他们的付费安装服务。。。

 

Spring Boot证书集成

把合并后的jks证书文件复制到项目 Resource 目录下然后在 application.properties 中添加下面的配置代码。其中 server.ssl.key-alias 是生成CSR时候的alias参数,key-store-password 和 key-password 是生成CSR时候设定的。
之后启动服务器就可以啦,这个证书是跟域名的哦,也就是说必须访问 miketech.it 的时候这个证书才会生效显示绿色,平时调试时候用的localhost是不会显示绿色锁头的。

  1. server.port = 443
  2. server.ssl.key-alias=server
  3. server.ssl.key-store-type=JKS
  4. server.ssl.key-store = classpath:miketech.jks
  5. server.ssl.key-store-password = 88888
  6. server.ssl.key-password = 88888

 

Spring Boot 80 端口重定向

最后一步是需要将 http 请求重定向为 https,在项目中加入以下代码即可。以下代码的作用是将 80端口的请求重定向到443,443是https的默认端口,在application.properties可以设置成别的。

  1. @Bean
  2. public ServletWebServerFactory servletContainer() {
  3. TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {
  4. @Override
  5. protected void postProcessContext(Context context) {
  6. SecurityConstraint constraint = new SecurityConstraint();
  7. constraint.setUserConstraint("CONFIDENTIAL");
  8. SecurityCollection collection = new SecurityCollection();
  9. collection.addPattern("/*");
  10. constraint.addCollection(collection);
  11. context.addConstraint(constraint);
  12. }
  13. };
  14. tomcat.addAdditionalTomcatConnectors(createHTTPConnector());
  15. return tomcat;
  16. }
  17. private Connector createHTTPConnector() {
  18. Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
  19. connector.setScheme("http");
  20. connector.setSecure(false);
  21. //http 端口
  22. connector.setPort(80);
  23. //https端口
  24. connector.setRedirectPort(443);
  25. return connector;
  26. }

Comments

July 21, 2018 at 10:52 am

There are no comments

keyboard_arrow_up