如何让 Node.Js 允许我为客户端证书提供智能卡/cac

Posted

技术标签:

【中文标题】如何让 Node.Js 允许我为客户端证书提供智能卡/cac【英文标题】:How to get Node.Js to allow me to provide client cert with smart card/cac 【发布时间】:2021-08-02 10:10:26 【问题描述】:

我正在尝试使用 node.js 构建 CAC 身份验证系统,但遇到了问题。我遵循了一些关于设置 https 服务器的教程,我可以让它正常工作;但是,每当我访问我的服务器时,使用下面的逻辑:

https://localhost:3000

系统提示我使用“/”路由处理程序发送的身份验证按钮登录;但是,它立即默认为 else 子句:

res.status(401)
        .send(`Sorry, but you need to provide a client certificate to continue.`)

通常,当访问启用 cac 的站点时,会提示我选择一个智能卡证书,它允许我登录;但是,在这种情况下,我根本没有收到提示。

我找到了similar question on SO,但无法从他们引用的文章中得到任何工作。他们提到我必须在 https 服务器上设置我的“ca”属性以允许相关 CAC 的特定 CA。我使用浏览器找到了我的 CAC 证书并导出了我的证书并将它们放入已批准的 CA 列表中,但我仍然没有收到任何提示。

我最初使用req.connection.getPeerCertificate() 来提示输入证书;但是,我读到 req.connection 在我的 Node.JS (14.15.0) 版本中已被弃用,所以我也尝试了req.socket.getPeerCertificate()。无论哪种方式,服务器似乎都运行得很好,我在客户端或服务器端都没有错误(除了从服务器发送的 401 响应,因为它没有获得有效的证书)。任何和所有的见解将不胜感激。

const fs = require('fs')
const express = require('express')
const https = require('https')

// Https options
const options = 
    // Path to private key (created by openssl in createSelfSignedCert.bat)
    key: fs.readFileSync('server_key.pem')
    // Path to public key
    ,cert: fs.readFileSync('server_cert.pem')
    // Indicate that https server should request client certificates
    ,requestCert: true
    // Manually handle bad requests (no certs)
    ,rejectUnauthorized: false
    //List of accepted/valid CA certs - just our own for now
    ,ca: [ 
        fs.readFileSync('server_cert.pem')
        ,fs.readFileSync('cac52.cer')
        ,fs.readFileSync('cac_export.p7b')
    ]
    //,ca: .



// Use express for routing
const app = express()


// Unprotected public endpoint
app.get('/', (req, res) => 
    res.send('<a href="login">Auth</a>')
)


// Protected endpoint
app.get('/login', (req, res) => 
    // req.connection is deprecated, perhaps req.socket.getPeerCertificate()
    const cert = req.connection.getPeerCertificate()
    //const cert = req.socket.getPeerCertificate()


    if (req.client.authorized) 
        res.send(`Hello $cert.subject.CN, your certificate was issued by $cert.issuer.CN!`)
        console.log(`$cert`)
     else if (cert.subject) 
        res.status(403)
           .send(`Sorry $cert.subject.CN, certificates from $cert.issuer.CN are not welcome here.`)
           console.log(`$cert`)
     else 
        res.status(401)
            .send(`Sorry, but you need to provide a client certificate to continue.`)
    

)

// Create https server with options and app routes
https.createServer(options, app).listen(3000)

【问题讨论】:

【参考方案1】:

我通过在浏览器 (Chrome) 中更改此设置来实现此功能:

chrome://flags/#allow-insecure-localhost

我是从this answer 那里得到的。我认为 Chrome 并没有提示我选择证书,因为它将我的开发环境视为不安全。启用该设置后,证书提示按预期出现,“/login” URL 显示我选择的证书的 CN。

此外,您还需要确保您拥有正确的 CA。 AFAIK,您不能只从 CAC 导出 CA 证书链 - 您需要从 CA 向您提供它们。如果您正在从事 DoD 项目,您将需要 DoD 根 CA。如果您已经拥有 DoD CAC,则可以从 this link 获取 DoD 根 CA。

请记住,您的 CAC 上加载的证书是客户端证书,它们对您来说是唯一的。 CA(认证机构)是向您颁发这些证书的组织。当您将 CA 证书添加到您的项目时,您的应用实际上是在说“我可以接受此 CA 颁发的客户端证书。”

【讨论】:

以上是关于如何让 Node.Js 允许我为客户端证书提供智能卡/cac的主要内容,如果未能解决你的问题,请参考以下文章

无论证书有效性如何,我的 node.js https 客户端始终有效

使用 node.js 验证带有 CA 证书的 X509 证书

每五分钟安排一次 Node.js 作业

如何让 Node.js 进程相互通信

如何在 express.js node.js 中设置 X-Frame-Options

Node.js + APN:在本地,一切正常,但在云主机上启动时出现“端点错误:无法获取本地颁发者证书”