使用绑定ip的自签名证书部署https

随着对安全的重视和几大公司的推动,https服务已经成为标配了。出于成本和其他因素的考量,最近需要对后台服务升级到https连接。通常证书的创建需要一个域名,但实际上可以无需域名而绑定ip地址。通过搜索和尝试,搞定:

  1. 创建CA,签署绑定到ip的服务器证书

我的操作环境是OS X 10.13.6。

创建CA(Certificate Authority)

创建私钥:这里生成长度1024的,你也可以生成更长的;密码要牢记,下面的处理过程中,不止一次会用到

openssl genrsa -out ca-key.pem -des 1024

通过CA私钥生成CSR

openssl req -new -key ca-key.pem -out ca-csr.pem

通过CSR文件和私钥生成CA证书

openssl x509 -req -in ca-csr.pem -signkey ca-key.pem -out ca-cert.pem

服务端证书

为服务器生成私钥

openssl genrsa -out server-key.pem 1024

利用服务器私钥文件服务器生成CSR,其中openssl.cnf格式如下:

openssl req -new -key server-key.pem -config openssl.cnf -out server-csr.pem

openssl.cnf文件示例:

[req]
distinguished_name = req_distinguished_name
req_extensions = v3_req

[req_distinguished_name]
countryName = Country Name (2 letter code)
countryName_default = CN
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = JS
localityName = Locality Name (eg, city)
localityName_default = WX
organizationalUnitName = Organizational Unit Name (eg, section)
organizationalUnitName_default = MyCA
commonName = ee ltd
commonName_max = 64

[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names

[alt_names]
IP.1 = 127.0.0.1

这一步的确非常重要,我在csdn看到的blog中也提到了添加v3_req,并且在 alt_names下添加了DNS和IP的记录,都没有成功。 注意这里只添加了IP。

通过服务器私钥文件和CSR文件生成服务器证书

openssl x509 -req -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -in server-csr.pem -out server-cert.pem -extensions v3_req -extfile openssl.cnf

客户端证书

生成客户端私钥

openssl genrsa -out client-key.pem

利用私钥生成CSR

openssl req -new -key client-key.pem -out client-csr.pem

这一步中,Common Name之类的可以随意填。

生成客户端证书

openssl x509 -req -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -in client-csr.pem -out client-cert.pem

测试

为了方便,可以将证书和私钥打包成pfx格式。 打包服务器端证书

openssl pkcs12 -export -in server-cert.pem -inkey server-key.pem -certfile ca-cert.pem -out server.pfx

打包客户端证书

openssl pkcs12 -export -in client-cert.pem -inkey client-key.pem -certfile ca-cert.pem -out client.pfx

测试

先修改服务端,服务端使用的Express,在www中修改:

var cnodeOptions = {
    //key: fs.readFileSync('./bin/server-key.pem'),
    //ca: [fs.readFileSync('./bin/ca-cert.pem')],
    //cert: fs.readFileSync('./bin/server-cert.pem'),
    pfx:fs.readFileSync('./bin/server.pfx'),
    passphrase:'生成pfx时所用的密码',

}; 注意:如果不使用pfx的话,就把pfx和passphrase行注释。

然后修改客户端:

var https = require('https');
var fs = require('fs');
var options = {
  hostname: "127.0.0.1",
  port: 3000,
  path: '/https',//'/',
  methed: 'GET',
  pfx:fs.readFileSync('./client.pfx'),
  passphrase:'生成pfx时所用的密码',
  agent: false
};
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);
});

启动服务端,运行客户端,如果能正常请求,就说明证书确认成功了。
在实际开发过程中,我们可以给options添加属性,使得开发过程中对证书不做校验:

rejectUnauthorized: false

或者:

checkServerIdentity: function (host, cert) {
  return undefined;
}

但切记不要在生成环境也这么做!

参考说明

在搜索过程中,参考了csdn,cnblog的多篇文章,但对我最有用的还是用Node.js创建自签名的HTTPS服务器。 看来关键字还是得和工作内容相联系,才能找到有用的信息。

名词解释

CA: Certificate Authority CSR: Certificate Signing Request