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

Mar*_*rek 17 ssl certificate node.js

我正在使用节点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);
Run Code Online (Sandbox Code Playgroud)

客户代码:

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();
Run Code Online (Sandbox Code Playgroud)

我用以下命令创建了证书,每次都将"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
Run Code Online (Sandbox Code Playgroud)

我运行客户端和服务器,包括客户端和服务器证书的所有组合(即:[(server1,client1),(server1,client2),(server2,client1),(server2,client2)]以及这些证书的每个组合.服务器已使用默认值"agent"字段和"agent"设置为"false"进行测试.

每次运行client.js时,res.req.connection.authorizationError都设置为DEPTH_ZERO_SELF_SIGNED_CERT.

如何在节点中使用客户端的证书身份验证建立安全连接?

rha*_*oto 20

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

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

ca: fs.readFileSync('ssl/ca.pem'),
Run Code Online (Sandbox Code Playgroud)

第二个问题是真正导致DEPTH_ZERO_SELF_SIGNED_CERT错误的问题.您将为所有证书(CA,服务器和客户端)提供相同的专有名称.当服务器从客户端证书中提取发行者信息时,它会看到颁发者DN与客户端证书DN相同,并断定客户端证书是自签名的.

尝试重新生成证书,为每个证书提供一个唯一的公共名称(以使DN也是唯一的).例如,将您的CA证书命名为"Foo CA",将您的服务器证书命名为主机名(本例中为"localhost"),将客户端命名为其他东西(例如"Foo Client 1").

  • 先生,您真是个天才!我遇到的确切问题是我的CA与服务器证书具有相同的CN。我没有意识到这将是一个问题,但是现在我读了您的回答后,我感觉自己像个大人物。 (2认同)
  • 你是救命稻草。我们在 Kibana 上遇到了这个问题。它给出的只是错误“请求错误,重试 HEAD https://<elastic-search-url>:9200/ => 自签名证书”。我们尝试了*一切*,最后不得不删除 Kibana 源代码并添加 printlns。最终,一个 println 出现了`DEPTH_ZERO_SELF_SIGNED_CERT`,你的解决方案帮助我们找出了原因:我们已经生成了我们的 CA 并用它来签署证书,并且两者都具有相同的 CN(通用名称)。如果没有这篇文章,我们永远不会想到这一点。谢谢! (2认同)

B T*_*B T 15

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

  • 简单而重要; 非常感谢你. (2认同)
  • downvote 因为它不安全并且因为以前的答案给出了问题的原因 (2认同)
  • @HeshamYassin如果你在自己的机器上使用服务器的开发环境中工作,你实际上*不能*获得证书,所以你需要使用这个解决方案.所以在你请求之前先想想. (2认同)
  • 但是,除非使用`rejectUnauthorized:false`,否则自签名证书仍会失败 (2认同)

Man*_*wal 8

这个对我有用:

process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
Run Code Online (Sandbox Code Playgroud)

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

  • 虽然有效,但它具有全球影响。`rejectUnauthorized:false`根据需要更安全。 (2认同)