无法将Node.js中的IP用于自签名证书
Cannot use IP in Node.js for self-signed certificate
我正在Node.js.中尝试使用HTTP自签名证书
我使用我编写的以下脚本生成了证书:
生成.sh
#!/bin/bash
read -p "FQDN: " FQDN
# for easy testing
rm ROOT.*
rm SERVER.*
openssl genrsa 4096 > ROOT.key
openssl req -x509 -nodes -sha256 -new -key ROOT.key -days 365 -subj "/C=AU/CN=example" > ROOT.crt
openssl req -newkey rsa:4096 -nodes -sha256 -keyout SERVER.key -subj "/C=AU/CN=${FQDN}" > SERVER.csr
openssl x509 -days 365 -req -in SERVER.csr -CA ROOT.crt -CAkey ROOT.key -CAcreateserial > SERVER.crt
我正在尝试使用以下方法测试证书:
test.js
let fs = require('fs')
let https = require('https')
// HTTP server
https.createServer({
key: fs.readFileSync('SERVER.key'),
cert: fs.readFileSync('SERVER.crt'),
ca: fs.readFileSync('ROOT.crt')
}, function (req, res) {
res.writeHead(200)
res.end('Hello world')
}).listen(4433)
// HTTP request
let req = https.request({
hostname: '127.0.0.1',
port: 4433,
path: '/',
method: 'GET',
ca: fs.readFileSync('ROOT.crt')
}, function (res) {
res.on('data', function (data) {
console.log(data.toString())
})
})
req.end()
但是,经过测试:
> node test.js
Error: Hostname/IP doesn't match certificate's altnames: "IP: 127.0.0.1 is not in the cert's list: "
这似乎很奇怪,因为如果我打印证书证书列表,它显示IP在那里?
如果我使用localhost
作为FQDN,使用host
(在请求中),它确实有效。
我错过了什么?
编辑:
curl --cacert ROOT.crt https://127.0.0.1:4433
完成时没有出现错误,那么Node.js代码中缺少什么呢?
感谢Kris Reeves为我指明了正确的方向。
问题如前所述,证书缺少subjectAltName
s,并且以Node的兼容格式获取它们并不那么简单(必须与X509v3兼容)。
最后的Makefile
最终是这样的:
.PHONY: clean default
FQDN ?= 127.0.0.1
default: SERVER.crt
clean:
rm -f openssl.conf
rm -f ROOT.*
rm -f SERVER.*
openssl.conf:
cat /etc/ssl/openssl.cnf > openssl.conf
echo "[ san_env ]" >> openssl.conf
echo "subjectAltName=$$""{ENV::SAN}" >> openssl.conf
ROOT.key:
openssl genrsa 4096 > ROOT.key
ROOT.crt: ROOT.key
openssl req '
-new '
-x509 '
-nodes '
-sha256 '
-key ROOT.key '
-days 365 '
-subj "/C=AU/CN=example" '
-out ROOT.crt
SERVER.csr: openssl.conf
SAN=IP:$(FQDN) openssl req '
-reqexts san_env '
-config openssl.conf '
-newkey rsa:4096 '
-nodes -sha256 '
-keyout SERVER.key '
-subj "/C=AU/CN=$(FQDN)" '
-out SERVER.csr
SERVER.crt: openssl.conf ROOT.key ROOT.crt SERVER.csr
SAN=IP:$(FQDN) openssl x509 '
-req '
-extfile openssl.conf '
-extensions san_env '
-days 365 '
-in SERVER.csr '
-CA ROOT.crt '
-CAkey ROOT.key '
-CAcreateserial '
-out SERVER.crt
希望这能帮助其他想要使用只有IP的自签名证书的人。
$ make FQDN=127.0.0.1
我在IRC上和你交谈,但我会把信息留在这里,以防对其他人有帮助。
通过节点的tls模块的源代码,我们可以看到它期望altname采用一种非常特定的格式:
https://github.com/nodejs/node/blob/v5.0.0/lib/tls.js#L108-L145
尤其是这句话:var option = altname.match(/^(DNS|IP Address|URI):(.*)$/);
稍后,它决定要检查的主机的格式,如果它是一个IP地址,它会在从altname中提取的IP地址中查找它。因此,除非证书的altname格式为"IP地址:127.0.0.1",否则证书将失败,因为这是Node在稍后发现它正在测试IP地址时将其放入IP列表中的唯一方法。
我不知道这是否是证书altnames字段格式的规范,但它应该为您提供一个生成Node将接受的证书的路径。
或者,您可以在套接字或http请求的连接选项中提供自己的checkServerIdentity
函数(应传递给套接字):
https://github.com/nodejs/node/blob/82022a79b035c25f8a41df1f2a20793d356c1511/lib/_tls_wrap.js#L962-L969
这是我以前不得不做的,但我相信altname匹配可能比我上次遇到这个问题时更新。
- 将函数的上下文应用于javascript变量
- keyup事件处理程序更改焦点不适用于快速键入
- JQueryhide()不适用于Mozzilla,但适用于Chrome
- JavaScript数组排序(函数)用于对表行进行排序,而不是排序
- PHP中的setcookie仅适用于localhost
- 包括用于facebook评论框的JavaScript SDK
- 如何检测用于WebGL的专用或集成显卡
- ng更改事件不适用于Dropdown
- 用于搜索的聚合物嵌套绑定
- jQuery表单添加不适用于下拉列表
- Rails/JSON:如何将JSON用于jquery UI自动完成表单
- JS编译器/包管理器,用于版本控制
- 将CSS应用于printWindow.print();在Javascript中
- 用于'魔术串'属性
- 用于检查数组中是否存在元素的javascript自定义方法
- 谷歌地图API v3不适用于移动浏览器或PhoneGap
- 在ajax成功后,cluetip不适用于首次点击活动元素
- D3.js模式不适用于弧形或圆环图
- AngularJS单选筛选不适用于Name、Description和Field4复选框值
- 无法将Node.js中的IP用于自签名证书