HTTPS 理论
1.对HTTPS 原理
前面已经讲过,不在赘述: HTTPS原文链接http://blog.youkuaiyun.com/yuanmengong886/article/details/54618351
2. 数字证书
是一种用于电脑的身份识别机制。由数字证书颁发机构(CA)对使用私钥创建的签名请求文件做的签名(盖章),表示CA结构对证书持有者的认可。
证书优点:
1 使用数字证书能够提高用户的可信度
2 数字证书中的公钥,能够与服务端的私钥配对使用,实现数据传输过程中的加密和解密
3 在证认使用者身份期间,使用者的敏感个人数据并不会被传输至证书持有者的网络系统上
X.509 证书
X.509证书包含三个文件:key,csr,crt。
• key是服务器上的私钥文件,用于对发送给客户端数据的加密,以及对从客户端接收到数据的解密
• csr是证书签名请求文件,用于提交给证书颁发机构(CA)对证书签名
• crt是由证书颁发机构(CA)签名后的证书,或者是开发者自签名的证书,包含证书持有人的信息,持有人的公钥,以及签署者的签名等信息
备注:在密码学中,X.509是一个标准,规范了公开秘钥认证、证书吊销列表、授权凭证、凭证路径验证算法等。
3.CA证书验证流程:
HTTPS 实践
单项认证
第一步:为服务器端准备公钥、私钥
# 生成服务器端私钥
openssl genrsa -out server.key 1024
# 生成服务器端公钥
openssl rsa -in server.key -pubout -out server.pem
第二步:生成 CSR(证书请求文件)
# 生成 CSR(Certificate Secure Request)
openssl req -new -key server.key -out server.csr
生成内容如下
➜ keys openssl req -new -key ca.key -out ca.csr
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) [AU]:CN
State or Province Name (full name) [Some-State]:Zhejiang
Locality Name (eg, city) []:Hangzhou
Organization Name (eg, company) [Internet Widgits Pty Ltd]:My CA
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:localhost
Email Address []:
注意:
1.上面的Common name可以是域名(IP),或者名字
当是生成服务器端的证书请求文件: commmon name要和自己的网站域名一致
当是生成客户端的证书请求文件时,写成自己的名字或者域名都行
2.这里的 Organization Name (eg, company) [Internet Widgits Pty Ltd]: 后面生成客户端和服务器端证书的时候也需要填写,不要写成一样的!!!可以随意写如:My CA, My Server, My Client
第三步:生成CA证书
1).使用自己的私钥作为CA进行自签名
# server.key 作为CA的私钥进行CA签名
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
2).使用不受操作系统提高的CA机构信任的CA机构进行CA签名
1. 生成CA证书
# 生成 CA 私钥
openssl genrsa -out ca.key 1024
# X.509 Certificate Signing Request (CSR) Management.
openssl req -new -key ca.key -out ca.csr
# X.509 Certificate Data Management. CA机构向上一级CA机构签名提供证书请求文件.csr和 上一级机构的私钥 .key文件生成 签名证书.crt
openssl x509 -req -in ca.csr -signkey ca.key -out ca.crt
2. CA机构 使用自己的 上级机构生成的证书 ca.crt和 自己的私钥 ca.key对证书请求文件进行签名
# 向自己的 CA 机构申请证书,签名过程需要 CA 的证书和私钥参与,最终颁发一个带有 CA 签名的证书
openssl x509 -req -CA ca.crt -CAkey ca.key -CAcreateserial -in server.csr -out server.crt
此时,我们的keys文件夹目录如下
├── https-server.js
└── keys
├── ca.crt
├── ca.csr
├── ca.key
├── ca.pem
├── ca.srl
├── server.crt
├── server.csr
├── server.key
└── server.pem
3). 将证书签名文件 server.csr 交给CA机构进行CA签名,步奏和上面第二种方案一样,唯一区别是ca.crt和ca.key是正式的CA机构的
HTTPS单项认证服务器端测试代码:
// file http-server.js
var https = require('https');
var fs = require('fs');
var options = {
key: fs.readFileSync('./keys/server.key'),
cert: fs.readFileSync('./keys/server.crt')
};
https.createServer(options, function(req, res) {
res.writeHead(200);
res.end('hello world');
}).listen(8000);
HTTPS单线认证缺点:
容易遭受第三方( 中间人)攻击例如:
1. 使用代理作为中间人进行抓包截取数据
2. curl -k https://localhost:8000 可以获取服务器的数据
双向认证
单项认证只有客户端对服务器端的认证,没有服务器端对客户端的认证
双向认证不仅需要服务器对客户端身份的认证,也需要客户端对服务器端身份的认证
第一步:为服务器端和客户端准备公钥、私钥
# 生成服务器端私钥
openssl genrsa -out server.key 1024
# 生成服务器端公钥
openssl rsa -in server.key -pubout -out server.pem
# 生成客户端私钥
openssl genrsa -out client.key 1024
# 生成客户端公钥
openssl rsa -in client.key -pubout -out client.pem
第二步:生成 CSR(证书请求文件)
# 服务器生成 CSR(Certificate Secure Request)
openssl req -new -key server.key -out server.csr
# client 端
openssl req -new -key client.key -out client.csr
第三步:生成CA证书
利于前面已生成的CA 机构的 私钥和签名证书对 服务端和客户端的 证书请求文件进行签名
# 向自己的 CA 机构申请证书,签名过程需要 CA 的证书和私钥参与,最终颁发一个带有 CA 签名的证书
openssl x509 -req -CA ca.crt -CAkey ca.key -CAcreateserial -in server.csr -out server.crt
# client 端到 CA 签名
openssl x509 -req -CA ca.crt -CAkey ca.key -CAcreateserial -in client.csr -out client.crt
此时,我们的 keys 文件夹下已经有如下内容了
├── https-client.js
├── https-server.js
└── keys
├── ca.crt
├── ca.csr
├── ca.key
├── ca.pem
├── ca.srl
├── client.crt
├── client.csr
├── client.key
├── client.pem
├── server.crt
├── server.csr
├── server.key
└── server.pem
HTTPS双项认证服务器端测试代码和单项认证一样,客户端代码如下:
// file http-client.js
var https = require('https');
var fs = require('fs');
var options = {
hostname: "localhost",
port: 8000,
path: '/',
methed: 'GET',
key: fs.readFileSync('./keys/client.key'),
cert: fs.readFileSync('./keys/client.crt'),
ca: [fs.readFileSync('./keys/ca.crt')]
};
options.agent = new https.Agent(options);
var req = https.request(options, function(res) {
res.setEncoding('utf-8');
res.on('data', function(d) {
console.log(d);
});
});
req.end();
req.on('error', function(e) {
console.log(e);
});
先打开服务器 node http-server.js,然后执行
node https-client.js
hello world
遇见的问题保存: 'DEPTH_ZERO_SELF_SIGNED_CERT'
由于HTTPS服务器会对客户端的证书进行验证,而客户端的证书是自签的证书,不是CA机构办法的,固然操作系统的根证书验证通不过
需要将rejectUnauthorized:false 告诉服务器不要进行根证书列表的验证
同时将ca: [fs.readFileSync('./keys/ca.crt')], 以保证数据双向传输的安全