Client certificate validation on server side, DEPTH_ZERO_SELF_SIGNED_CERT error

后端 未结 7 1213
不知归路
不知归路 2020-12-09 16:34

I\'m using node 0.10.26 and trying to establish https connection with client validation.

Server\'s code:

var https = require(\'https\');
var fs = req         


        
相关标签:
7条回答
  • 2020-12-09 16:57

    For those of that want to use a self-signed certificate, the answer is to add rejectUnauthorized: false to the https.request options.

    0 讨论(0)
  • 2020-12-09 16:57

    This one worked for me:

    process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
    

    Note: Posting answer so it can help others in future.

    0 讨论(0)
  • 2020-12-09 16:59

    Despite of long lines of description in this page, I still got 'UNABLE_TO_VERIFY_LEAF_SIGNATURE' error in the client side with this recipe. Maybe I had something wrong in following rhashimoto's comment.

    By referencing book of 'Professional Node.js', I found another way to test HTTPS with Client Certificate Verification successfully.
    Here is my story.
    By setting requestCert: true in server side, the server tries to validate client certificate. But the default CA doesn't validate the self-signed certificate of the client. I can succeed the test with simple trick -- copy the client certificate and say that is a Certificate Authority.

    I reused original code and modified it slightly to make it work. The big difference is in creating certificate files.

    Creating certificate files:

    # 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
    

    Server code:

    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,
    };
    

    Client code:

        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();
    
    0 讨论(0)
  • 2020-12-09 17:10

    I believe you have two problems, one with your code and one with your certificates.

    The code issue is in your server. You are not specifying the CA to check client certificates with an options property like you have in your client code:

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

    The second problem is the one that really causes that DEPTH_ZERO_SELF_SIGNED_CERT error. You are giving all your certificates - CA, server, and client - the same Distinguished Name. When the server extracts the issuer information from the client certificate, it sees that the issuer DN is the same as the client certificate DN and concludes that the client certificate is self-signed.

    Try regenerating your certificates, giving each one a unique Common Name (to make the DN also unique). For example, name your CA certificate "Foo CA", your server certificate the name of your host ("localhost" in this case), and your client something else (e.g. "Foo Client 1").

    0 讨论(0)
  • 2020-12-09 17:13

    As mentioned above, there is a sledgehammer to hammer in your nail, using rejectUnauthorized: false.

    A more sensible option, from a security point of view, would be to ask the user if (s)he would like to accept and store the self-signed server certificate, just like a browser (or SSH) does.

    That would require:

    (1) That NodeJS throws an exception that contains the server certificate, and

    (2) that the application calls https.request with the stored certificate in the ca: property (see above for description of ca) after the certificate has been manually accepted.

    It seems that NodeJS does not do (1), making (2) impossible?

    Even better from a security point of view would be to use EFF's SSL observatory to make a crowd-sourced judgement on the validity of a self-signed certificate. Again, that requires NodeJS to do (1).

    I think a developer needs to improve NodeJS with respect to (1)...

    0 讨论(0)
  • 2020-12-09 17:17

    Just add strictSSL: false to your options.

    0 讨论(0)
提交回复
热议问题