服务器端的客户端证书validation,DEPTH_ZERO_SELF_SIGNED_CERT错误

我正在使用节点0.10.26,并尝试build立与客户端validation的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(); 

我用下面的命令创build了证书,每次都提供“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)],服务器被testing,默认值为“agent”字段,“agent”设置为“false”。

每次我运行client.js,res.req.connection.authorizationError被设置为DEPTH_ZERO_SELF_SIGNED_CERT。

如何在客户端的证书身份validation中build立与节点的安全连接?

我相信你有两个问题,一个是你的代码,另一个是你的证书。

代码问题在你的服务器上。 您没有指定CA来检查客户端证书,并使用您的客户端代码中的options属性:

 ca: fs.readFileSync('ssl/ca.pem'), 

第二个问题是真正导致DEPTH_ZERO_SELF_SIGNED_CERT错误的问题。 您正在提供所有证书 – CA,服务器和客户端 – 相同的专有名称。 当服务器从客户端证书中提取发行者信息时,发现发行者DN与客户端证书DN相同,并得出客户端证书是自签名的结论。

尝试重新生成您的证书,给每个人一个唯一的通用名称(使DN也是唯一的)。 例如,将您的CA证书命名为“Foo CA”,您的服务器证书是您主机的名称(本例中为“localhost”),您的客户端是其他名称(例如“Foo Client 1”)。

对于那些想要使用自签名证书的人来说,答案是将rejectUnauthorized: false添加到https.request选项。

这个为我工作:

 process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"; 

注意:发布答案,以便将来可以帮助他人。

尽pipe在这个页面中有很长的描述,但我仍然在客户端使用这个配方得到'UNABLE_TO_VERIFY_LEAF_SIGNATURE'错误。 也许我在跟随rhashimoto的评论有错误。

通过参考“ 专业Node.js ”的书,我find了另一种方法来成功testing客户端证书validation的HTTPS。
这是我的故事。
通过在服务器端设置requestCert: true ,服务器尝试validation客户端证书。 但是默认的CA不validation客户端的自签名证书。 我可以通过简单的伎俩来成功完成testing – 复制客户端证书,并说这是一个证书颁发机构。

我重复使用原始代码 ,并稍微修改它,使其工作。 最大的区别在于创build证书文件。

创build证书文件

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

如上所述,有一个大锤钉在你的指甲,使用rejectUnauthorized: false

从安全angular度来看,更明智的select是询问用户是否愿意接受和存储自签名服务器证书,就像浏览器(或SSH)一样。

这将需要:

(1)NodeJS抛出一个包含服务器证书的exception

(2)在手动接受证书之后,应用程序使用ca:属性中存储的证书(参见上面有关ca描述)调用https.request

看来,NodeJS不做(1),使(2)不可能?

从安全的angular度来看,更好的办法是使用EFF的SSL观察站对自签名证书的有效性做出群体判断。 同样,这需要NodeJS来完成(1)。

我认为开发人员需要改进NodeJS(1)…

只需将strictSSL: false添加到您的options

如果您只有.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 };