国密证书应用二:基于Tengine+TongSuo实现国密HTTPS

1,648 阅读5分钟

背景信息

Tengine是由阿里云团队开发并开源的一款高性能、可扩展的Web服务器和反向代理服务器,它在Nginx的基础上,针对大访问量网站的需求,添加了很多高级功能和特性。Tengine已对铜锁/Tongsuo(原名BabaSSL)进行适配,并增加了对NTLS(National TLS,也称国密TLS)相关能力的支持。对于有使用国密算法进行安全通信协议需求的用户,可以直接使用Tengine+Tongsuo的组合。
本文使用Tengine+Tongsuo组合实现SM2/RSA双证书模式,在Tengine部署SM2/RSA双SSL证书, 当用户使用360浏览器、奇安信浏览器、红莲花浏览器等国密浏览器访问时,自动采用国密算法HTTPS加密; 当用户使用Chrome、Firefox、IE、Safari等不支持国密算法的通用浏览器访问时, 自动采用RSA算法HTTPS加密,自适应兼容所有浏览器及移动终端。

image.png

1. 环境准备

1.1 下载Tongsuo

cd /usr/local/src
# 下载Tongsuo
wget -c https://github.com/Tongsuo-Project/Tongsuo/archive/refs/tags/8.4.0.tar.gz

# 解压Tongsuo源码
tar zxf 8.4.0.tar.gz

1.2 下载Tengine

# 下载Tengine
wget -c https://github.com/alibaba/tengine/archive/refs/tags/3.1.0.tar.gz

# 解压Tengine源码
tar zxf 3.1.0.tar.gz

1.3 安装依赖

# CentOS 系统 [麒麟/Redhat]
yum  install -y wget gcc  gcc-c++ make pcre  pcre-devel gzip zlib-devel

# Ubuntu 系统
apt install g++ libpcre3 libpcre3-dev  openssl libssl-dev zlib1g zlib1g-dev -y

 2. 编译安装Tengine

cd /usr/local/src/tengine-3.1.0
# 配置
./configure --prefix=/usr/local/tengine \
            --with-openssl=/usr/local/src/Tongsuo-8.4.0 \
            --with-openssl-opt="enable-ntls" --with-http_ssl_module \
            --with-http_stub_status_module --with-http_v2_module \
            --with-http_realip_module --with-http_sub_module \
            --with-http_flv_module --with-http_mp4_module \
            --with-http_random_index_module --with-http_gzip_static_module  \
            --add-module=modules/ngx_tongsuo_ntls \
            --add-module=modules/ngx_http_upstream_session_sticky_module  \
            --add-module=modules/ngx_http_upstream_check_module 
            
# 编译
make -j

# 安装
make install

--prefix=/usr/local/tengine:指定Tengine安装目录为/usr/local/tengine,您可以指定其他目录。
--add-module=modules/ngx_tongsuo_ntls:加载Tongsuo NTLS。Tengine 2.4.1之前的版本需将ngx_tongsuo_ntls替换为ngx_openssl_ntls。
--with-openssl=/usr/local/src/Tongsuo-8.4.0 :OpenSSL替换为Tongsuo以实现SM2。/usr/local/src/Tongsuo-8.4.0 需替换为实际Tongsuo源码解压路径。
--add-module=modules/ngx_http_upstream_session_sticky_module  :负载均衡模块,通过cookie实现客户端与后端服务器的会话保持。
--add-module=modules/ngx_http_upstream_check_module :提供主动式后端服务器健康检查的功能。

3. Tengine 配置

cd /usr/local/tengine/conf

# 备份模式配置文件
mv nginx.conf nging.conf.bak0

# 编辑生成新的配置文件[根据应用部署模式(单机/多节点)选择配置]
vi /usr/local/tengine/conf/nginx.conf

3.1 应用单机配置[nginx.conf]

worker_processes auto; 
worker_rlimit_nofile 20960; 
error_log  logs/error.log  crit;

events {
  worker_connections  4096;
  multi_accept on; 
  accept_mutex on;
  accept_mutex_delay 500ms; 
}

http {
  server_tokens off;
  sendfile on;
  tcp_nopush on; 
  tcp_nodelay on;
  include       mime.types;
  default_type  application/octet-stream;
  keepalive_timeout  300;
  client_max_body_size 10240M;
  gzip on;
  gzip_min_length 1k;
  gzip_buffers 4 16k;
  gzip_comp_level 3;
  gzip_types text/xml text/plain text/css text/javascript application/x-javascript application/javascript application/xml;
  gzip_disable "MSIE [1-6].";
    
  server {
       listen 443 ssl;
        server_name oa.test.cc; 
        enable_ntls on;
    
        # 配置国密算法签名证书
        ssl_sign_certificate cert/sm2.test.cc.sig.crt.pem; 
        ssl_sign_certificate_key cert/sm2.test.cc.sig.key.pem;
    
        # 配置国密算法加密证书
        ssl_enc_certificate cert/sm2.test.cc.enc.crt.pem;
        ssl_enc_certificate_key cert/sm2.test.cc.enc.key.pem;
    
        # 配置RSA算法证书
        ssl_certificate cert/rsa.test.cc.crt.pem;
        ssl_certificate_key cert/rsa.test.cc.key.pem;
    
        ssl_session_cache shared:SSL:1m;
        ssl_session_timeout 5m;
    
        # 配置加密套件# ssl_ciphers HIGH: !aNULL: !MD5;
        ssl_ciphers ECC-SM2-SM4-CBC-SM3:ECC-SM2-SM4-GCM-SM3:ECDHE-SM2-SM4-CBC-SM3:ECDHE-SM2-SM4-GCM-SM3:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA:ECDHE-RSA-AES128-SHA256:!aNULL:!eNULL:!RC4:!EXPORT:!DES:!3DES:!MD5:!DSS:!PKS;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
        ssl_prefer_server_ciphers on;

    # 如正式配置,可使用此段location;
    location / {
      # 应用服务地址
      proxy_pass http://192.168.159.151:8088;
      proxy_set_header Host $http_host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header REMOTE-HOST $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      # http访问配置为非80端口,需要删除
      proxy_set_header X-Forwarded-Proto $scheme;
      proxy_redirect     off;
      proxy_connect_timeout 300;
      proxy_read_timeout 300;
      proxy_send_timeout 300;
    }
  
    # 如测试证书,可启用此段location(取消行前注释即可);  
#    location / {
#      root html;
#      index index.html index.htm;
#    }

    error_page  404              /404.html;
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
      root   html;
    }
    # 需模块ngx_http_upstream_check_module支持,浏览器访问 http://IP:PORT/status [可选]
    location /status {
            check_status;
            access_log   off;
            #allow SOME.IP.ADD.RESS;
            #deny all;
        }
  }
  
# 配置80端口默认转发至443端口
  server {
    listen 80;
    return 301 https://$host$request_uri;
  }

}

3.2 应用负载配置[nginx.conf]

worker_processes auto; 
worker_rlimit_nofile 20960; 
error_log  logs/error.log  crit;

events {
  worker_connections  4096;
  multi_accept on; 
  accept_mutex on;
  accept_mutex_delay 500ms; 
}

http {
  server_tokens off;
  sendfile on;
  tcp_nopush on; 
  tcp_nodelay on;
  include       mime.types;
  default_type  application/octet-stream;
  keepalive_timeout  300;
  client_max_body_size 10240M;
  gzip on;
  gzip_min_length 1k;
  gzip_buffers 4 16k;
  gzip_comp_level 3;
  gzip_types text/xml text/plain text/css text/javascript application/x-javascript application/javascript application/xml;
  gzip_disable "MSIE [1-6].";
  
  upstream apps_cluster{
    session_sticky; 
    # 负载多个应用服务地址
    server 192.168.159.151:8088;
    server 192.168.159.152:8088;
    server 192.168.159.153:8088;
    # 需模块ngx_http_upstream_check_module支持
    check interval=3000 rise=2 fall=5 timeout=1000 type=http;
    check_keepalive_requests 100;
  }
  
  server {
       listen 443 ssl;
        server_name app.test.cc; 
        enable_ntls on;
    
        # 配置国密算法签名证书
        ssl_sign_certificate cert/sm2.test.cc.sig.crt.pem; 
        ssl_sign_certificate_key cert/sm2.test.cc.sig.key.pem;
    
        # 配置国密算法加密证书
        ssl_enc_certificate cert/sm2.test.cc.enc.crt.pem;
        ssl_enc_certificate_key cert/sm2.test.cc.enc.key.pem;
    
        # 配置RSA算法证书
        ssl_certificate cert/rsa.test.cc.crt.pem;
        ssl_certificate_key cert/rsa.test.cc.key.pem;
    
        ssl_session_cache shared:SSL:1m;
        ssl_session_timeout 5m;
    
        # 配置加密套件# ssl_ciphers HIGH: !aNULL: !MD5;
        ssl_ciphers ECC-SM2-SM4-CBC-SM3:ECC-SM2-SM4-GCM-SM3:ECDHE-SM2-SM4-CBC-SM3:ECDHE-SM2-SM4-GCM-SM3:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA:ECDHE-RSA-AES128-SHA256:!aNULL:!eNULL:!RC4:!EXPORT:!DES:!3DES:!MD5:!DSS:!PKS;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
        ssl_prefer_server_ciphers on;

    location / {
      proxy_pass http://apps_cluster;
      proxy_set_header Host $http_host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header REMOTE-HOST $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      # http访问配置为非80端口,需要删除
      proxy_set_header X-Forwarded-Proto $scheme;
      proxy_redirect     off;
      proxy_connect_timeout 300;
      proxy_read_timeout 300;
      proxy_send_timeout 300;
    }
    error_page  404              /404.html;
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
      root   html;
    }
    # 需模块ngx_http_upstream_check_module支持,浏览器访问 http://IP:PORT/status [可选]
    location /status {
            check_status;
            access_log   off;
            #allow SOME.IP.ADD.RESS;
            #deny all;
        }
  }
  
# 配置80端口默认转发至443端口
  server {
    listen 80;
    return 301 https://$host$request_uri;
  }

}

3.3 服务控制

vi /usr/lib/systemd/system/nginx.service

 nginx.service 文件内容

[Unit]
Description=Tengine Web Server
Documentation=https://tengine.taobao.org/documentation_cn.html
After=network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target
[Service]
# User=nginx
# Group=nginx
Type=forking
PIDFile=/usr/local/tengine/logs/nginx.pid
ExecStart=/usr/local/tengine/sbin/nginx -p /usr/local/tengine -c /usr/local/tengine/conf/nginx.conf
ExecReload=/usr/local/tengine/sbin/nginx -p /usr/local/tengine -s reload 
ExecStop=/usr/local/tengine/sbin/nginx -p /usr/local/tengine -s stop 
LimitNOFILE=infinity
PrivateTmp=true
Restart=on-failure
RestartPreventExitStatus=1
RestartSec=3
[Install]
WantedBy=multi-user.target
# 设置开机启动并立即启动服务
systemctl enable --now nginx.service

# 服务重启
systemctl restart nginx.service

# 服务状态
systemctl status nginx.service

3.4 防护墙策略

# firewalld
# 默认端口时,可添加http或https服务
firewall-cmd --permanent --zone=public --add-service=http --add-service=https

# 非默认端口时使用指定端口
firewall-cmd --permanent --zone=public --add-port=8080/tcp --add-port=8443/tcp

# 立即生效
firewall-cmd --reload复制

4. 附

国密浏览器下载:
密信浏览器www.mesigndoc.com/zh-cn/brows…
360安全浏览器browser.360.net/gmzb.html?s…
奇安信可信浏览器www.qianxin.com/ctp/gmbrows…