为本地主机创建一个可信的自签名SSL证书(用于Express/Node)

194

尝试遵循各种关于创建用于localhost的自签名证书的说明,大多数说明似乎是针对IIS的,但我正在尝试使用Nodejs/Express。由于证书未受信任,所以它们没有正常工作。以下是我尝试失败的内容:

有人能提供一个可以执行此操作的流程吗?我可以安装证书,但是我无法使证书在Chrome(v32)或IE(v10)中受信任。

编辑:在评论中建议问题是没有可信的证书根。我通过IE安装了证书,但它仍然没有得到信任。


没有自签名证书可以被信任用于Web浏览器。它们没有由受信任的签名机构签署。 - user1741851
1
这并不正确:你可以安装根证书来获取你的自签名证书的信任。然而,我似乎做不好这个。我读到可以在IE中安装证书链(不能在Chrome中),所以我尝试了一下,但还是没有被识别。我不知道是因为localhost特殊还是自签名证书不正确。 - JasonS
3
我从未成功在Chrome等浏览器上使用自签名证书。这是我的解决方法:我为local.MYDOMAIN.com创建了一个DNS条目,指向127.0.0.1(本地主机),然后只需使用我的生产证书即可。这样做的附加好处是确保您的生产证书链等方面没有问题。 - JasonS
18个回答

175

以上答案仅部分正确。我花了很多时间让它工作,真是疯狂。提醒未来的自己,以下是需要做的:

我正在使用 Windows 10 和 Chrome 65,Firefox 表现良好 - 只需确认 localhost 为安全例外即可工作。但是 Chrome 不行:

步骤1。 在您的后端中创建一个名为 security 的文件夹。我们将在其中工作。

步骤2。 创建一个名为 req.cnf 的请求配置文件,其内容如下(鸣谢:@Anshul

req.cnf :

[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_req
prompt = no
[req_distinguished_name]
C = Country initials like US, RO, GE
ST = State
L = Location
O = Organization Name
OU = Organizational Unit 
CN = www.localhost.com
[v3_req]
keyUsage = critical, digitalSignature, keyAgreement
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = www.localhost.com
DNS.2 = localhost.com
DNS.3 = localhost

这个字段的解释在这里

步骤 3。在终端中导航到安全文件夹并输入以下命令:

openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout cert.key -out cert.pem -config req.cnf -sha256

步骤 4。然后在 security 文件夹之外,在您的 express 应用程序中执行以下操作:(感谢 @Diego Mello)

backend 
 /security
 /server.js

server.js:

const express = require('express')
const app = express()
const https = require('https')
const fs = require('fs')
const port = 3000

app.get('/', (req, res) => {
    res.send("IT'S WORKING!")
})

const httpsOptions = {
    key: fs.readFileSync('./security/cert.key'),
    cert: fs.readFileSync('./security/cert.pem')
}
const server = https.createServer(httpsOptions, app)
    .listen(port, () => {
        console.log('server running at ' + port)
    })

步骤5。 启动服务器,node server.js,然后转到https://localhost:3000

此时我们已经设置好了服务器。但浏览器应会显示警告消息。

我们需要将自签名证书注册为受信任的 CA 证书颁发机构,并存储在 chrome/windows 证书存储中。(Chrome 还会将其保存在 Windows 中)

步骤6。 在 Chrome 中打开 Dev Tools,进入 Security 面板,然后单击 View Certificate。 enter image description here

步骤7。 进入详细信息面板,单击“复制文件”,然后出现证书导出向导时,按以下方式单击下一步:

go to details - copy file - next on export wizard

步骤8。 保留 DER 编码,单击下一步,选择Browse,将其放置在易于访问的文件夹(如桌面)中,并将证书命名为localhost.cer,然后单击保存,再单击完成。您应该能够在桌面上看到您的证书。

步骤9。 通过在 URL 箱中插入它来打开chrome://settings/。向下滚动,然后单击“高级/高级选项”,查找“管理证书”。

choose manage certificates

步骤10。 进入受信任的根证书颁发机构面板,然后单击导入。

Go to Trusted Root Certification Authorities panel, and click import

我们将导入刚刚在步骤8中导出的localhost.cer证书。

步骤11。 单击浏览,找到localhost.cer,保留默认值,单击下一步多次直到出现此警告,然后单击是。

confirm security exception

步骤12。 关闭所有内容,并重新启动 Chrome。然后,当转到https://localhost:3000时,您应该会看到: gotta love the green


1
如果您正在为网络上的地址执行此操作,我发现将证书DNS设置为主机名,例如:DNS.1 = server.local 然后在连接的计算机上更新HOSTS文件以将服务器IP地址指向主机名,例如:192.168.0.50 server.local 这将允许证书和地址匹配并验证证书。 - roskelld
@Alon,不清楚req.cnf中哪些字段需要更改。 - TKoL
1
我找到了一个部分答案来回答自己的问题:如果你把CN和DNS.1改成类似于“local.com”的东西,并且在每台需要访问服务器的计算机上,更改etc/hosts文件将local.com指向服务器的IP地址,那么这是有效的。 - TKoL
3
第二步是在窗口中创建问题。 14148错误:0D07A097:asn1编码例程:ASN1_mbstring_ncopy:字符串过长:.\crypto\asn1\a_mbstr.c:158:maxsize = 2。 - Hermenpreet Singh
2
@HermenpreetSingh 这是一个与国家缩写有关的问题,你可能只是没有在 req.cnf 文件中更改该行 C = Country initials like US, RO, GE,它应该只是类似于 C = US 的东西。 - sme
显示剩余8条评论

149

最短路径。 在MacOS上测试过,但在其他操作系统上可能类似。

生成pem

> openssl req -x509 -newkey rsa:2048 -keyout keytmp.pem -out cert.pem -days 365

> openssl rsa -in keytmp.pem -out key.pem

你的 Express 服务器

const express = require('express')
const app = express()
const https = require('https')
const fs = require('fs')
const port = 3000

app.get('/', (req, res) => {
  res.send('WORKING!')
})

const httpsOptions = {
  key: fs.readFileSync('./key.pem'),
  cert: fs.readFileSync('./cert.pem')
}
const server = https.createServer(httpsOptions, app).listen(port, () => {
  console.log('server running at ' + port)
})
  • 在 Google Chrome 中打开 https://localhost:3000 ,您会发现它还不安全。但是!
  • 在“开发者工具”>“安全性”>“查看证书”中:将图像拖到桌面上,然后双击它。
  • 点击“添加”
  • 在“钥匙串访问”中找到它并双击它
  • 展开“信任”,将“使用此证书时”更改为“始终信任”。
  • 可能需要提示进行身份验证。
  • 重新启动服务器。
  • 刷新您的浏览器。
  • 享受吧! :)

太好了!这个可行!我想补充一下:从这里安装OpenSSL:https://indy.fulgan.com/SSL/?C=M;O=A。从这里获取.cnf文件:,然后从这里进行配置:https://gist.githubusercontent.com/pandurang90/dbe6a67339747ef5bacf/raw/ceb8bc0b30e206abaf9afdc030a7d24bc272b864/openssl.cnf,并从这里配置openSSL:https://dev59.com/questions/oGs05IYBdhLWcg3wPfgR - Jose A
2
我想补充一点,对于Chrome 58+,您将收到一个“缺少主题备用名称”的错误。https://dev59.com/PGsz5IYBdhLWcg3w6MNS#42917227。请查看下面的答案以获取更多帮助:https://dev59.com/PGsz5IYBdhLWcg3w6MNS#43666288,https://dev59.com/PGsz5IYBdhLWcg3w6MNS#44398368。 - Jose A
20
拖动图像到您的桌面并双击它。-> 我无法将任何东西拖到我的桌面上,无法进行拖动。你具体是在说哪一个“图像”? - AIon
11
为了解决 Chrome 中的“主题替代名称丢失”问题,您可以执行以下命令:openssl req -newkey rsa:2048 -x509 -nodes -keyout keytmp.pem -new -out cert.pem -subj /CN=localhost -reqexts SAN -extensions SAN -config <(cat /System/Library/OpenSSL/openssl.cnf <(printf '[SAN]\nsubjectAltName=DNS:localhost')) -sha256 -days 3650,而不是您提供的第一行命令。此命令在过程中还会询问较少的问题… - Michael Litvin
@AIon,这只适用于MacOS,在Windows上可能会更加复杂 ;) - Michael Litvin
显示剩余4条评论

77
你可以尝试使用openSSL来生成证书。 请查看this
为给Node JS Express服务器添加HTTPS,您需要.key和.crt文件。一旦生成了这些文件,请使用以下代码将HTTPS添加到服务器。
var https = require('https');
var fs = require('fs');
var express = require('express');

var options = {
    key: fs.readFileSync('/etc/apache2/ssl/server.key'),
    cert: fs.readFileSync('/etc/apache2/ssl/server.crt'),
    requestCert: false,
    rejectUnauthorized: false
};


var app = express();

var server = https.createServer(options, app).listen(3000, function(){
    console.log("server started at port 3000");
});

这在我的本地机器和我部署的服务器上都正常工作。我在服务器上购买的证书来自goDaddy,但是本地主机使用了自签名证书。

然而,每个浏览器都会抛出一个错误,说连接不受信任,是否要继续。当我点击继续后,它就可以正常工作了。

如果有人曾经绕过这个自签名证书的错误,请指点一下。


11
您的证书仍未被信任,因此您面临我所描述的相同问题。我需要让它被信任才能正确测试/调试网络服务。 - JasonS
1
所以您希望此证书仅在本地计算机上受信任,而不在网络中受信任? - user1741851
1
答案顶部的链接推荐使用1024位3DES加密,但这已经过时了。更好的方法是使用“openssl genrsa -out key.pem 2048”生成更好的密钥。 - steampowered
3
您的证书仍未获得信任。 - Diego Mello
2
以上的快速代码可正常运行,利用 https://github.com/FiloSottile/mkcert(而不是openSSL)来创建本地CA / 可信证书。全绿安全条。 - som
显示剩余6条评论

30

Mkcert是由@FiloSottile开发的工具,可以使这个过程无限简单:

  1. 安装mkcert,有适用于macOS/Windows/Linux的说明
  2. 运行mkcert -install以创建本地CA
  3. 运行mkcert localhost 127.0.0.1 ::1在当前目录中为localhost创建可信证书
  4. 因为您正在使用不使用系统根证书存储的node,所以需要在环境变量中显式指定CA,例如: export NODE_EXTRA_CA_CERTS="$(mkcert -CAROOT)/rootCA.pem"
  5. 最后按照其他答案提供的设置运行您的Express服务器(例如下面)
  6. 完成。localhost已经被标记为安全。

基本的node设置如下:

const https = require('https');
const fs = require('fs');
const express = require('express');

const app = express();    
const server = https.createServer({
    key: fs.readFileSync('/XXX/localhost+2-key.pem'), // where's me key?
    cert: fs.readFileSync('/XXX/localhost+2.pem'), // where's me cert?
    requestCert: false,
    rejectUnauthorized: false,
}, app).listen(10443); // get creative

运作得非常好!采用这种方法,我们无需在 Chrome/Windows 证书存储中注册自签名证书作为 CA 可信证书颁发机构。这也解答了其他答案中提到的问题。 - zaheer
我可以在管道上运行这个吗?这是我问题的参考链接 https://stackoverflow.com/questions/71850480/express-https-azure-pipelines-secret-variable - Ibra
1
@Ibra,关于管道使用,在mkcert github repo上似乎有一些讨论,所以可以假设它是可能的...但请记住,mkcert并不适用于生产环境。 - som

13
如何为本地主机生成SSL证书:链接
openssl genrsa -des3 -out server.key 1024

在这里您需要输入一个密码,并在以下步骤中重新输入该密码。

openssl req -new -key server.key -out server.csr

在被询问“通用名称”时,输入:localhost

openssl x509 -req -days 1024 -in server.csr -signkey server.key -out server.crt

1
这是我在过去两个小时里在互联网上搜寻的解决方案。对于Ubuntu用户,移动cp server.crt /usr/local/share/ca-certificates/.并运行sudo update-ca-certificates,然后本地主机的HTTPS请求可以在NodeJS 8+下工作。我还建议将1024增加到2048 - Salyangoz

7

这里发布的一些答案对我克服这个问题非常有用。然而,我也对最少步骤和避免在Windows 10上使用OpenSSL(如果可能)感兴趣。

所以,答案中一个关键的部分(由@TroyWorks提供)是你需要编辑HOSTS文件创建一个虚假服务器,并将其映射到127.0.0.1。这假定你将会进行本地开发。

在我的情况下,我正在使用SS证书保护NodeJS中的websocket,该socket是通过编程方式连接的(而非通过浏览器)。因此,对我来说,重要的是证书能够被正确接受而没有警告或错误信息,其关键之处是使用正确的CN创建证书(当然还要像答案中其他地方所描述的那样接受证书到受信任的颁发机构)。使用IIS创建自签名证书无法创建正确的CN,所以我发现了以下使用PowerShell的简单命令:

New-SelfSignedCertificate -DnsName "gandalf.dummy.dev" -FriendlyName "gandalf" -CertStoreLocation "cert:\LocalMachine\My"

这需要在PS Admin控制台中运行,但它非常有效,并将证书放入LocalMachine证书存储的“个人”部分。 您可以通过执行以下操作来验证其创建:

ls cert:\LocalMachine\My 

要信任它,只需将此内容复制并粘贴到证书管理器中的“受信任的根证书颁发机构”(确保您正在查看本地计算机证书,而不是当前用户!)。
如果您在IIS中绑定此证书,应该能够访问https://gandalf.dummy.dev/并获得安全连接,而无需任何警告。
最后一步,在NodeJS中使用此证书,如上文和其他SO答案所述,因此我只会补充说明在Windows上,使用结合了证书和私钥的pfx文件更容易。您可以轻松从证书管理器中导出pfx文件,但它确实会影响您在NodeJS中的使用方式。当使用“https”模块实例化服务器时,您将使用的选项(而不是'key'和'cert')将是“pfx”和“passphrase”,例如:
var https = require('https');
var options = { 
    pfx: fs.readFileSync('mypfxfile'), 
    passphrase: 'foo' 
};
var server = https.createServer(options);

6

以下是我使用的方法

在Windows系统上:

1) 将下面这行代码添加到 %WINDIR%\System32\drivers\etc\hosts 文件中: 127.0.0.1 localdev.YOURSITE.net (因为浏览器对 'localhost'(跨域脚本)存在问题)

Windows Vista 和 Windows 7 Vista 和 Windows 7 使用用户账户控制 (UAC),所以记事本必须以管理员身份运行。

  1. 点击开始->所有程序->附件

  2. 右键单击记事本并选择以管理员身份运行

  3. 点击 "Windows 需要您的许可" UAC 窗口上的继续。

  4. 当记事本打开时,点击文件->打开

  5. 在文件名字段中键入 C:\Windows\System32\Drivers\etc\hosts

  6. 点击打开

  7. 将下面这行代码添加到 %WINDIR%\System32\drivers\etc\hosts 文件中: 127.0.0.1 localdev.YOURSITE.net

  8. 保存

  9. 关闭并重新启动浏览器

在Mac或Linux上:

  1. 使用 su 权限打开 /etc/hosts
  2. 添加 127.0.0.1 localdev.YOURSITE.net
  3. 保存

在开发时,请使用 localdev.YOURSITE.net 代替 localhost,因此如果您在 IDE 中使用运行/调试配置,请确保更新它。

在创建 cookie 时,将 ".YOURSITE.net"(以点开头)作为 cookiedomain,这样应该可以与所有子域一起使用。

2) 使用 localdev.url 创建证书

提示:如果在 Windows 上生成证书时遇到问题,请改用 VirtualBox 或 Vmware 虚拟机。

3) 按照以下步骤导入证书: http://www.charlesproxy.com/documentation/using-charles/ssl-certificates/


嗨Troy,谢谢你分享这个。其他人将不得不评论这是否有效。我的解决方法:我最终在我的hosts文件中添加了dev.phantomjscloud.com,然后使用我的生产证书。但那只有在您想让生产密钥在开发框中可用时才有用,因此我认为如果有人可以验证,您的解决方案仍然是有效的。 - JasonS
它对我和我的团队都有效,可以在多种方式下使用,包括从安全的本地到本地服务器,以及从安全的本地到生产服务器。 - TroyWorks
对于Windows系统,使用git bash控制台可以很好地使用来自此处的openssl命令。只需安装根证书,您就可以创建多个特定于站点的证书并由其签名。 - Jason Goemaat

6

对于Windows操作系统,请按照以下简单步骤进行操作:

  1. 以管理员身份打开 Windows PowerShell
  2. 通过此链接安装 Chocolatey
  3. 使用 choco install mkcert 命令安装 mkcert
  4. 运行命令 mkcert -install,将会创建本地CA。
  5. 运行命令 mkcert localhost 127.0.0.1 ::1,将会在当前目录下创建一个可信任的 localhost 证书。
  6. 在服务器上将生成的 ./localhost+2.pem./localhost+2-key.pem 文件作为证书和密钥使用(添加密钥和证书因服务器而异)。
  7. 最后按照其他答案中所述的设置运行您的服务器(例如 Express 服务器的设置如下)。
    const https = require('https');
    const fs = require('fs');
    const express = require('express');

    const app = express();


    app.get('/', function(req, res){
      res.send("HELLO!");
    });

    const server = https.createServer({
        key: fs.readFileSync('./localhost+2-key.pem'), // path to localhost+2-key.pem
        cert: fs.readFileSync('./localhost+2.pem'), // path to localhost+2.pem
        requestCert: false,
        rejectUnauthorized: false,
    }, app).listen(3000, function(){
      console.log("Successfully started server on port 3000");
    });

然后使用以下命令运行你的服务器:

node server.js
  1. 在你的浏览器中访问 https://localhost:3000,将会在地址栏中看到一个锁。

享受吧!


4
如果您使用的是OSX/Chrome,您可以按照这里所述的方法将自签名SSL证书添加到系统钥匙链中:http://www.robpeck.com/2010/10/google-chrome-mac-os-x-and-self-signed-ssl-certificates
这是一个手动过程,但我最终使它工作了。只需确保通用名称(CN)设置为“localhost”(不带端口),并在添加证书后确保所有证书上的信任选项都设置为“始终信任”。还要确保将其添加到“系统”钥匙链而不是“登录”钥匙链。

他提到了IE,这意味着他在使用Windows。 - 2-bits

4

前往:chrome://flags/

启用:允许加载自localhost的资源使用无效证书。

您没有绿色安全标志,但是在Chrome中始终允许https://localhost


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接