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

iyfamqjs  于 2023-06-23  发布在  其他
关注(0)|答案(8)|浏览(613)

我正在使用节点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

我已经使用客户端和服务器的证书的所有组合运行了客户端和服务器(即:[(服务器1,客户端1),(服务器1,客户端2),(服务器2,客户端1),(服务器2,客户端2)],并且对于这些服务器的每个组合,在“代理”字段的默认值和“代理”设置为“假”的情况下进行测试。
每次我运行client.js时,res.req.connection.authorizationError都被设置为DEPTH_ZERO_SELF_SIGNED_CERT。
如何通过客户端的证书认证在节点中建立安全连接?

cnwbcb6i

cnwbcb6i1#

我相信你有两个问题,一个是你的代码,另一个是你的证书。
代码问题在您的服务器中。您没有像在客户端代码中那样指定CA来检查具有options属性的客户端证书:

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

第二个问题是真正导致DEPTH_ZERO_SELF_SIGNED_CERT错误的问题。您正在为所有证书(CA、服务器和客户端)指定相同的可分辨名称。当服务器从客户端证书中提取颁发者信息时,它发现颁发者DN与客户端证书DN相同,并得出客户端证书是自签名的结论。
尝试重新生成您的证书,为每个证书指定一个唯一的通用名称(以使DN也是唯一的)。例如,将您的CA证书命名为“Foo CA”,将您的服务器证书命名为您的主机名称(本例中为“localhost”),将您的客户端证书命名为其他名称(例如,“Foo客户端Γ)。

v6ylcynt

v6ylcynt2#

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

yws3nbqq

yws3nbqq3#

这一个为我工作:

process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";

注意:张贴答案,以便将来可以帮助其他人。

pzfprimi

pzfprimi4#

尽管在这个页面中有很长的描述,我仍然在客户端得到了'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();
fxnxkyjh

fxnxkyjh5#

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

2exbekwf

2exbekwf6#

如上所述,有一个大锤在你的指甲,使用rejectUnauthorized: false
从安全的Angular 来看,一个更明智的选择是询问用户是否愿意接受并存储自签名的服务器证书,就像浏览器(或SSH)所做的那样。
这将需要:
(1)NodeJS抛出异常,包含服务器证书,并且
(2)在手动接受证书后,应用程序使用ca:属性中存储的证书调用https.request(有关ca的说明,请参见上文)。
NodeJS似乎不做(1),使得(2)不可能?
从安全的Angular 来看,更好的方法是使用EFF的SSL天文台对自签名证书的有效性进行众包判断。同样,这需要NodeJS做(1)。
我认为开发人员需要在以下方面改进NodeJS:(1)...

hc2pp10m

hc2pp10m7#

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

disbfnqx8#

我也遇到了DEPTH_ZERO_SELF_SIGNED_CERT错误。但在我的例子中,服务是由docker部署的,我对源代码非常陌生。因此,在docker内部的代码中添加一个选项rejectUnauthorized: false会很烦人。
在谷歌上搜索了一段时间后,我在this post中找到了一个更友好的解决方案:将选项设置为环境变量

NODE_TLS_REJECT_UNAUTHORIZED=0

相关问题