Https、Wss加密实践

2,048 阅读4分钟

Websocket是基于Http的一种长连接方案,一些简单的IM产品会基于Websocket实现 但是如果聊天的内容比较敏感,比如在Websocket通道中聊天内容如果涉及到卡密、金钱等信息,那一定要对Websocket的传输进行保护。

https或者wss是最基本的防嗅探和传输加密方式,这里演示下如何配置wss的多种方式;

本文知识点:

  • p12格式文件与证书文件介绍
  • 如何生成p12文件和证书文件,以及如何互相转换
  • Nginx如何配置Https
  • Spring Boot如何配置Https?
  • WSS如何配置和使用?

过程

证书和p12基本概念

证书一般包含两个文件:

  • 证书文件,可以理解为公钥,用户访问的时候发给用户的
  • 私钥文件,在数据传输过程中对公钥加密的内容进行解密

p12为是保存私钥和证书的组合格式,同时包含了公钥和私钥内容。p12文件和证书可以互相转换。

转换方式如下:

# 私钥和证书生成p12文件
openssl pkcs12 -inkey PRIVATE_TEST.key -in PUBLIC_TEST.pem -export -out TEST.p12

# p12文件生成证书和私钥
openssl pkcs12 -nokeys -in TEST.p12 -out PUBLIC_TEST.pem
openssl pkcs12 -nocerts -nodes -in TEST.p12 -out PRIVATE_TEST.key

生成证书和p12文件

如果想要使用wss,首先要有个证书才行,证书有两种来源:

  • CA机构颁发,当然目前各种云产品都会帮我们做掉这个事情,阿里云上如果有购买域名,可以申请免费的证书
  • 自己签名证书,使用OpenSSL,keytools,或者Mac的钥匙串;

阿里云

在阿里云的菜单下面,安全部分,有个SSL证书

因为阿里云的证书要收费,我们考虑一些便宜又简单的方案

openssl

如果在Nginx中使用:

直接生成公钥和私钥:

openssl req -newkey rsa:2048 -sha256 -nodes -keyout PRIVATE_TEST.key -x509 -days 365 -out PUBLIC_TEST.pem -subj "/C=NG/ST=Lagos/L=Lagos/O=YOUR_ORG_NAME_HERE/CN=test.aihe.space"

将公钥和私钥转为P12格式

openssl pkcs12 -inkey PRIVATE_TEST.key -in PUBLIC_TEST.pem -export -out TEST.p12

keytool

# 生成一个jks格式的证书文件,
keytool -genkeypair -alias tomcat -keyalg RSA -keystore wss.jks

# 将JKS的文件,转换为p12格式的文件;
keytool -importkeystore -srckeystore wss.jks -destkeystore wss.p12 -deststoretype pkcs12

# 从P12的文件中提取证书和提取私钥
openssl pkcs12 -nokeys -in wss.p12 -out wss.pem
openssl pkcs12 -nocerts -nodes -in wss.p12 -out wss.private.key

如果要在Nginx中使用,方式一样:

ssl_certificate "cert/wss.pem";
ssl_certificate_key "cert/wss.private.key";

Mac钥匙串

导出为P12格式之后仍然按照老方式:

openssl pkcs12 -nokeys -in aihetest0916.p12 -out aihetest.pem
openssl pkcs12 -nocerts -nodes -in aihetest0916.p12 -out aihetest.key

Nginx配置Https-公私钥方式

在nginx下添加如下内容:在nginx.conf文件中,或者nginx配置目录下conf.d种新建一个文件都可以。

   server {
        listen       443 ssl ;
        listen       [::]:443 ssl ;
        server_name  ssl.aihe.space;
        root         /usr/share/nginx/html;

        ssl_certificate "cert/wss.pem";
        ssl_certificate_key "cert/wss.private.key";
        ssl_session_cache shared:SSL:1m;
        ssl_session_timeout  10m;
        #ssl_ciphers PROFILE=SYSTEM;
        ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
        ssl_prefer_server_ciphers on;
        ssl_verify_client off;

        
        location / {
           proxy_http_version 1.1;
           proxy_redirect off;

           proxy_set_header X-Real-IP $remote_addr;
           proxy_set_header Host            $host;
           proxy_set_header X-Forwarded-For $remote_addr;

           proxy_set_header Upgrade $http_upgrade;
           proxy_set_header Connection $connection_upgrade;
           
           # 这里配置了反向代理服务器的地址
           proxy_pass  http://127.0.0.1:8080;
        }
    }

在Safari浏览器上可以看到证书信息,网站访问也是生效的,谷歌浏览器如果遇到自签名证书不让访问,相对麻烦,所以还是用Safari浏览器。

SpringBoot配置Https-使用P12文件

1、将生成好的P12文件拷贝到resource目录下; 2、配置application.properties文件

#server.port=443
server.ssl.key-store=classpath:aihetest0916.p12
server.ssl.key-store-password=123456
server.ssl.key-password=123456
server.ssl.key-alias=aihetest0916

3、启动查看效果;

WSS配置和使用

Wss是基于Https的,如果已经配置好了Https:

  • 在Nginx中反向代理https到后端的http服务器即可,http服务器有Websocket。
  • 直连SpringBoot的WSS应用,让SpringBoot配置支持HTTPS

在Spring Boot中的Websocket代码:

@Configuration
@Slf4j
public class WebSocketConfig implements WebSocketConfigurer {

    @Autowired
    List<HandshakeInterceptor> handshakeInterceptorList;

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {

        registry.addHandler(new DemoTextWebSocketHandler(), "/websocket-spring").setAllowedOrigins("*")
                ;
    }


    private static class DemoTextWebSocketHandler extends TextWebSocketHandler {
        @Override
        public void afterConnectionEstablished(WebSocketSession session) throws Exception {
            log.info("建立连接 {}", session.getId());
            super.afterConnectionEstablished(session);
            TextMessage textMessage = new TextMessage("建立连接:" + session.getId());
            session.sendMessage(textMessage);
        }

        @Override
        protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
            super.handleTextMessage(session, message);
            log.info("处理收到的数据:{}", new String(message.asBytes()));
            session.sendMessage(new TextMessage("收到:" + new String(message.asBytes())));
        }
    }
}

测试本地访问:

测试Nginx反向代理

总结

  1. 现在证书配置有两种常见文件,p12文件和公钥私钥方式,p12只是把公钥和私钥组合了一下,p12和公钥私钥可以互相转换。
  2. Nginx配置Https使用公钥和私钥的方式
  3. SpringBoot应用中可以直接使用p12文件格式配置Https
  4. WSS加密其实只需要把Https功能配置好就行;在nginx反向代理中需要nginx支持下websocket的功能,在spring boot中默认就支持;
  5. 演示了几种生成证书的方式:阿里云、openssl、keytool、以及Mac电脑的钥匙串也可以创建对应的证书文件。

参考