首先,SSL/TLS是什么?
比如:https://www.db.ci/,前面是https,表明这个是https协议。
https就是http + SSL/TLS,在http外面套一个加密层,让第三方难以得到传输的明文数据。
如果用chrome访问这个站,在这个URL旁边会显示一个绿色的锁,表明这个连接是安全的。
另外,境外的https还有一个附加效果,就是抵御关键字的审查,同时Google也更喜欢收录https的站点。
其实以上是在说废话,看这文章的乃萌肯定是知道此为何物才会找到这里来的啦,所以就不废话了。
由于这里主要讲搭建步骤,去CA机构注册什么的就不介绍了,个人小站推荐 StartSSL 和 AlphaSSL ,前者可以得到免费证书。
1 生成证书签署请求文件
新建一个目录,并在这个目录中生成密钥文件(.key)和证书签署请求文件(.csr):
$ mkdir /etc/nginx/ssl $ cd /etc/nginx/ssl $ openssl req -new -newkey rsa:2048 -sha256 -nodes -out www.db.ci.csr -keyout www.db.ci.key
其中,
req:表示指定证书类型,后面一般跟-new或者-x509选项。-new说明要生成证书请求,x509说明要生成自签名证书。
-newkey:表示在生成证书请求或者自签名证书时自动生成密钥,本例要求生成2048位的rsa密钥。
-sha256:表示签名算法使用sha256。openssl默认采用sha1加密,而现代已将 sha1 加密方式认定为非安全,故使用sha2。
-nodes:表示认证过程不需要输入密码。
-out:指定证书名称。
-keyout:指定密钥名称。
然后会要求你输入一些信息,具体如下,从 Email Address 开始不要填写:
Country Name (2 letter code) [AU]:CN State or Province Name (full name) [Some-State]:Guangdong Locality Name (eg, city) []:Shenzhen Organization Name (eg, company) [Internet Widgits Pty Ltd]:Awaimai Inc. Organizational Unit Name (eg, section) []:Web Security Common Name (eg, YOUR name) []:www.db.ci Email Address []: A challenge password []: An optional company name []:
Common Name 填写你要 SSL 支持的域名,如 www.db.ci,泛域名证书填*.db.ci。
填写完毕后,就会生成 www.db.ci.csr请求文件和www.db.ci.key密钥文件。
上面的信息也可以在openssl命令后加上-subj参数指定,省去证书信息的录入过程:
$ openssl req -new -newkey rsa:2048 -sha256 -nodes -out www.db.ci.csr -keyout www.db.ci.key -subj "/C=CN/ST=Guangdong/L=Shenzhen/O=DBCI Inc./OU=Web Security/CN=www.db.ci"
这样第一步就完成了。
2 签发一个crt证书
使用编辑器打开刚才生成的csr文件,会看到类似如下的内容:
-----BEGIN CERTIFICATE REQUEST----- MIICrjCCAZYCAQAwaTELMAkGA1UEBhMCR0IxDzANBgNVBAgMBkxvbmRvbjEPMA0G ...... -----END CERTIFICATE REQUEST-----
复制里面全部内容,然后在CA机构网站上,提交csr内容的地方粘贴。
如下是 Let's Encrypt 和 AlphaSSL 的网站地址。
Let's Encrypt(免费) :https://letsencrypt.org/ AlphaSSL :http://www.alphassl.com/
签发成功后,就能下载回来一个.crt文件,可能通过网页上下载,也可能通过邮件方式发送给你。
如果是邮件方式的话,最好是使用Gmail邮箱。
邮件方式的话需要自行复制里面crt文件的部分自行保存为crt文件。
crt文件类似以下的格式:
-----BEGIN CERTIFICATE----- MIIETTCCAzWgAwIBAgILBAAAAAABRE7wNjEwDQYJKoZIhvcNAQELBQAwVzELMAkG ... -----END CERTIFICATE-----
保存好了后,第二步就完成了。
3 配置证书链
这一步在某些情况下不是必需的,建议先跳过这一步。
如果Chrome访问网站提示网站不可信,再配置证书链。如果已经提示安全,则不需要配置证书链。
前面推荐的两家机构所签发的证书没有直接返回证书链,需要自行配置。
用Chrome访问网站,按F12进入调试模式,选Security标签,点击View Certificate按钮查看证书。
如上,我的网站与根证书中间差了一级,上上一级才是根证书DST Root CA X3。
而浏览器和操作系统里面保存的均是可信任的根证书,中间那一层Let's Encrpt Authority X3很可能是没有的。
直接使用CA机构提供的crt证书,可能导致浏览器提示这是不可信的网站。
那如何配置证书链?其实配置这个证书链非常的简单。
首先,选择父级证书,点击【查看证书】,选【详细信息】,【 复制到文件】,到处格式用“base64 编码 X.509(.CER)”,然后导出父级证书。
同理,导出父级的父级证书。
使用文本编辑器打开crt证书,然后父级crt证书的内容粘贴到后面,像这样子:
-----BEGIN CERTIFICATE----- 自己的crt证书 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- 父级的crt证书 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- 父级的父级crt证书 -----END CERTIFICATE-----
有多少层就做多少层(除了根证书那一层),然后保存为新的crt文件,如cert_chain.crt。
就完成了证书链的配置了。
4 Nginx配置
文本编辑器打开nginx配置文件,找到相应域名。
删除对80端口的监听:
listen 80;
加入如下配置:
server { # ... # 监听443端口 listen 443 ssl; # 开启ssl ssl on; # 指定域名 server_name www.db.ci; # 指定证书 ssl_certificate /etc/nginx/ssl/cert_chain.crt; # 指定密钥 ssl_certificate_key /etc/nginx/ssl/www.db.ci.key; # 使用HSTS(HTTP Strict Transport Security)策略,强制浏览器总是使用HTTPS连接, # 这样攻击者在用戶与服务器通讯过程中便难以拦截、篡改信息以及冒充身份变 add_header Strict-Transport-Security max-age=31536000; # ... }
然后再加一个server块,监听80端口,301跳转到https:
server { listen 80; server_name www.db.ci db.ci; add_header Strict-Transport-Security max-age=31536000; return 301 https://www.db.ci$request_uri; }
重启服务即可。
5 使用赫尔曼密钥(可选)
为了更安全 ,可以考虑使用迪菲-赫尔曼密钥交换。
在Shell命令行:
$ cd /etc/nginx/ssl $ openssl dhparam -out dhparam.pem 2048 # 生成迪菲-赫尔曼密钥
然后在nginx ssl配置的后面,加上下面的配置:
server { # ... # 设置服务器加密方式优先于客户端 ssl_prefer_server_ciphers on; # 指定迪菲-赫尔曼密钥位置 ssl_dhparam /etc/nginx/ssl/dhparam.pem; # 使用安全协议,禁止其他不安全的 SSL 协议 ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # 禁止已经不安全的加密算法 ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS !RC4"; # ... }
6 HTTPS服务器优化(可选)
SSL 的运行计算需要消耗额外的 CPU 资源,其中 SSL 通讯过程中『握手』阶段的运算最占用 CPU 资源。
有两个方法可以减少每台客户端的运算量:
激活 keepalive 长连接,一个连接发送更多个请求
配置ssl_session_cache,复用 SSL 会话参数,在并发的连接数中避免进行多次 SSL『握手』
这样,session会存储在一个 SSL 会话缓存里面。
1M 的ssl_session_cache大概包含 4000 个会话。
然后利用客戶端在『握手』阶段使用的 seesion id 去查询服务端的 session cache,简化『握手』阶段。
另外,还可以使用 ssl_session_timeout 配置缓存超时时间,默认5分钟。
配置范例:
server { # ... # 配置共享会话缓存大小 ssl_session_cache shared:SSL:10m; # 配置会话超时时间 ssl_session_timeout 10m; # 设置长连接 keepalive_timeout 70; # ... }
一般情況下,还可以加上以下几个命令,增强安全性:
# 减少点击劫持 add_header X-Frame-Options DENY; # 禁止服务器自动解析资源类型 add_header X-Content-Type-Options nosniff; # 防XSS攻击 add_header X-Xss-Protection 1;
7 配置 HTTP/2 (可选)
HTTP/2于2015年5月作为互联网标准正式发布。
它基于Google制定的SPDY协议,由IETF HTTPbis小组制定维护。
并且Google表示将放弃SPDY转而全力支持HTTP/2。
HTTP/2 与 HTTP/1.x 的主要区别:
基于二进制而不是文本的
完全多路复用,代替原来的排序和阻塞机制
在一条连接中并行处理多个请求
压缩头部减少开销
允许服务器主动推送响应到客户端的缓存中
配置HTTP/2之前,我们要确保:
openssl版本为1.0.2+,因为HTTP/2需要openssl支持ALPN
Nginx版本为1.9.5+,因为这个版本默认编入了--with-http_v2_module
$ openssl version # openssl必须为1.0.2或以上版本 $ nginx -V # 1.9.5或以上版本,低于这个版本需要自行编译加入--with-http_v2_module
如果版本不满足要求,则需要重新编译,编译之前需要安装一些依赖工具和库:
$ yum install gcc-c++ pcre-devel zlib-devel make wget openssl-devel libxml2-devel libxslt-devel gd-devel perl-ExtUtils-Embed GeoIP-devel gperftools-devel
7.1 更新openssl
openssl更新步骤:
$ wget https://www.openssl.org/source/openssl-1.0.2-latest.tar.gz $ tar -zxf openssl-1.0.2-latest.tar.gz $ cd openssl-1.0.2k $ ./config $ make depend $ make $ make install
完成之后,如果还是显示原来版本,则:
$ mv /usr/bin/openssl ~ # 备份原来的文件 $ ln -s /usr/local/ssl/bin/openssl /usr/bin/openssl # 新的bin文件软链到系统/usr/bin目录下
7.2 重新编译nginx
用nginx -V命令可以看到nginx编入的 openssl 版本,我的是OpenSSL 1.0.1e-fips,明显不满足要求。
我们需要编入为openssl 1.0.2 或以上版本,所以要重新编译一遍nginx。
$ wget http://nginx.org/download/nginx-1.10.3.tar.gz $ tar zxf nginx-1.10.3.tar.gz $ cd nginx-1.10.3 $ ./configure ... $ make $ make install
./configure后面的配置项请自行加上,也可以直接拷贝nginx -V命令输出的配置参数。
7.3 配置http2
在端口监听处加上http2就可以了:
server { # ... listen 443 ssl http2; # ... }
7 总结
最后嘛,为啥窝会想到弄成https呢?
因为窝知道很多路由器可以开启网站访问log,会记录下访问者IP、所访问的url、以及get/post参数内容。这表示什么吗?
这表示如果你通过这个路由器上网,然后在普通 http 网页上做登陆操作,那么路由器的管理员可以通过查 log 得到你对应网站的登陆信息。
这是非常危险的。
因为绝大多数的网站在传输登陆信息的时候,均使用明文发送密码,这样你的帐号密码就被看得一清二楚了。
但是 https 的话,路由器根本无法知道你所访问的 url 是什么,更别说具体的参数内容了,只能知道访问者的IP和目标IP,安全性自然大大提高。
比如你在麦当劳用免费 wifi,那么那边的路由管理员就知道你的帐号密码了。
或者电信联通什么的也会知道,因为它们在政策下必须保留至少3个月的路由数据,而你的帐号密码就在那里保存至少三个月。
想要抓你只要把你的登陆记录找到,然后登陆你的帐号,查你的个人信息就知道你到底是谁了。
也就是说,任何非https连接下做登陆或其它敏感操作是非常危险的,所有的操作被完整的记录了下来。
本文除了介绍SSL/TLS的配置外,还简要的介绍了一下其必要性,科普一下网络安全方面的东西。
如对这方面还有疑问,欢迎留言或mail。