我正在使用节点0.10.26并尝试与客户端验证建立https连接。
服务器代码:
var https = require('https');
var fs = require('fs');
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
var options = {
key: fs.readFileSync('ssl/server1.key'),
cert: fs.readFileSync('ssl/server1.pem'),
requestCert: true,
rejectUnauthorized: false,
};
var server = https.createServer(options, function (req, res) {
if (req.client.authorized) {
res.writeHead(200, {"Content-Type":"application/json"});
res.end('{"status":"approved"}');
console.log("Approved Client ", req.client.socket.remoteAddress);
} else {
console.log("res.connection.authroizationError: " + res.connection.authorizationError);
res.writeHead(403, {"Content-Type":"application/json"});
res.end('{"status":"denied"}');
console.log("Denied Client " , req.client.socket.remoteAddress);
}
});
server.on('error', function(err) {
console.log("server.error: " + err);
});
server.on("listening", function () {
console.log("Server listeining");
});
server.listen(5678);
客户代码:
var https = require('https');
var fs = require('fs');
var options = {
host: 'localhost',
port: 5678,
method: 'GET',
path: '/',
headers: {},
agent: false,
key: fs.readFileSync('ssl/client2.key'),
cert: fs.readFileSync('ssl/client2.pem'),
ca: fs.readFileSync('ssl/ca.pem')
};
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
var req = https.request(options, function(res) {
console.log(res.req.connection.authorizationError);
});
req.on("error", function (err) {
console.log('error: ' + err);
});
req.end();
我用以下命令创建了证书,每次都将“uname -n”的结果作为“Common Name”提供:
openssl genrsa -out ca.key 4096
openssl req -x509 -new -nodes -key ca.key -days 999 -out ca.pem
openssl genrsa -out server1.key 1024
openssl req -new -key server1.key -out server1.csr
openssl x509 -req -days 999 -in server1.csr -CA ca.pem -CAkey ca.key -set_serial 01 -out server1.pem
openssl genrsa -out client1.key 1024
openssl req -new -key client1.key -out client1.csr
openssl x509 -req -days 999 -in client1.csr -CA ca.pem -CAkey ca.key -set_serial 01 -out client1.pem
openssl genrsa -out server2.key 1024
openssl req -new -key server2.key -out server2.csr
openssl x509 -req -days 999 -in server2.csr -CA server1.pem -CAkey server1.key - set_serial 02 -out server2.pem
openssl genrsa -out client2.key 1024
openssl req -new -key client2.key -out client2.csr
openssl x509 -req -days 999 -in client2.csr -CA client1.pem -CAkey client1.key -set_serial 02 -out client2.pem
我运行客户端和服务器,包括客户端和服务器证书的所有组合(即:[(server1,client1),(server1,client2),(server2,client1),(server2,client2)]和每个这些服务器的组合使用默认值“agent”字段和“agent”设置为“false”进行了测试。
每次运行client.js时,res.req.connection.authorizationError都设置为DEPTH_ZERO_SELF_SIGNED_CERT。
如何在节点中使用客户端的证书身份验证建立安全连接?
答案 0 :(得分:20)
我相信你有两个问题,一个是你的代码,一个是你的证书。
代码问题在您的服务器中。您没有指定CA来检查具有options
属性的客户端证书,就像您在客户端代码中一样:
ca: fs.readFileSync('ssl/ca.pem'),
第二个问题是真正导致DEPTH_ZERO_SELF_SIGNED_CERT
错误的问题。您将为所有证书(CA,服务器和客户端)提供相同的专有名称。当服务器从客户端证书中提取颁发者信息时,它会看到颁发者DN与客户端证书DN相同,并断定客户端证书是自签名的。
尝试重新生成证书,为每个证书提供唯一的公用名称(以使DN也是唯一的)。例如,将您的CA证书命名为“Foo CA”,将您的服务器证书命名为主机名(本例中为“localhost”),将您的客户端命名为其他内容(例如“Foo Client 1”)。
答案 1 :(得分:15)
对于那些想要使用自签名证书的人,答案是将rejectUnauthorized: false
添加到https.request选项。
答案 2 :(得分:8)
这个对我有用:
Lock
注意:发布回答以便将来可以帮助其他人。
答案 3 :(得分:2)
尽管此页面中有很多描述,但我仍然在客户端使用此配方时出现“UNABLE_TO_VERIFY_LEAF_SIGNATURE”错误。也许我在跟随rhashimoto's comment时出了点问题。
通过引用“Professional Node.js”一书,我找到了另一种成功测试HTTPS的方法。
这是我的故事
通过在服务器端设置requestCert: true
,服务器会尝试验证客户端证书。但默认CA不验证客户端的自签名证书。我可以通过简单的技巧成功完成测试 - 复制客户端证书并说这是一个证书颁发机构。
我重复使用original code并略微修改它以使其正常工作。 最大的区别在于创建证书文件。
创建证书文件:
# create client private key
openssl genrsa -out client2.key
openssl req -new -key client2.key -out client2.csr
# create client certificate
openssl x509 -req -in client2.csr -signkey client2.key -out client2.pem
# create server private key and certificate
openssl genrsa -out server1.key
openssl req -new -key server1.key -out server1.csr
openssl x509 -req -in server1.csr -signkey server1.key -out server1.pem
# * Important *: create fake CA with client certificate for test purpose
cp client2.pem fake_ca.pem
服务器代码:
var options = {
key: fs.readFileSync('ssl/server1.key'),
cert: fs.readFileSync('ssl/server1.pem'),
ca: [fs.readFileSync('ssl/fake_ca.pem')], // Line added
requestCert: true,
rejectUnauthorized: false,
};
客户代码:
key: fs.readFileSync('ssl/client2.key'),
cert: fs.readFileSync('ssl/client2.pem'),
//ca: fs.readFileSync('ssl/ca.pem') // Line commented
};
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
var req = https.request(options, function(res) {
//console.log(res.req.connection.authorizationError);
console.log("statusCode:", res.statusCode);
res.on('data', function(d) {
console.log('data:', d.toString());
});
});
req.on("error", function (err) {
console.log('error: ' + err);
});
req.end();
答案 4 :(得分:1)
只需将strictSSL: false
添加到options
。
答案 5 :(得分:0)
如上所述,使用rejectUnauthorized: false
有一把大锤敲打你的钉子。
从安全的角度来看,更明智的选择是询问用户他是否愿意接受并存储自签名服务器证书,就像浏览器(或SSH)一样。 / p>
这需要:
(1)NodeJS抛出包含服务器证书的异常,并且
(2)在手动接受证书后,应用程序使用https.request
属性中存储的证书调用ca:
(参见上面的ca
的说明)。
似乎NodeJS不做(1),使得(2)不可能?
从安全角度来看,更好的方法是使用EFF的SSL观察站对自签名证书的有效性做出众源判断。同样,这需要NodeJS做(1)。
我认为开发人员需要针对(1)...
改进NodeJS答案 6 :(得分:0)
如果您只有.pem自签名证书(例如/tmp/ca-keyAndCert.pem),则以下选项将起作用:
var options = {
url: 'https://<MYHOST>:<MY_PORT>/',
key: fs.readFileSync('/tmp/ca-keyAndCert.pem'),
cert: fs.readFileSync('/tmp/ca-keyAndCert.pem'),
requestCert: false,
rejectUnauthorized: false
};