仅部分路径上的Node.js客户端证书身份验证

时间:2013-01-23 08:05:19

标签: node.js ssl https x509

我有一个基于node.js的网络应用,需要来自客户端的安全(https)连接。我想要的是在某些路径上需要客户端证书身份验证,而在其他路径上则不需要。

所以举个例子。如果用户转到https://www.example.com/main,则服务器不需要客户端证书身份验证(因此浏览器不会询问任何内容)。但是,如果用户导航到https://www.example.com/secure,则需要客户端证书身份验证(因此浏览器将弹出一个对话框,用于选择要使用的证书)。

我怎样才能实现这一目标。如果我将requestCert:truerejectUnauthorized:true传递给https.createServer选项,我可以强制进行客户端证书身份验证。这种方法的问题是每条路径都需要客户端证书。

3 个答案:

答案 0 :(得分:1)

我来到这里是因为我正在研究同样的问题,并将分享我所采取的方法。对于要求用户使用有效证书进行身份验证的端点,我使用附加到需要证书的端点的自定义路径,并验证用户是否使用证书进行身份验证(如果他们正在访问遵循该路径的任何端点)(假设使用Express应用程序)。即:

app.use('/api/cert', function(req, res, next){
    //validate that any token passed in the request was generated for a valid
    //cert login, otherwise reject request

    //pseudo-code
    if(isValidCertToken(req.authentication.token)) {
        next(); //this will pass it on to the correct endpoint in the /api/cert/[whatever] chain
    } else {
        req.status(401).send({error: 'invalid login, cert required'});
    }
});

这将要求您允许用户通过将requestCert标志设置为true来使用证书进行身份验证,但如果用户不希望使用"证书,还将允许其他身份验证方法所需"端点,只要在设置https connecton时将rejectUnauthorized设置为false。

答案 1 :(得分:0)

我不确定我是否完全理解你想要的东西..但根据我的理解,如果你使用快递,你可以通过一个简单的中间件管理这个东西..在那个中间件你可以跟踪任何一个请求是来自http或https来自

HTTPS连接具有req.connection.encrypted(包含SSL连接信息的对象)。 HTTP连接没有req.connection.encrypted。

另外(来自文档):

使用HTTPS支持,使用request.connection.verifyPeer()和request.connection.getPeerCertificate()来获取客户端的身份验证详细信息。

我希望这有帮助..

答案 2 :(得分:0)

您可以通过 TLS 重新协商来实现此目的,但不幸的是,TLS 1.3 不支持此功能,因此您必须禁用它:

https
    .createServer(
        {
            // configure key, cert, ca,
            secureOptions: require('constants').SSL_OP_NO_TLSv1_3,
        },
        function (req, res) {
            if (req.url.startsWith('/secure')) {
                req.socket.renegotiate(
                    {
                        requestCert: true,
                        rejectUnauthorized: true,
                    },
                    err => {
                        if (err) {
                            console.log('Renegotiation failed', err);
                            res.writeHead(500);
                            res.end('Internal Server Error');

                            return;
                        }

                        // handle secure content
                    },
                );
            } else {
                // handle main content
            }
        },
    )
    .listen(443);