信息安全系列_用https双向认证来保护网站的敏感数据

自打上个月买了云服务器,基于 wordpress 搭建了自己的博客站点后,我就为站点的安全性开始担忧

wordpress 的管理后台采用的是帐号密码登录,连个验证码都没有。太不安全了

虽然 php 是最好的开发语言,但是我不会啊,怎么搞下安全呢?

nginx 倒是可以做 ip 黑白名单,关键是我也没有固定的上网 ip 啊,不知道可不可以用 shadowsocks 代理来实现固定 ip。除了 nginx 的 ip 限制,还有什么办法呢?

https 双向认证

https

https 双向认证,我以前做的某个项目里用过,当时是做 B2B,公司的网站配置了双向数字认证,然后给所有客户签发数字证书,这样就只有认证的用户才能访问我们的网站。

基于这个思路,我的解决方案如下

给博客站再加一个域名(blog.refusea.com),该域名配置为使用双向数字证书认证主域名将管理后台页面屏蔽,这个只要在 nginx 上配置为返回 404 即可

站点的访客使用主域名访问是没有任何限制的,但是要访问管理后台,就必须持有数字证书

自签发证书

既然这个双向认证是自用的,就没必要花钱买证书了,完全可以用 openssl 来自建 CA,自己给自己签发服务器证书和客户端证书

自签证书的步骤

创建 CA 根证书用 CA 根证书签发二级 CA 证书用 二级 CA 证书签发服务器证书,配置 blog.refusea.com 域名为双向数字认证用 二级 CA 证书签发客户端证书,转换为 pkcs12 格式,导入到需要访问的电脑

自签发证书准备工作

环境为 Linux

mkdir /root/openssl # 服务器,客户端的 openssl.cnf cp /etc/pki/tls/openssl.cnf /root/openssl/server_openssl.cnf cp /etc/pki/tls/openssl.cnf /root/openssl/user_openssl.cnf # 修改上述文件 # 1) [ req ] 小节: 取消 req_extensions = v3_req 前面的注释 # 2) [ req_distinguished_name ] 小节: 注释 0.* 开头的内容 # 3) [ v3_req ] 小节 ## 服务端增加如下内容,其中 DNS.1 是服务器域名,多个域名可以用 DNS.2/DNS.3/... # extendedKeyUsage=serverAuth # subjectAltName = @alt_names # [ alt_names ] # DNS.1 = blog.refusea.com ## 客户端 # extendedKeyUsage=clientAuth

创建证书目录

# 如果想使用其他目录,修改 /etc/pki/tls/openssl.cnf 的 [ tsa_config1 ] 小节 mkdir /etc/pki/CA/newcerts -p touch /etc/pki/CA/index.txt # 如果文件不存在,用以下命令创建 echo 01 > /etc/pki/CA/serial cd /etc/pki/CA

签发 CA 根证书和二级 CA 证书

# 根证书 openssl genrsa -out ca_root.key 2048 openssl req -x509 -new -key ca_root.key -out ca_root.cer -days 3650 -subj "/C=CN/ST=GD/L=SZ/O=refusea/CN=Refusea-ROOT-CA" # 二级证书 openssl genrsa -out sub_ca.key 2048 openssl req -new -key sub_ca.key -out sub_ca.csr -subj "/C=CN/ST=GD/L=SZ/O=refusea/CN=Refusea-SUB-CA" openssl ca -extensions v3_ca -in sub_ca.csr -days 3650 -out sub_ca.cer -cert ca_root.cer -keyfile ca_root.key

用 二级 CA 证书签发服务器证书

openssl genrsa -out server.key 2048 openssl req -new -key server.key -out server.csr -subj "/C=CN/ST=GD/L=SZ/O=refusea/CN=blog.refusea.com" openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.cer -CA sub_ca.cer -CAkey sub_ca.key -CAcreateserial -extensions v3_req -extfile /root/openssl/server_openssl.cnf

用二级 CA 证书签发客户端证书

openssl genrsa -out user.key 2048 openssl req -new -key user.key -out user.csr -subj "/C=CN/ST=GD/L=SZ/O=refusea/CN=wordpress" openssl x509 -req -days 365 -in user.csr -signkey user.key -out user.cer -CA sub_ca.cer -CAkey sub_ca.key -CAcreateserial -extensions v3_req -extfile /root/openssl/user_openssl.cnf

将客户端证书导出为 pkcs12 格式

# 将根证书, 二级证书和用户证书合并 cat ca_root.cer sub_ca.cer user.cer > user_combination.cer # 用合并证书生成 p12,这样在导入时能同时导入根证书,注意设置导出密码 openssl pkcs12 -export -inkey user.key -in user_combination.cer -out user.p12

在导出为 pkcs12 时,会提示输入密码,这个密码在将证书导入到 windows 电脑时要进行验证,这样可以避免证书被盗导致的风险

nginx 配置双向认证

在 http 下增加新的 server 节点

server { listen 443 ssl; server_name blog.refusea.com; ssl_certificate cert/server.cer; ssl_certificate_key cert/server.key; ssl_session_timeout 5m; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; # 双向认证 ssl_client_certificate cert/ca_root.cer; ssl_verify_client on; location / { root /var/www/wordpress; index index.php index.html index.htm; } location ~ \.php$ { root /var/www/wordpress; fastcgi_pass unix:/run/php-fpm/www.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } }

nginx 主域名禁止访问管理后台

location = /wp-login.php { return 404; } location /wp-admin/ { return 404; }

效果展示

首先访问下管理后台

404

ok,效果达成,那么用新域名来访问下

400

因为这个时候还没有导入证书,所以返回 400 状态码,那么就导入下证书吧,双击 openssl 生成的 user.p12,出现以下界面

导入证书

一路默认即可,注意过程中需要输入密码,就是生成 pkcs12 时设置的密码。客户端证书导入成功后,会自动导入 CA 根证书

导入 CA 根证书到 windows

证书被导入到哪里了呢?我们 win+r 输入 certmgr.msc 查看

客户端证书

个人证书

二级 CA 证书

二级 CA 证书

根证书

CA 根证书

现在证书已经导入,可以再访问下管理后台了,浏览器需要重新打开下

安全警告

不知为啥,CA 根证书已经被信任,但是依然告警了,这里不管了,点击继续前往

选择证书

这里会弹出证书选择窗口,选中证书即可登录

登录界面

经过一番折腾,我的博客站点总算是安全了那么一点点。关于 openssl 制作证书,本文并未深入讲解,有空会再详细聊聊