如何为HTTPS Node.js服务器使用自签名证书?

我已经开始编写API的包装器,要求所有请求都通过HTTPS。 而不是在开发和testing时向实际的API发出请求,我想在本地运行我自己的服务器来模拟响应。

我很困惑如何生成我需要创build一个HTTPS服务器和发送请求的证书。

我的服务器看起来像这样:

var options = { key: fs.readFileSync('./key.pem'), cert: fs.readFileSync('./cert.pem') }; https.createServer(options, function(req, res) { res.writeHead(200); res.end('OK\n'); }).listen(8000); 

pem文件是通过以下方式生成的:

 openssl genrsa 1024 > key.pem openssl req -x509 -new -key key.pem > cert.pem 

一个请求看起来像这样:

 var options = { host: 'localhost', port: 8000, path: '/api/v1/test' }; https.request(options, function(res) { res.pipe(process.stdout); }).end(); 

有了这个设置,我得到Error: DEPTH_ZERO_SELF_SIGNED_CERT ,所以我想我需要为请求添加一个ca选项。

所以我的问题是我应该如何产生以下内容:

  1. 服务器key
  2. 服务器cert
  3. 请求的ca

我已经阅读了一些关于使用openssl生成自签名证书的事情,但似乎无法绕过它,并找出哪些密钥和证书在我的节点代码中使用。

更新

API提供了一个CA证书来代替默认值。 下面的代码使用他们的证书,这是我想要在本地重现。

 var ca = fs.readFileSync('./certificate.pem'); var options = { host: 'example.com', path: '/api/v1/test', ca: ca }; options.agent = new https.Agent(options); https.request(options, function(res) { res.pipe(process.stdout); }).end(); 

截屏

https://coolaj86.com/articles/how-to-create-a-csr-for-https-tls-ssl-rsa-pems/

完整,工作示例

  • 创build证书
  • 运行node.js服务器
  • 在node.js客户端中没有警告或错误
  • 没有警告或cURL错误

https://github.com/coolaj86/nodejs-self-signed-certificate-example

localhost.daplie.com为例(它指向127.0.0.1):

server.js

 'use strict'; var https = require('https') , port = process.argv[2] || 8043 , fs = require('fs') , path = require('path') , server , options ; require('ssl-root-cas') .inject() .addFile(path.join(__dirname, 'server', 'my-private-root-ca.cert.pem')) ; options = { key: fs.readFileSync(path.join(__dirname, 'server', 'privkey.pem')) // You don't need to specify `ca`, it's done by `ssl-root-cas` //, ca: [ fs.readFileSync(path.join(__dirname, 'server', 'my-private-root-ca.cert.pem'))] , cert: fs.readFileSync(path.join(__dirname, 'server', 'fullchain.pem')) }; function app(req, res) { res.setHeader('Content-Type', 'text/plain'); res.end('Hello, encrypted world!'); } server = https.createServer(options, app).listen(port, function () { port = server.address().port; console.log('Listening on https://127.0.0.1:' + port); console.log('Listening on https://' + server.address().address + ':' + port); console.log('Listening on https://localhost.daplie.com:' + port); }); 

client.js

 'use strict'; var https = require('https') , fs = require('fs') , path = require('path') , ca = fs.readFileSync(path.join(__dirname, 'client', 'my-private-root-ca.cert.pem')) , port = process.argv[2] || 8043 , hostname = process.argv[3] || 'localhost.daplie.com' ; var options = { host: hostname , port: port , path: '/' , ca: ca }; options.agent = new https.Agent(options); https.request(options, function(res) { res.pipe(process.stdout); }).end(); 

和使证书文件的脚本:

make-certs.sh

 #!/bin/bash FQDN=$1 # make directories to work from mkdir -p server/ client/ all/ # Create your very own Root Certificate Authority openssl genrsa \ -out all/my-private-root-ca.privkey.pem \ 2048 # Self-sign your Root Certificate Authority # Since this is private, the details can be as bogus as you like openssl req \ -x509 \ -new \ -nodes \ -key all/my-private-root-ca.privkey.pem \ -days 1024 \ -out all/my-private-root-ca.cert.pem \ -subj "/C=US/ST=Utah/L=Provo/O=ACME Signing Authority Inc/CN=example.com" # Create a Device Certificate for each domain, # such as example.com, *.example.com, awesome.example.com # NOTE: You MUST match CN to the domain name or ip address you want to use openssl genrsa \ -out all/privkey.pem \ 2048 # Create a request from your Device, which your Root CA will sign openssl req -new \ -key all/privkey.pem \ -out all/csr.pem \ -subj "/C=US/ST=Utah/L=Provo/O=ACME Tech Inc/CN=${FQDN}" # Sign the request from Device with your Root CA openssl x509 \ -req -in all/csr.pem \ -CA all/my-private-root-ca.cert.pem \ -CAkey all/my-private-root-ca.privkey.pem \ -CAcreateserial \ -out all/cert.pem \ -days 500 # Put things in their proper place rsync -a all/{privkey,cert}.pem server/ cat all/cert.pem > server/fullchain.pem # we have no intermediates in this case rsync -a all/my-private-root-ca.cert.pem server/ rsync -a all/my-private-root-ca.cert.pem client/ # create DER format crt for iOS Mobile Safari, etc openssl x509 -outform der -in all/my-private-root-ca.cert.pem -out client/my-private-root-ca.crt 

例如:

 bash make-certs.sh 'localhost.daplie.com' 

希望这个钉在这个棺材上。

还有一些解释: https : //github.com/coolaj86/node-ssl-root-cas/wiki/Painless-Self-Signed-Certificates-in-node.js

在iOS Mobile Safari上安装私人证书

您需要创build具有.crt扩展名的DER格式的根CA证书副本:

 # create DER format crt for iOS Mobile Safari, etc openssl x509 -outform der -in all/my-private-root-ca.cert.pem -out client/my-private-root-ca.crt 

然后,您可以简单地与您的networking服务器提供该文件。 当你点击链接时,应该询问你是否要安装证书。

有关如何工作的示例,您可以尝试安装MIT的证书颁发机构: https : //ca.mit.edu/mitca.crt

相关的例子

尝试将其添加到您的请求选项

 var options = { host: 'localhost', port: 8000, path: '/api/v1/test', // These next three lines rejectUnauthorized: false, requestCert: true, agent: false }; 

你的关键一代看起来不错。 你不应该需要一个ca,因为你不拒绝未签名的请求。

将.toString()添加到readFileSync方法的末尾,以便实际传递一个string,而不是文件对象。

尝试添加代理:false,rejectUnauthorized:false

此过程允许您创build证书颁发机构和证书:

  1. 抓住这个ca.cnf文件作为configuration快捷键:

    wget https://raw.githubusercontent.com/anders94/https-authorized-clients/master/keys/ca.cnf


  1. 使用此configuration创build一个新的证书颁发机构:

    openssl req -new -x509 -days 9999 -config ca.cnf -keyout ca-key.pem -out ca-cert.pem


  1. 现在我们在ca-key.pemca-cert.pem拥有我们的authentication权限,我们来为服务器生成一个私钥:

    openssl genrsa -out key.pem 4096


  1. 抓住这个server.cnf文件作为configuration快捷方式:

    wget https://raw.githubusercontent.com/anders94/https-authorized-clients/master/keys/server.cnf


  1. 使用此configuration生成证书签名请求:

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


  1. 签署请求:

    openssl x509 -req -extfile server.cnf -days 999 -passin "pass:password" -in csr.pem -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -out cert.pem

我在这里find了这个过程,以及有关如何使用这些证书的更多信息。