给Nginx配置一个自签名的SSL证书

公司有一套系统在进行第三方评测的时候,要求要有https加密访问,而根据实际情况,去买一个CA证书是不太现实了,所以为了应付第三方公司的评测,这个时候弄个自签的CA证书就派上用场了,既能完美过评测,又能为公司省下一笔资金,简直就是美滋滋。。。

  HTTPS基础知识  

HTTPS(超文本传输安全),所谓HTTPS,其实就是HTTP和SSL/TLS的组合,用以提供加密通讯及对网络服务器的身份鉴定。HTTPS的主要思想是在不安全的网络上创建一安全信道,防止黑客的窃听和攻击。

SSL/TLS协议:

SSL: Secure Socket Layer(安全套接字层:由网景公司创建),通过一种机制在互联网上提供密钥传输。其主要目标是保证两个应用间通信数据的保密性和可靠性,可在服务器端和用户端同时支持的一种加密算法。目前主流版本SSLV2、SSLV3(常用)。

TLS:Transport Lanyer Security:由于网景公司的没落,IETF将SSL进行标准化,1999年公布了TLS标准文件。常用的版本:TLS v1(与SSL v3基本相同)

常见的加密技术

(1)单向加密:根据一定的运算规则对原数据进行某种形式的提取,这种提取就是“摘要”,也叫“特征码”,根据名称可以知道,单向加密仅支持从明文–>密文,而且还有一个很重要的特性,就是输入数据微小改变,将引起结果的巨大改变,这种现象称之为“雪崩效应

(2)对称加密:同时运用同一个密钥进行加密和解密(依赖于密钥来实现,算法是公开的);

(3)非对称加密:加密和解密所用的密钥不一样,它有一对密钥,称为“公钥”“私钥”,这一对密钥必须配对使用(即公钥加密的文件必须用相应的私钥才能解密,反之亦然)。

SSL/TLS的工作原理

SSL利用非对称密码技术进行数据加密。加密过程中使用到两个秘钥:一个公钥和一个与之对应的私钥。因此,如果在网络上传输的消息或数据流是被服务器的私钥加密的,则只能使用与其对应的公钥解密,从而可以保证客户端与服务器之间的数据安全。

OS网络5层协议

SSL的会话过程

SSL的会话过程

说明:前提服务器端在本地通过非对称加密算法生成一对密钥,并将公钥信息发送给CA证书颁发机构,CA给服务器端颁发数字证书,并将证书发送至服务器端。    

SSL会话建立过程:   

第一步:客户端向服务器端建立连接请求(TCP/IP);  

第二步:当TCP/IP建立完成后,客户端和服务器之间协商使用哪种加密算法,常用的如(TSLv1/SSLv2/SSLv3);   

第三步:协商完成后,服务器将公钥发送给客户端,客户端接收公钥信息;

第四步:客户端到CA证书颁发机构下载CA公钥信息,并对服务器端发送的证书做验证;    

第五步:随后,客户端在本地通过对称加密算法生成密钥,然后用服务器端发送的公钥进行对这段密钥进行加密,发送至服务器端,其保证了数据的机密性;    

第六步:服务器用自己的私钥对这段数据进行解密,得到密钥,然后将客户端的请求数据进行加密发送给客户端;

第七步:客户端接到响应,并用密钥进行机密,得到数据;

第八步:通信结束后,断开会话通道(TCP/IP) ; 

数字证书(Certificate)

在HTTPS的传输过程中,有一个非常关键的角色——数字证书,那什么是数字证书?又有什么作用呢?

所谓数字证书,是一种用于电脑的身份识别机制。由数字证书颁发机构(CA)对使用私钥创建的签名请求文件做的签名(盖章),表示CA结构对证书持有者的认可。

X.509证书包含三个文件:key,csr,crt。

key:是服务器上的私钥文件,用于对发送给客户端数据的加密,以及对从客户端接收到数据的解密

csr:是证书签名请求文件,用于提交给证书颁发机构(CA)对证书签名

crt:是由证书颁发机构(CA)签名后的证书,或者是开发者自签名的证书,包含证书持有人的信息,持有人的公钥,以及签署者的签名等信息

备注:在密码学中,X.509是一个标准,规范了公开秘钥认证、证书吊销列表、授权凭证、凭证路径验证算法等。

这里有两个概念,总是搞混淆了:自建CA自签证书

简单的说一下自己的理解

自建CA:就是自己搭建一个CA中心,自立为王的意思,在这个CA中心的范围内,你自己就有根CA证书,可以给其他人签署证书,可以吊销和管理证书文件,但是这个CA中心是你自己搭建的,没有得到互联网的承认,所以不具备通用和有效性,一般就是一些企业或者公司内部网络通用。

自签证书:一般而言,我们的证书是要发给权威机构CA进行验证签署的,但是自签证书,就是自己给自己签署证书,自己生成一份CA证书,同样的道理,自签的证书,不具备互联网的通用和有效性,只有内部网络或者测试使用。

我们这里举一个例子进行说明,具体的流程如下:

有两台服务器,一台做CA服务器,一台做web服务器

我们首先要搭建CA中心,这样才可以对证书请求文件进行签名,然后生成证书文件。而自建CA中心的服务器,我们称呼为CA服务器,自建CA的流程是,首先生成CA中心的密钥文件,然后自签生成CA自己的根CA证书,注意,这里的密钥文件是CA中心的密钥文件,这里的证书是CA中心的根证书文件。

CA中心搭建成功,我们就可以对其他证书请求文件进行签署生成证书,比如有一台web服务器,这台服务器要实现https访问,那么这台web服务器就生成密钥文件(key),再由密钥文件生成web服务器的证书签署请求文件(csr),把csr发给我们指自建的CA中心进行签署,签署后的证书(crt)发给web服务器,web服务器利用key和crt就可以实现https了。

上面的例子中,有两个密钥和两个证书文件,一份是CA中心自己的,一份是web服务器的,同样的,有两次自签证书的操作,一次是搭建CA中心的时候,给根CA证书自签,而一次是给web服务器的证书文件进行签名,我们也叫自签,就是这两次自签容易混淆。

当然,为了简化过程,我们配置一个自签的SSL证书,也未必需要一定自建CA中心后才可以进行签署证书,也可以直接对web服务器的证书签署请求文件进行自签,直接生成证书文件。这种简化方式生成的证书文件的签署者信息就只能默认,而自己CA中心进行签署的证书,则可用自定义的签署者信息。

  创建自签名证书  

下面是简化的创建自签名证书流程,需要安装openssl,使用以下步骤:

  1. 创建Key;

  2. 创建签名请求;

  3. 将Key的口令移除;

  4. 用Key签名证书。

第1步:生成私钥

使用openssl工具生成一个RSA私钥

[root@JYZX ssl]#openssl genrsa -des3 -out server.key 1024

参数说明:生成rsa私钥,des3算法,1024位强度,server.key是秘钥文件名。

注意:生成私钥,需要提供一个至少4位的密码。

创建秘钥文件

第2步:生成CSR(证书签名请求)

利用上面创建的秘钥文件,就可以生成csr(证书签署请求文件)

[root@JYZX ssl]#openssl req -new -key server.key -out server.csr

创建证书签署请求文件

说明:需要依次输入秘钥密码,国家,地区,城市,组织,组织单位,Common Name和Email。
其中Common Name,可以写自己的名字或者域名,如果要支持https,Common Name应该与域名保持一致,否则会引起浏览器警告

生成证书签署请求文件之后,就可以进行证书签名了,而这个时候可以有两种选择。
第一种,就是你把这个CSR文件,发送给权威的CA机构,由他们进行验证和正式签名,这种方式签名后的证书就是得到权威机构进行验证的,具备有效性,效果就是所有客户端的浏览器都能认可你的证书,但是这种方式是收费的。

第二种,自建CA,自签证书,意思就是自己给自己签署证明,很显然,这种方式的签署证书,就不能得到权威验证,无法具备公认的有效性,所以如果客户端访问,会显示证书无效,或者不安全之类的,这种方式是免费的,一般内部测试或者使用的话,用这种方式就可以了。

第3步:删除私钥中的密码

在第1步创建私钥的过程中,由于必须要指定一个密码。而这个密码会带来一个副作用,那就是在每次Apache启动Web服务器时,都会要求输入密码,这显然非常不方便。要删除私钥中的密码,操作如下:

[root@JYZX ssl]#openssl rsa -in server.key.org -out server.key

第4步:生成自签名证书

[root@JYZX ssl]#openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

自签证书信息

说明:crt上有证书持有人的信息,持有人的公钥,以及签署者的签名等信息。当用户安装了证书之后,便意味着信任了这份证书,同时拥有了其中的公钥。

  给Nginx配置SSL证书  

有了已经签署的证书文件之后,实现https就非常简单了,我们这里用nginx演示如何配置ssl证书,以实现https的访问。

第1步:创建证书存放目录

[root@JYZX ssl]#mkidr /usr/local/nginx/conf/ssl

第2步:把上面创建的秘钥文件和证书文件放置ssl目录

秘钥和证书文件

第3步:配置nginx.conf文件

server {
    ...
    listen 443 default ssl;
    ssl_certificate     /usr/local/nginx/conf/ssl/server.crt;
    ssl_certificate_key /usr/local/nginx/conf/ssl/server.key;
    server_name www.xjimmy.com;
}

配置SSL证书

Web服务器需要把server.crt发给浏览器验证,然后用server.key解密浏览器发送的数据

第4步:重载nginx让配置生效

[root@JYZX ssl]#/usr/local/nginx/sbin/nginx -s reload

如果一切顺利,打开浏览器,就可以通过HTTPS访问网站。

第一次访问时会出现警告(因为我们的自签名证书不被浏览器信任),我们可以手动把证书通过浏览器导入到系统并设置为“受信任”,以后该电脑访问网站就可以安全地连接Web服务器了:

  问题点解决  

配置完成后,浏览器访问https://xxxxx,总是出现如下错误

一开始以为是自签证书那里出了问题,因为我实际应用的时候,不是用域名配置https的,而是用IP地址,但是经过请教之后,确认ip地址也是支持https的。

异常报错信息

网上搜索错误关键字:“The plain HTTP request was sent to HTTPS port”

得到的反馈信息是,因为每一次客户试图通过HTTP访问你的网站,这个请求被重定向到HTTPS。于是Nginx预计使用SSL交互,但原来的请求(通过端口80接收)是普通的HTTP请求,于是会产生错误。

按照上面这段的理解,应该是nginx配置文件配置错误了,导致http和https互相交互产生的错误,后面查了一下nginx的配置文件,发现确实是之前的一段配置信息,用http进行重定位了,如下图:

nginx配置信息

从上面这段配置信息可知,我们用https访问首页的时候,会被方向代理到http页面,导致https和http进行交互了

所以这里也需要改成https进行方向代理即可

nginx配置信息

  总结  

1. 以一张图来总结https会话流程

(该图片来源于小小忍者的博文:http://xxrenzhe.blog.51cto.com/4036116/1370114

https会话流程

2. 利用shell脚本实现一键创建自签CA证书

证书来源于廖雪峰大神的站点,从这里下载脚本:https://github.com/michaelliao/itranswarp.js/blob/master/conf/ssl/gencert.sh

脚本内容:

#!/bin/sh
# create self-signed server certificate:
read -p "Enter your domain [www.example.com]: " DOMAIN
echo "Create server key..."
openssl genrsa -des3 -out $DOMAIN.key 1024
echo "Create server certificate signing request..."
SUBJECT="/C=US/ST=Mars/L=iTranswarp/O=iTranswarp/OU=iTranswarp/CN=$DOMAIN"
openssl req -new -subj $SUBJECT -key $DOMAIN.key -out $DOMAIN.csr
echo "Remove password..."
mv $DOMAIN.key $DOMAIN.origin.key
openssl rsa -in $DOMAIN.origin.key -out $DOMAIN.key
echo "Sign SSL certificate..."
openssl x509 -req -days 3650 -in $DOMAIN.csr -signkey $DOMAIN.key -out $DOMAIN.crt
echo "TODO:"
echo "Copy $DOMAIN.crt to /etc/nginx/ssl/$DOMAIN.crt"
echo "Copy $DOMAIN.key to /etc/nginx/ssl/$DOMAIN.key"
echo "Add configuration in nginx:"
echo "server {"
echo "    ..."
echo "    listen 443 ssl;"
echo "    ssl_certificate     /etc/nginx/ssl/$DOMAIN.crt;"
echo "    ssl_certificate_key /etc/nginx/ssl/$DOMAIN.key;"
echo "}"

运行脚本,假设你的域名是www.test.com,那么按照提示输入:

$ ./gencert.sh
Enter your domain [www.example.com]: www.test.com
Create server key...
Generating RSA private key, 1024 bit long modulus
.................++++++
.....++++++
e is 65537 (0x10001)
Enter pass phrase for www.test.com.key:输入口令
Verifying - Enter pass phrase for www.test.com.key:输入口令
Create server certificate signing request...
Enter pass phrase for www.test.com.key:输入口令
Remove password...
Enter pass phrase for www.test.com.origin.key:输入口令
writing RSA key
Sign SSL certificate...
Signature ok
subject=/C=US/ST=Mars/L=iTranswarp/O=iTranswarp/OU=iTranswarp/CN=www.test.com
Getting Private key
TODO:
Copy www.test.com.crt to /etc/nginx/ssl/www.test.com.crt
Copy www.test.com.key to /etc/nginx/ssl/www.test.com.key
Add configuration in nginx:
server {
    ...
    ssl on;
    ssl_certificate     /etc/nginx/ssl/www.test.com.crt;
    ssl_certificate_key /etc/nginx/ssl/www.test.com.key;
}

注意4次输入的口令都是一样的。

在当前目录下会创建出4个文件:

  • www.test.com.crt:自签名的证书

  • www.test.com.csr:证书的请求

  • www.test.com.key:不带口令的Key

  • www.test.com.origin.key:带口令的Key

Web服务器需要把www.test.com.crt发给浏览器验证,然后用www.test.com.key解密浏览器发送的数据,剩下两个文件不需要上传到Web服务器上。

3. 学习https的优秀站点

在学习https及nginx配置ssl的过程中,看到了很多非常优秀的文章,下面贴出来分享给大家:

图解openssl实现私有CA

Linux运维之加密/解密原理、自建CA及搭建基于https的Apache

如何创建一个自签名的SSL证书(X509)

给Nginx配置一个自签名的SSL证书

Jimmy's Blog ,版权所有丨如未注明,均为原创丨本网站采用BY-NC-SA协议进行授权,转载请注明转自:https://www.xjimmy.com/nginx_ssl.html

Leave a Comment