Nginx配置ssl模块踩坑与过坑案例

达芬奇密码2018-07-19 10:15

前景提要

目前越来越多的产品开始采用HTTPS,而采用HTTPS就需要SSL证书,所以需要在nginx中使用ssl模块配置HTTPS的支持。本文就是nginx配置ssl模块中一个踩坑与过坑的案例。

HTTPS科普:

首先来科普下什么是HTTPSHTTPS (基于安全套接字层的超文本传输协议 或者是 HTTP over SSL) 是一个 Netscape 开发的 Web 协议。可以这么认为:HTTPS = HTTP + SSL

超文本传输协议 (HTTP) 是一个用来通过互联网传输和接收信息的协议。HTTP 使用请求/响应的过程,因此信息可在服务器间快速、轻松而且精确的进行传输,当我们在访问web页面时,采用的是不安全的HTTP协议。所以Netscape推出了HTTPS,也就是基于安全套接字层的 HTTP 协议

大多数情况下,HTTP  HTTPS 是相同的,因为都是采用同一个基础的协议,作为 HTTP  HTTPS 客户端——浏览器,设立一个连接到 Web 服务器指定的端口。当服务器接收到请求,它会返回一个状态码以及消息,这个回应可能是请求信息、或者指示某个错误发送的错误信息。系统使用统一资源定位器 URI 模式,因此资源可以被唯一指定。而 HTTPS  HTTP 唯一不同的只是一个协议头(https)的说明,其他都是一样的。下文列举一下HTTP  HTTPS 的不同之处:

HTTP 的 URL 以 http:// 开头,而 HTTPS 的 URL 以 https:// 开头
HTTP 是不安全的,而 HTTPS 是安全的
HTTP 标准端口是 80 ,而 HTTPS 的标准端口是 443
在 OSI 网络模型中,HTTP 工作于应用层,而 HTTPS 工作在传输层
HTTP 无需加密,而 HTTPS 对传输的数据进行加密
HTTP 无需证书,而 HTTPS 需要认证证书

简而言之,在使用HTTPS连接时,服务器要求有公钥和签名的证书。当使用 https 连接,服务器响应初始连接,并提供它所支持的加密方法。作为回应,客户端选择一个连接方法,并且客户端和服务器端交换证书验证彼此身份。完成之后,在确保使用相同密钥的情况下传输加密信息,然后关闭连接。为了提供 https 连接支持,服务器必须有一个公钥证书,该证书包含经过证书机构认证的密钥信息,大部分证书都是通过第三方机构授权的,以保证证书是安全的。上文提到HTTPS = HTTP + SSL,那HTTP和SSL分别需要做的工作是这样的:

HTTP 包含如下动作:

浏览器打开一个 TCP 连接
浏览器发送 HTTP 请求到服务器端
服务器发送 HTTP 回应信息到浏览器
TCP 连接关闭

SSL 包含如下动作:

验证服务器端
允许客户端和服务器端选择加密算法和密码,确保双方都支持
验证客户端(可选)
使用公钥加密技术来生成共享加密数据
创建一个加密的 SSL 连接
基于该 SSL 连接传递 HTTP 请求

nginx配置

当然,前面的都是铺垫,本文的重点终于来了。就是如何生成SSL证书并配置nginx。这部分通常都是PE或者SA进行操作的,但是如果想在测试环境自己玩一玩的话,那么攻略来了。

1. 生成证书

可以通过以下步骤生成一个简单的证书:
首先,进入你想创建证书和私钥的目录,例如:
$ cd /home/appuser/nginx-1.4.7/conf
创建服务器私钥,命令会让你输入一个口令:
$ openssl genrsa -des3 -out cookie.key 1024
创建签名请求的证书(CSR):
$ openssl req -new -key cookie.key -out cookie.csr
在加载SSL支持的Nginx并使用上述私钥时除去必须的口令:
$ cp cookie.key cookie.key.org
$ openssl rsa -in cookie.key.org -out cookie.key

2. 配置nginx

最后标记证书使用上述私钥和CSR:
$ openssl x509 -req -days 365 -in cookie.csr -signkey cookie.key -out cookie.crt
修改Nginx配置文件,让其包含新标记的证书和私钥:
server {
    server_name YOUR_DOMAINNAME_HERE;
    listen 443;
    ssl on;
    ssl_certificate /usr/local/nginx/conf/server.crt;
    ssl_certificate_key /usr/local/nginx/conf/server.key;
}
重启nginx

踩坑与过坑

本来以为这样就可以万事大吉了,但是在压力提高以后,就会出现一些错误。去查看nginx的错误日志以及dmesg的报错如下:

nginx报错:

2016/12/26 19:37:48 [alert] 27592#0: worker process 27593 exited on signal 11
2016/12/26 19:37:48 [alert] 27592#0: worker process 27596 exited on signal 11
2016/12/26 19:37:49 [alert] 27592#0: worker process 27594 exited on signal 11

dmesg报错:

[51059663.024824] nginx[32061]: segfault at 0 ip 00000000004248db sp 00007fffffba9b70 error 4 in nginx[400000+92000]
[51059668.968624] show_signal_msg: 54 callbacks suppressed
[51059668.968628] nginx[32115]: segfault at 0 ip 00000000004248db sp 00007fffffba9b30 error 4 in nginx[400000+92000]
[51059669.036477] nginx[32184]: segfault at 0 ip 00000000004248db sp 00007fffffba9b30 error 
这种信息一般都是由内核内存访问越界造成的,不管是用户态程序还是内核态程序访问越界都会出core,并在系统日志里面输出一条这样的信息。这条信息的前面分别是访问越界的程序名,进程id号,访问越界的地址以及当时进程进程堆栈地址等信息,比较有用的信息是最后的error number.在上面的信息中。 error number是由3个字位组成的,从高到低分别是bit2、bit1、bit0,转成二进制就是100,即bit2=1,bit1=0,bit0=0,所以它的取值范围是0~7,每个字位的含义是:
bit2:值为1时表示 是用户态程序内存访问越界,值为0时表示 是内核态程序内存访问越界
bit1:值为1时表示 是写操作导致内存访问越界,值为0时表示 是读操作导致内存访问越界
bit0:值为1表示没有足够的权限访问非法地址的内容,值为0时表示访问的非法地址根本没有对应的页面,也就是无效地址。
因此error number 是4,就表示用户态程序nginx进行读操作时访问的地址无效。在查找了大量资料之后,从
https://toontong.github.io/blog/nginx-gdb-coredump-segfault.html 这里找到了问题的所在原因。由于我们整站都是使用HTTPS,所以需要在nginx的ssl模块添加如下配置:
ssl_session_cache   shared:SSL:1024m;
ssl_session_timeout 10m;
重启nginx,完美过坑。


本文来自网易实践者社区,经作者齐红方授权发布。