Nginx Https 配置

Https简介

要保证Web浏览器到服务器的安全连接,HTTPS几乎是唯一选择。HTTPS其实就是HTTP over SSL,也就是让HTTP连接建立在SSL安全连接之上, 并不是一个单独的应用层协议。那么对于Https, 只需要了解Http(参考HTTP详解)和SSL协议即可。而所谓的HTTPS报文也就是SSL报文:

HTTPS作用

不使用SSL/TLS的HTTP通信,就是不加密的通信。所有信息明文传播,带来了三大风险。

(1) 窃听风险(eavesdropping):第三方可以获知通信内容。

(2) 篡改风险(tampering):第三方可以修改通信内容。

(3) 冒充风险(pretending):第三方可以冒充他人身份参与通信。

SSL/TLS协议是为了解决这三大风险而设计的,希望达到:

(1) 所有信息都是加密传播,第三方无法窃听。

(2) 具有校验机制,一旦被篡改,通信双方会立刻发现。

(3) 配备身份证书,防止身份被冒充。

SSL协议

SSL(Secure Socket Layer)安全套接层,是一种位于应用层与传输层之间,为网络通信提供安全及完整性验证的一种网络协议。
相对于TCP或HTTP协议,SSL协议要复杂很多。由于它也是建立在TCP协议之上的,所以在使用SSL传输数据之前需要先进行三次握手和服务器建立连接,具体的流程如图所示:

SSL协议的握手过程

  • (1) 客户端先给服务端发送一个消息,消息内容包括:客户端支持的加密方式,支持的压缩方法SSL的版本号客户端生成的随机数,文本内容“Hello”等;

  • (2) 服务端接收到消息后,也回复一个Hello,并携带从客户端支持的加密方式中选择的加密方式服务端生成的随机数服务端的SSL版本号等信息;

  • (3) 随后服务器给客户端发送一个Certificate报文,报文中包含服务端的公钥证书

  • (4) 紧接着服务器给客户端发送Server Hello Done, 表示最初的协商握手过程结束;

  • (5) 客户端接收到服务端发送的握手结束的消息后,以Client Key Exchange作为回应,此报文中包含通信加密过程中使用的一种被称为Pre-master secret的随机密码串,并使用第三步接收到的公钥证书进行了加密;

  • (6) 接着客户端发送Change Cipher Spec报文,该报文告知服务端,此步骤之后的所有数据将使用第五步中生成的master secret进行加密(master secret的生成过程看后面的介绍);

  • (7) 随后客户端发送Finish报文,此报文中包含连接至今所有报文的整体校验值,用于完整性验证;

  • (8) 服务端接收到客户端发送的Change Cliper Spec报文后,同样以Change Cliper Spec报文 作为回应;

  • (9) 接着服务端发送Finish报文给客户端,表示服务端已正确解析客户端发送的整体校验值,至此,SSL握手的过程结束。

随后开始使用HTTP协议传输使用master secret加密过的数据。

说明

  • 前两步是协商加密算法以及传输各自生成的随机数(为后续生成master secret做准备)的过程;

  • 第三步服务端将自己的证书发送给客户端,这个证书中包含一个数字签名(CA签名)和服务端CA证书的公钥,客户端对证书中包含的服务端信息进行Hash, 同时使用接收到的公钥对数字证书解密,获取其中的Hash值,与前面计算得到的Hash值进行比较,即可验证证书的有效性(完整性&真实性);

  • 服务端收到客户端发送的Change Cipher Spec(第五步),会使用自己的私钥进行解密,获取报文中的Pre-master secret,这时通信双方都拥有对方的Random(前两步生成的),Pre-master secret,以及自身的Random, 将三个数作为种子通过算法生成master secret, 用来加密后续Http请求过程中的数据。其中master secret的生成规则为:

1
2
3
4
5
6
master_secret =
MD5(pre_master_secret + SHA('A' + pre_master_secret + ClientHello.random + ServerHello.random)) +

MD5(pre_master_secret + SHA('BB' + pre_master_secret + ClientHello.random + ServerHello.random)) +

MD5(pre_master_secret + SHA('CCC' + pre_master_secret + ClientHello.random + ServerHello.random));

CA证书

  • 私钥
    私钥就是一个算法名称加上密码串,自己保存,从不给任何人看

  • 公钥
    公钥也是一个算法名称加上密码串,一般不会单独给别人,而是嵌在证书里面一起给别人

  • CA
    专门用自己的私钥给别人进行签名的单位或者机构

  • 申请(签名)文件
    公钥的基础上加上一些申请人的属性信息,比如我是谁,来自哪里,名字叫什么,证书适用于什么场景等的信息,然后带上进行的签名,发给CA(私下安全的方式发送),带上自己签名的目的是为了防止别人篡改文件。

  • 证书文件
    证书由公钥加上描述信息,然后经过私钥签名之后得到,一般都是一个人的私钥给另一个人的公钥签名,如果是自己的私钥给自己的公钥签名,就叫自签名

  • 签名过程
    CA收到申请文件后,会走核实流程,确保申请人确实是证书中描述的申请人,防止别人冒充申请者申请证书,核实通过后,会用CA的私钥对申请文件进行签名,签名后的证书包含申请者的基本信息,CA的基本信息,证书的使用年限,申请人的公钥,签名用到的摘要算法,CA的签名

签完名之后,证书就可以用了。

证书如何验证

下面以浏览器为例,说明证书的验证过程:

  • 在TLS握手的过程中,浏览器得到了网站的证书

  • 打开证书,查看是哪个CA签名的这个证书

  • 在自己信任的CA库中,找相应CA的证书,

  • 用CA证书里面的公钥解密网站证书上的签名,取出网站证书的校验码(指纹),然后用同样的算法(比如sha256)算出出网站证书的校验码,如果校验码和签名中的校验码对的上,说明这个证书是合法的,且没被人篡改过

  • 读出里面的CN,对于网站的证书,里面一般包含的是域名

  • 检查里面的域名和自己访问网站的域名对不对的上,对的上的话,就说明这个证书确实是颁发给这个网站的

到此为止检查通过。

如果浏览器发现证书有问题,一般是证书里面的签名者不是浏览器认为值得信任的CA,浏览器就会给出警告页面,这时候需要谨慎,有可能证书被掉包了。如访问12306网站,由于12306的证书是自己签的名,并且浏览器不认为12306是受信的CA,所以就会给警告,但是一旦你把12306的根证书安装到了你的浏览器中,那么下次就不会警告了,因为你配置了浏览器让它相信12306是一个受信的CA。

SSL证书类型

SSL使用证书来创建安全连接。有两种验证模式:

  • 1 仅客户端验证服务器的证书,客户端自己不提供证书;

  • 2 客户端和服务器都互相验证对方的证书。

显然第二种方式安全性更高,一般用网上银行会这么搞,但是,大部分服务只需要采用第一种方式就可以。

服务器自己的证书必须经过某“权威”证书的签名,而这个“权威”证书又可能经过更权威的证书签名,这么一级一级追溯上去,最顶层那个最权威的证书就称为根证书。根证书直接内置在浏览器中,这样,浏览器就可以利用自己自带的根证书去验证某个服务器的证书是否有效。

SSL证书级别分为三种类型,域名型SSL证书(DV SSL)、企业型SSL证书(OVSSL)、增强型SSL证书(EVSSL)

1. 域名型 SSL 证书(DV SSL - Domain Validation SSL)

即证书颁布机构只对域名的所有者进行在线检查,通常是验证域名下某个指定文件的内容,或者验证与域名相关的某条 TXT 记录;

比如访问 [http|https]://www.mimvp.com/.../test.txt,文件内容: 2016082xxxxxmimvpcom2016

或添加一条 TXT 记录:www.mimvp.com –> TXT –> 20170xxxxxmimvpcom2066

2. 企业型 SSL 证书(OV SSL - Organization Validation SSL)

是要购买者提交组织机构资料和单位授权信等在官方注册的凭证,

证书颁发机构在签发 SSL 证书前,不仅仅要检验域名所有权,

还必须对这些资料的真实合法性进行多方查验,只有通过验证的才能颁发 SSL 证书。

3. 增强型 SSL 证书(EV SSL - Extended Validation SSL)

与其他 SSL 证书一样,都是基于 SSL/TLS 安全协议,

但是验证流程更加具体详细,验证步骤更多,

这样一来证书所绑定的网站就更加的可靠、可信。

它跟普通 SSL 证书的区别也是明显的,安全浏览器的地址栏变绿,

如果是不受信的 SSL 证书则拒绝显示,如果是钓鱼网站,地址栏则会变成红色,以警示用户。

自签名证书生成

下面简单介绍如何创建一个自签名的SSL证书。执行脚本create_cert.sh即可。

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
#!/bin/bash

## 生成秘钥key
## 会有两次要求输入密码,输入同一个即可,
## 然后你就获得了一个server.key文件.
openssl genrsa -des3 -out server.key 2048

## 以后使用此文件(通过openssl提供的命令或API)可能经常回要求输入密码
## 如果想去除输入密码的步骤可以使用以下命令:
openssl rsa -in server.key -out server.key


## 创建服务器证书的申请文件server.csr
## 其中Country Name填CN,Common Name填主机名也可以不填,如果不填浏览器会认为不安全.
## (例如你以后的url为https://abcd/xxxx....这里就可以填abcd),其他的都可以不填.
openssl req -new -key server.key -out server.csr


## 创建CA证书
## 此时,你可以得到一个ca.crt的证书,这个证书用来给自己的证书签名.
openssl req -new -x509 -key server.key -out ca.crt -days 3650


## 创建自当前日期起有效期为期十年的服务器证书server.crt
openssl x509 -req -days 3650 -in server.csr -CA ca.crt -CAkey server.key -CAcreateserial -out server.crt

其中第三条指令在第二步第二条时会出来一个填写资料的界面(我已经填好参考,有些地方可以空着)

1
2
3
4
5
6
7
Country Name (2 letter code) [AU]:CN
State or Province Name (full name) [Some-State]:BEIJING
Locality Name (eg, city) []:haidian
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Baidu
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:localhost
Email Address []:

这里有点要注意, Common Name (e.g. server FQDN or YOUR name) []: 这一项,是最后可以访问的域名,我这里为了方便测试,写成 localhost ,如果是为了给网站生成证书,需要写成 xxxx.com 。

脚本执行完成后,ls你的文件夹,可以看到一共生成了5个文件:
ca.crt ca.srl server.crt server.csr server.key
其中,server.crtserver.key就是你的nginx需要的证书文件.

配置nginx

(1) 查看nginx是否安装了ssl模块

nginx -V

nginx version

又红框中标记内容,则表示已经安装了ssl模块,否则需要手动安装或是更换nginx版本。

###(2)配置nginx

将之前生成的密钥及证书文件server.crtserver.key拷贝到nginx配置文件nginx.conf同级目录,然后修改nginx.conf.

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# HTTPS server
server {
listen 443 ssl;
server_name localhost; # 域名

ssl_certificate server.crt;
ssl_certificate_key server.key;

ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;

ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;

location / {
root /home/bigdata/dayu/www/;
index index.html;
proxy_set_header Host $http_host;
rewrite (.*) /index.html break;
}

location /public/ {
root /home/bigdata/dayu/www;
}

location /metamap/ {
proxy_pass http://127.0.0.1:8083/;
proxy_redirect /metamap/ http://127.0.0.1:8083/;
proxy_set_header Host $http_host;
}


location /bflow/ {
proxy_pass http://127.0.0.1:8084/;
proxy_redirect /workflow/ http://127.0.0.1:8084/;
proxy_set_header Host $http_host;
}

location /authenticate/ {
proxy_pass http://cp01-mxnet-test.epc.baidu.com:8010/;
proxy_redirect /authenticate/ http://127.0.0.1:8082/;
proxy_set_header Host $http_host;
}
}