我正在尝试在nginx中启用客户端证书身份验证,其中证书已由中间CA签名。使用由自签名根CA签名的证书时,我能够正常工作;但是,当签名CA是中间CA时,这不起作用。
我的简单服务器部分如下所示:
server {
listen 443;
server_name _;
ssl on;
ssl_certificate cert.pem;
ssl_certificate_key cert.key;
ssl_session_timeout 5m;
ssl_protocols SSLv2 SSLv3 TLSv1;
ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
ssl_prefer_server_ciphers on;
ssl_client_certificate ca.pem;
ssl_verify_client on;
ssl_verify_depth 1;
location / {
root html;
index index.html index.htm;
}
}
对于ca.pem的内容,我尝试仅使用 中间CA并连接中间CA证书和根CA证书,例如:
cp intermediate.crt ca.pem
cat root.crt >> ca.pem
我还验证了在使用相同的CA链时,从openssl的角度来看证书是有效的:
openssl verify -CAfile /etc/nginx/ca.pem certs/client.crt
certs/client.crt: OK
我已经尝试将ssl_verify_depth显式设置为1(如上所述),然后甚至为0(不确定该数字的确切含义),但仍会得到相同的错误。
我在中间CA的所有变体中得到的错误是“400 Bad Request”,更具体地说是“SSL证书错误”(不确定这意味着什么)。
也许nginx不支持中间证书的证书链?任何帮助非常感谢!
答案 0 :(得分:44)
编辑:我也有这个“问题”,解决方案和解释位于文本底部。
似乎nginx不支持中间证书。我的证书是自己创建的:( RootCA是自签名的,IntrermediateCA1是由RootCA签名的等等)
RootCA -> IntermediateCA1 -> Client1
RootCA -> IntermediateCA2 -> Client2
我想在nginx“IntermediateCA1”中使用,只允许访问“Client1”证书的所有者。
当我使用 IntermediateCA1和RootCA 放入“ssl_client_certificate”文件并设置“ssl_verify_depth 2”(或更多)时,客户端可以使用证书 Client1和Client2 >登录到站点strong>(应该只是Client1)。 同样的结果是当我使用仅RootCA 放入“ssl_client_certificate”文件时 - 两个客户端都可以登录。
当我使用仅IntermediateCA1 放入“ssl_client_certificate”文件,并设置“ssl_verify_depth 1”(或“2”或更多 - 无论如何)时,登录是不可能的,我收到错误400.在调试模式下,我看到日志:
verify:0, error:20, depth:1, subject:"/C=PL/CN=IntermediateCA1/emailAddress=cert@asdf.com",issuer: "/C=PL/CN=RootCA/emailAddress=cert@asdf.com"
verify:0, error:27, depth:1, subject:"/C=PL/CN=IntermediateCA1/emailAddress=cert@asdf.com",issuer: "/C=PL/CN=RootCA/emailAddress=cert@asdf.com"
verify:1, error:27, depth:0, subject:"/C=PL/CN=Client1/emailAddress=cert@asdf.com",issuer: "/C=PL/CN=IntermediateCA1/emailAddress=cert@asdf.com"
(..)
client SSL certificate verify error: (27:certificate not trusted) while reading client request headers, (..)
我觉得这是一个错误。在Ubuntu上测试,nginx 1.1.19和1.2.7-1~dotdeb.1,openssl 1.0.1。 我看到nginx 1.3有更多关于使用客户端证书的选项,但我们没有看到解决这个问题的方法。
目前,分离客户端1和2的唯一方法是创建两个自签名的RootCAs,但这只是解决方法..
编辑1: 我在这里报告了这个问题:http://trac.nginx.org/nginx/ticket/301
编辑2“ * 好的,这不是错误,它是功能;) *
我在这里得到回复:http://trac.nginx.org/nginx/ticket/301 它正在运作,你必须只检查你的ssl_client_i_dn是什么(。你可以使用证书主题,或者你想要的http://wiki.nginx.org/HttpSslModule#Built-in_variables
来代替发行者这是证书验证的工作原理:证书必须是 验证了受信任的根。如果链不能构建为可信任的 root(非中间) - 验证失败。如果你信任root - all 由其直接或间接签署的证书将是 成功验证。
如果您可以使用限制验证深度 想要将客户端证书限制为直接颁发的证书 只是,但它更多的是关于DoS预防,显然它不可能 用于将verificate仅限制为intermediate1(但不是 intermediate2)。
您想要的是基于授权层的一些内容 在验证结果上 - 即您可能想要检查该客户端 证书颁发者是中间人1。最简单的解决方案是 如果发行人的DN与允许的DN不匹配,则拒绝请求,例如 这样的事情(完全未经测试):
[由我编辑,它在我的配置中正常工作]
server {
listen 443 ssl;
ssl_certificate ...
ssl_certificate_key ...
ssl_client_certificate /path/to/ca.crt;
ssl_verify_client on;
ssl_verify_depth 2;
if ($ssl_client_i_dn != "/C=PL/CN=IntermediateCA1/emailAddress=cert@asdf.com") {
return 403;
}
}
答案 1 :(得分:11)
您是否尝试过增加ssl_verify_depth
指令? Docs说:
(it) sets a verification depth in the client certificates chain.
但你的验证深度是1.你说:
我已经尝试将ssl_verify_depth显式设置为1(如上所述),然后甚至为0(不确定该数字的确切含义),但仍会得到相同的错误。
所以,试试2或3 ..
PS:
在我发现提到此问题的任何地方,它被告知将中间CA证书与您的服务器证书组合在一起。根据验证的顺序将一个文件(作为@vikas-nalwar suggested并且你做了)(但我不确定订单是否重要)并粗略地将ssl_verify_depth
设置为捆绑中的证书数量。< / p>
答案 2 :(得分:2)
我相信您希望在服务器端启用客户端验证。如果是这样的话,我不会看到你的链中有你的客户证书。请按完全相同的顺序尝试以下操作。使用certchain.pem。
cat client.crt > certchain.pem
cat intermediate.crt >> certchain.pem
cat root.crt >> certchain.pem
答案 3 :(得分:2)
当我与nginx和cloudflare搏斗时, 这些线为我做了诀窍:
ssl_client_certificate /etc/nginx/ssl/ca-bundle-client.crt;
ssl_verify_client optional_no_ca;
ssl_verify_depth 2;
optional_no_ca 的第二行是重要的部分
答案 4 :(得分:1)
我必须说nginx/1.13.2
对我来说工作正常,即
我认为证书就像
cat client-intermediate1.crt ca-client.crt > ca.chained1.crt
和
cat client-intermediate2.crt ca-client.crt > ca.chained2.crt
和
cat ca.chained1.crt ca.chained2.crt > ca.multiple.intermediate.crt
如果我只将ca.chained1.crt作为ssl_client_certificate
,那么只有client1.crt可以连接,同样适用于ca.chained2.crt / client2.crt
ca.multiple.intermediate.crt
时,两个客户端都可以连接用于撤销中间件,只需从ca.multiple.intermediate.crt中删除证书链
这是相关的配置。它还具有高安全性设置
# minimum settings for ssl client auth
ssl_client_certificate /etc/ssl/ca.multiple.intermediate.crt;
ssl_verify_client on;
ssl_verify_depth 2;
# ssl high security settings (as of writing this post)
ssl_protocols TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_ecdh_curve secp384r1;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
如果要解析证书CN并将其传递给后端,则将此外部添加到server {..
块
# parse out CN
map $ssl_client_s_dn $ssl_client_s_dn_cn {
default "should_not_happen";
~CN=(?<CN>[^,]+) $CN;
}
然后在块中你可以使用它
# add headers for backend containing SSL DN/CN
add_header X-SSL-client-s-dn $ssl_client_s_dn;
add_header X-SSL-client-s-dn_cn $ssl_client_s_dn_cn;
答案 5 :(得分:0)
另一种简单的方法是在单个文件中连接证书(包括域证书)并在服务器和nginx配置文件中使用它
cat www.example.com.crt bundle.crt&gt; www.example.com.chained.crt
始终记住首先使用服务器证书,然后只使用CA服务器证书
您可以在http://nginx.org/en/docs/http/configuring_https_servers.html#chains
了解更多信息答案 6 :(得分:0)
ssl_verify_depth -> sets a verification depth in the client certificates chain
Authority提供了一堆链接的证书,这些证书应与已签名的服务器证书串联在一起。服务器证书必须出现在组合文件中链接证书的前面
'$ openssl s_client -connect www.godaddy.com:443
...
Certificate chain
0 s:/C=US/ST=Arizona/L=Scottsdale/1.3.6.1.4.1.311.60.2.1.3=US
/1.3.6.1.4.1.311.60.2.1.2=AZ/O=GoDaddy.com, Inc
/OU=MIS Department/CN=www.GoDaddy.com
/serialNumber=0796928-7/2.5.4.15=V1.0, Clause 5.(b)
i:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc.
/OU=http://certificates.godaddy.com/repository
/CN=Go Daddy Secure Certification Authority
/serialNumber=07969287
1 s:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc.
/OU=http://certificates.godaddy.com/repository
/CN=Go Daddy Secure Certification Authority
/serialNumber=07969287
i:/C=US/O=The Go Daddy Group, Inc.
/OU=Go Daddy Class 2 Certification Authority
2 s:/C=US/O=The Go Daddy Group, Inc.
/OU=Go Daddy Class 2 Certification Authority
i:/L=ValiCert Validation Network/O=ValiCert, Inc.
/OU=ValiCert Class 2 Policy Validation Authority
/CN=http://www.valicert.com//emailAddress=info@valicert.com'
在此示例中,www.GoDaddy.com服务器证书#0的主题(“ s”)由颁发者(“ i”)签名,而颁发者本身就是证书#1的主题,证书由#1签署。颁发者本身就是证书#2的主体,该证书由著名的颁发者ValiCert,Inc.签名,该证书的证书存储在浏览器的内置证书库中
Nginx使用ssl_verify_depth
指令深入到证书束中,以验证发布者在其受信任存储中的身份,该存储在proxy_ssl_trusted_certificate
中
答案 7 :(得分:0)
@Jack和@HansL(仅允许一个IntermediateCA1允许客户端使用的解决方案)是使用nginx config ssl_trusted_certificate。来自nginx documentation:
使用PEM格式指定具有受信任CA证书的文件,该证书用于 如果启用了ssl装订,请验证客户端证书和OCSP响应。 与ssl客户端证书设置的证书相反,这些列表 证书将不会发送给客户。
这些设置对我有用(但当然可以与其他PKI一起使用)。在第一个文件中,仅存在IntermediateCA1
。在后者中,只有RootCA
。
ssl_client_certificate /etc/nginx/ssl/ca-bundle-for-client-selection-filtering.crt;
ssl_trusted_certificate /etc/nginx/ssl/ca-bundle-for-client-cert-valdiation.crt;