0

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

https://localhost:3000

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

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

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

在 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)
4

1 回答 1

0

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

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

我从这个答案中得到了这一点。我认为 Chrome 并没有提示我选择证书,因为它将我的开发环境视为不安全。启用该设置后,证书提示按预期出现,“/login” URL 显示我选择的证书的 CN。

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

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

于 2021-12-22T16:21:34.343 回答