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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19665863/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 16:07:31  来源:igfitidea点击:

How do I use a self signed certificate for a HTTPS Node.js server?

node.jssslhttps

提问by Brett

I have started writing a wrapper for an API which requires all requests to be over HTTPS. Instead of making requests to the actual API while I am developing and testing it I would like to run my own server locally which mocks the responses.

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

I am confused about how to generate the certificates I need to create a HTTPS server and send requests to it.

我对如何生成创建 HTTPS 服务器并向其发送请求所需的证书感到困惑。

My server looks something like this:

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

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);

The pem files were generated with:

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

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

And a request looks something like this:

一个请求看起来像这样:

var options = {
  host: 'localhost',
  port: 8000,
  path: '/api/v1/test'
};

https.request(options, function(res) {
  res.pipe(process.stdout);
}).end();

With this setup I get Error: DEPTH_ZERO_SELF_SIGNED_CERT, so I think I need to add a caoption for the request.

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

So my question is how should I generate the following:

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

  1. The server key?
  2. The server cert?
  3. The cafor the request?
  1. 服务器key
  2. 服务器cert
  3. ca为请求?

I have read a few things about generating self signed certificates with openssl, but can't seem to wrap my head around it and figure out which keys and certificates to use where in my node code.

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

Update

更新

The API provides a CA certificate to use instead of the defaults. The following code works using their certificate and this is what I want to reproduce locally.

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();

回答by CoolAJ86

Update (Nov 2018): Do you needself-signed certs?

更新(2018 年 11 月):您需要自签名证书吗?

Or would real certificates get the job done better? Have you considered any of these?

或者真正的证书会让工作做得更好?你考虑过这些吗?

(Note: Let's Encrypt can also issue certificates to private networks)

(注:Let's Encrypt 也可以向私有网络颁发证书)

ScreenCast

投屏

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

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

Full, Working example

完整的工作示例

  • creates certificates
  • runs node.js server
  • no warnings or errors in node.js client
  • no warnings or errors in cURL
  • 创建证书
  • 运行 node.js 服务器
  • node.js 客户端中没有警告或错误
  • cURL 中没有警告或错误

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

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

Using localhost.greenlock.domainsas an example (it points to 127.0.0.1):

使用localhost.greenlock.domains作为一个例子(它指向127.0.0.1):

server.js

服务器.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 = {
  // this is ONLY the PRIVATE KEY
  key: fs.readFileSync(path.join(__dirname, 'server', 'privkey.pem'))
  // You DO NOT specify `ca`, that's only for peer authentication
//, ca: [ fs.readFileSync(path.join(__dirname, 'server', 'my-private-root-ca.cert.pem'))]
  // This should contain both cert.pem AND chain.pem (in that order) 
, 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.greenlock.domains:' + port);
});

client.js

客户端.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.greenlock.domains'
  ;

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();

And the script that makes the certificate files:

以及制作证书文件的脚本:

make-certs.sh

make-certs.sh

#!/bin/bash
FQDN=

# 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

For example:

例如:

bash make-certs.sh 'localhost.greenlock.domains'

Hopefully this puts the nail in the coffin on this one.

希望这能把钉子钉在棺材上。

And some more explanation: https://github.com/coolaj86/node-ssl-root-cas/wiki/Painless-Self-Signed-Certificates-in-node.js

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

Install private cert on iOS Mobile Safari

在 iOS Mobile Safari 上安装私有证书

You need to create a copy of the root ca certificate a DER format with a .crt extension:

您需要创建一个带有 .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

Then you can simply serve that file with your webserver. When you click the link you should be asked if you want to install the certificate.

然后您可以简单地使用您的网络服务器提供该文件。当您单击该链接时,系统会询问您是否要安装证书。

For an example of how this works you can try installing MIT's Certificate Authority: https://ca.mit.edu/mitca.crt

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

Related Examples

相关例子

回答by Loourr

Try adding this to your request options

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

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

回答by user1570577

Try adding

尝试添加

  agent: false,
  rejectUnauthorized: false

回答by binderbound

Your key generation looks okay. You shouldn't need a ca because you aren't rejecting unsigned requests.

您的密钥生成看起来不错。您不应该需要 ca,因为您不会拒绝未签名的请求。

Add .toString() to the end of your readFileSync methods so that you are actually passing a string, not a file object.

将 .toString() 添加到 readFileSync 方法的末尾,以便您实际上传递的是字符串,而不是文件对象。

回答by John Slegers

This procedure allows you to create both a certificate authority & a certificate :

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

  1. grab this ca.cnffile to use as a configuration shortcut :

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

  1. 获取此ca.cnf文件以用作配置快捷方式:

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



  1. create a new certificate authority using this configuration :

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

  1. 使用此配置创建一个新的证书颁发机构:

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



  1. now that we have our certificate authority in ca-key.pemand ca-cert.pem, let's generate a private key for the server :

    openssl genrsa -out key.pem 4096

  1. 现在我们在ca-key.pemand 中拥有我们的证书颁发机构ca-cert.pem,让我们为服务器生成一个私钥:

    openssl genrsa -out key.pem 4096



  1. grab this server.cnffile to use as a configuration shortcut :

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

  1. 获取此server.cnf文件以用作配置快捷方式:

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



  1. generate the certificate signing request using this configuration :

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

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

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



  1. sign the request :

    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

  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

I found this procedure here, along with more information on how to use these certificates.

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