Nginx之旅-基于Nginx的HTTPS服务

HTTPS原理和作用

为什么需要HTTPS呢?

原因:HTTP不安全

  1. 传输数据容易被中间人盗用,信息泄露
  2. 数据内容劫持,篡改

HTTPS是能够解决上述问题的,是因为HTTPS利用了加密的协议

要说清楚 HTTPS 协议的实现原理,至少需要如下几个背景知识。

  1. 大致了解几个基本术语(HTTPS、SSL、TLS)的含义
  2. 大致了解 HTTP 和 TCP 的关系(尤其是“短连接”VS“长连接”)
  3. 大致了解加密算法的概念(尤其是“对称加密与非对称加密”的区别)
  4. 大致了解 CA 证书的用途
  5. TCP通信协议的几次握手

HTTPS协议的实现:对传输内容进行加密以及身份验证

对称加密和非对称加密的含义

DHEDXj.png

上图就是一个典型的对称加密,加密方和解密方用的是相同的密钥。

DHEbAx.png

上图是典型的非对称加密,使用的是不同的密钥。公钥用于加密,私钥用于解密。

非对称加密的加密算法,特点是私钥加密后的密文,只要是公钥,都可以解密,但是公钥加密后的密文,只有私钥可以解密。

HTTPS加密协议原理

DHEvge.png

HTTPS加密既有对称加密,又有非对称加密。

在一开始的时候进行一次非对称加密,服务端将公钥发送给客户端,以后的数据传输都是利用这个公钥进行加密传输。

这是因为非对称的性能要求高,在第一次进行非对称加密之后,完全可以进行对称加密数据传输了。

中间人伪造客户端和服务端

DHVNr9.png

对于上图这种中间人,在客户端发送数据到服务端,以及服务端发送数据到客户端的时候都能够劫持。这样多次数据连接都能被劫持。

针对SSL的中间人攻击方式主要有两类,分别是SSL劫持攻击和SSL剥离攻击:

SSL劫持攻击

SSL劫持攻击即SSL证书欺骗攻击,攻击者为了获得HTTPS传输的明文数据,需要先将自己接入到客户端和目标网站之间;在传输过程中伪造服务器的证书,将服务器的公钥替换成自己的公钥,这样,中间人就可以得到明文传输带Key1、Key2和Pre-Master-Key,从而窃取客户端和服务端的通信数据
但是对于客户端来说,如果中间人伪造了证书,在校验证书过程中会提示证书错误,由用户选择继续操作还是返回,由于大多数用户的安全意识不强,会选择继续操作,此时,中间人就可以获取浏览器和服务器之间的通信数据

SSL剥离攻击

这种攻击方式也需要将攻击者设置为中间人,之后见HTTPS范文替换为HTTP返回给浏览器,而中间人和服务器之间仍然保持HTTPS服务器。由于HTTP是明文传输的,所以中间人可以获取客户端和服务器传输数据

SSL(Secure Socket Layer 安全套接层)是基于HTTPS下的一个协议加密层,最初是由网景公司(Netscape)研发,后被IETF(The Internet Engineering Task Force - 互联网工程任务组)标准化后写入(RFCRequest For Comments 请求注释),RFC里包含了很多互联网技术的规范!

起初是因为HTTP在传输数据时使用的是明文(虽然说POST提交的数据时放在报体里看不到的,但是还是可以通过抓包工具窃取到)是不安全的,为了解决这一隐患网景公司推出了SSL安全套接字协议层,SSL是基于HTTP之下TCP之上的一个协议层,是基于HTTP标准并对TCP传输数据时进行加密,所以HPPTS是HTTP+SSL/TCP的简称。

由于HTTPS的推出受到了很多人的欢迎,在SSL更新到3.0时,IETF对SSL3.0进行了标准化,并添加了少数机制(但是几乎和SSL3.0无差异),标准化后的IETF更名为TLS1.0(Transport Layer Security 安全传输层协议),可以说TLS就是SSL的新版本3.1,并同时发布“RFC2246-TLS加密协议详解”,如果想更深层次的了解TLS的工作原理可以去RFC的官方网站:www.rfc-editor.org,搜索RFC2246即可找到RFC文档!

不过如果我们利用了CA证书就能解决这个问题。

DHVDPK.png

这是因为,服务端返回给客户端的不再是公钥而是CA证书。客户端会和第三方签名机构进行校验CA证书。CA证书里面有对应的公钥。

相比之前只发送公钥比,这种就很安全。因为服务端事先会和第三方机构进行对应的签名和授权。

这样利用CA证书,就能完全预防中间人劫持。

证书签名生成CA证书

生成的是自签证书

下面我们生成密钥和CA证书:

首先检查模块是否安装

1
2
[root@hongshaorou ~]# openssl version
OpenSSL 1.0.2k-fips 26 Jan 2017

Nginx对应模块是否加载

1
2
[root@hongshaorou ~]# nginx -V
--with-http_ssl_module

步骤一:(利用openssl)生成key密钥

步骤二:生成证书签名请求文件(csr文件)

上述两步完成之后就可以一起打包发送到对应的结构 关于网站和公司信息进行CA证书签名,机构将返回CA证书。

步骤三:生成证书签名文件(CA文件)

证书签名生成和Nginx的HTTPS服务场景

注意:一般生成的文件放在/etc/nginx/ssl目录下,这是个好的习惯。

生成key文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[root@hongshaorou ~]# cd /etc/nginx/

[root@hongshaorou nginx]# mkdir ssl_key
[root@hongshaorou nginx]# cd ssl_key/

# 生成key密钥 idea 对称加密 1024 加密位数 位数越高 精度越高
[root@hongshaorou ssl_key]# openssl genrsa -idea -out hongsr.key 1024
Generating RSA private key, 1024 bit long modulus
............++++++
..............++++++
e is 65537 (0x10001)
# 根据提示输入密码
Enter pass phrase for hongsr.key:
Verifying - Enter pass phrase for hongsr.key:

# 生成key文件
[root@hongshaorou ssl_key]# ls
hongsr.key

生成证书签名请求文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 命令
[root@hongshaorou ssl_key]# openssl req -new -key hongsr.key -out hongsr.csr

Enter pass phrase for hongsr.key:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:Zhejiang
Locality Name (eg, city) [Default City]:Hangzhou
Organization Name (eg, company) [Default Company Ltd]:dabaojian
Organizational Unit Name (eg, section) []:imooc
Common Name (eg, your name or your server's hostname) []:hongshaorou.com
Email Address []:123456@qq.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:imooc

# 生成csr文件
[root@hongshaorou ssl_key]# ls
hongsr.csr hongsr.key

生成这两个文件就可以打包发给三方机构了

生成自签名证书

1
2
3
4
5
6
7
8
9
[root@hongshaorou ssl_key]# openssl x509 -req -days 3650 -in hongsr.csr -signkey hongsr.key -out hongsr.crt
Signature ok
subject=/C=CN/ST=Zhejiang/L=Hangzhou/O=dabaojian/OU=imooc/CN=hongshaorou.com/emailAddress=123456@qq.com
Getting Private key
Enter pass phrase for hongsr.key:

# 最后生成证书
[root@hongshaorou ssl_key]# ls
hongsr.crt hongsr.csr hongsr.key

其中的-days 3650 签名证书的过期时间,默认过期时间是一个月。

Nginx的HTTPS语法配置

是否开启

1
2
3
Syntax: ss|on|off;
Default:ssl off;
Context:http,server

证书文件

1
2
3
Syntax:ssl_certificate file;
Default:-
Context:http,server

密码文件

1
2
3
Syntax:ssl_certificate_key file;
Default:-
Context:http,server

新增配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
server
{
listen 443;
server_name hongshaorou.com;
ssl on;
ssl_certificate /etc/nginx/ssl_key/hongsr.crt;
ssl_certificate_key /etc/nginx/ssl_key/hongsr.key;


index index.html index.htm;
location / {
root /opt/app/code;
}
}

检查配置

1
2
3
4
[root@hongshaorou conf.d]# nginx -t
Enter PEM pass phrase:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

需要我们输入生成密码文件的密码。

重启nginx服务

1
2
3
4
[root@hongshaorou nginx]# nginx -c /etc/nginx/nginx.conf
Enter PEM pass phrase:
[root@hongshaorou nginx]# netstat -tlunp | grep 443
tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN 29073/nginx: master

其他命令

1
2
3
4
5
6
7
8
//停止 需要输入设置的key密码
nginx -s stop -c /etc/nginx/nginx.conf
//启动
nginx -c /etc/nginx/nginx.conf
//检查语法
nignx -tc /etc/nginx/nginx.cof
//查看端口是否启用
netstat -luntp |grep 443

访问页面https://192.168.205.10/admin.html将会出现下面的情形

DHZyF0.png

之所以是这样是因为我们的证书是自己的咩有拿到去第三方机构认证,点击高级继续前往将会访问到真正的页面。

配置苹果要求的HTTPS服务

下面是苹果公司要求HTTPS要实现的技术细节。

  • 服务器所有的连接使用TLS1.2以上的版本(openssl1.0.2)
  • https证书必须使用SHA256以上的哈希算法签名
  • Https证书必须使用RSA 2048位 或ECC 256以上的公钥算法
  • 使用前向加密技术

查看当前openssl证书版本

1
2
[root@hongshaorou nginx]# openssl version
OpenSSL 1.0.2k-fips 26 Jan 2017

符合要求不要升级

查看加密算法

DHZ5wR.png

加密算法是256,位数是2048。

重新生成证书

1
[root@hongshaorou ssl_key]# openssl req -days 36500 -x509 -sha256 -nodes -newkey rsa:2048 -keyout hongsr.key -out hongsr.crt

重启

1
2
3
4
5
6
7
[root@hongshaorou ssl_key]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@hongshaorou ssl_key]#
[root@hongshaorou ssl_key]# nginx -s reload -c /etc/nginx/nginx.conf
[root@hongshaorou ssl_key]# netstat -tlunp | grep 443
tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN 1744/nginx: worker

这种配置方式,在重启停止nginx不需要输入key的密码,因为在生成的时候配置了一个参数 -keyout 重新生成新的(没有保护码的)文件

SSL证书去除私钥密码保护 生成没有保护码 key 的方式(通过拷贝的方式去掉密码保护码):

1
openssl rsa -in ./applelife.key -out ./applelife_nopass.key
HTTPS服务优化

减少 CPU 运算量

SSL 的运行计算需要消耗额外的 CPU 资源,一般多核处理器系统会运行多个工作进程(worker processes ),进程的数量不会少于可用的 CPU 核数。SSL 通讯过程中『握手』阶段的运算最占用 CPU 资源,有两个方法可以减少每台客户端的运算量:

  • 激活 keepalive 长连接,一个连接发送更多个请求
  • 复用 SSL 会话参数,在并行并发的连接数中避免进行多次 SSL『握手』(设置ssl session缓存)

这些会话会存储在一个 SSL 会话缓存里面,通过命令 ssl_session_cache 配置,可以使缓存在机器间共享,然后利用客戶端在『握手』阶段使用的 seesion id 去查询服务端的 session cathe(如果服务端设置有的话),简化『握手』阶段。

1M 的会话缓存大概包含 4000 個会话,默认的缓存超时时间为 5 分钟,可以通过使用 ssl_session_timeout 命令设置缓存超时时间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
server {
listen 443;
server_name 192.33.2.1;

#让长连接保持更长
keepalive 100;
ssl on;
#设置缓存10M 大约可以存储 8000到10000 个会话
ssl_session_cache shared:SSL:10m;
#配置10分钟 session过期
ssl_session_timeout 10m;

#证书文件
ssl_certificate /etc/nginx/ssl_key/applelife.crt;
#key文件
ssl_certificate_key /etc/nginx/ssl_key/applelife.key;

}

ssl session缓存作用:用于缓存 https建立连接后的session key,减少后续因为断开后需要重新建连造成的性能损耗。
DHmmKe.png

推荐阅读:

Nginx 配置 HTTPS 服务器

HTTPS协议和原理

MITM攻击(中间人攻击)

菜鸟学网络之 —— 长连接和短连接

知识就是财富
如果您觉得文章对您有帮助, 欢迎请我喝杯水!