导读:本期聚焦于高宇创作的《Nginx如何配置客户端证书吊销列表CRL实现双向认证安全控制?》,敬请观看详情。客户端证书被泄露或者员工离职后,怎么让原本签发的证书立刻失效?答案就是证书吊销列表CRL。本文围绕Nginx的双向认证场景,详细讲解CRL的工作原理、吊销列表文件的生成方法,以及在Nginx中通过ssl_crl指令加载CRL完成客户端证书状态校验的完整流程。文中还介绍了如何用OpenSSL命令签发CA、签发客户端证书、执行证书吊销、更新CRL文件,并配合ssl_client_verify变量和error_page做精细化访问控制,最后补充了CRL过期报错的排查思路与reload注意事项,帮助你在生产环境搭建一套可控的双向认证体系。

在做基于客户端证书的双向认证(mTLS)时,很多团队都会遇到一个现实问题:某张客户端证书泄露了,或者持有人已经离职,但证书本身还没到期,CA签发时的有效期是一年甚至三年。这种情况下如果Nginx端只校验证书链的有效性,这张"问题证书"依然可以畅通无阻地访问服务。要解决这个问题,就需要引入证书吊销列表CRL(Certificate Revocation List),让Nginx在校验客户端证书时同时检查它是否已被吊销。本文从原理到实操,完整走一遍整个流程。

Nginx如何配置客户端证书吊销列表CRL实现双向认证安全控制?

CRL的工作原理与双向认证的关系

先厘清概念。双向认证指的是服务端除了出示自己的证书给客户端验证,还要求客户端出示证书,由服务端验证客户端身份。在Nginx中,这通过ssl_verify_client on开启。开启之后,Nginx会做几层校验:证书是否由受信任的CA签发、证书链是否完整、证书是否在有效期内,以及这张证书是否出现在吊销列表中。

CRL本质上是一份由CA定期签署发布的"黑名单"文件,里面记录了已被吊销的证书序列号。因为CRL是CA用私钥签名的,所以不能被伪造篡改。Nginx收到客户端证书后,会把证书中的序列号和CRL里的记录比对,一旦命中就拒绝连接。Nginx使用的是OpenSSL的校验逻辑,对应的指令是ssl_crl,它指向一个PEM格式的CRL文件。

需要注意一点:CRL文件本身也有有效期(nextUpdate字段)。如果CA生成CRL时设定的更新周期过了,Nginx校验会直接报错"CRL has expired",导致所有客户端证书校验失败,这一点在后面排查小节会详细说。

用OpenSSL搭建测试CA并签发客户端证书

为了演示完整流程,先用OpenSSL自建一个CA。创建必要的目录结构和索引文件:

mkdir -p ./demoCA/{certs,crl,newcerts,private}
touch ./demoCA/index.txt
echo 1000 > ./demoCA/serial
# 生成CA私钥和自签证书
openssl genrsa -out ca.key 2048
openssl req -new -x509 -days 3650 -key ca.key -out ca.crt \
  -subj "/C=CN/ST=BJ/O=Demo/CN=DemoCA"

接着签发一张客户端证书,模拟正常用户的身份:

openssl genrsa -out client1.key 2048
openssl req -new -key client1.key -out client1.csr \
  -subj "/C=CN/ST=BJ/O=Demo/CN=client1"
openssl ca -in client1.csr -out client1.crt -cert ca.crt -keyfile ca.key \
  -config /etc/ssl/openssl.cnf -days 365

openssl ca方式签发的好处是,CA数据库(index.txt)会自动记录证书状态,后面吊销时直接依赖这个数据库。如果图省事用openssl x509 -req签发,吊销环节就会缺少数据库记录,操作会麻烦很多,这一点新手经常踩坑。

执行证书吊销并生成CRL文件

假设client1这张证书需要作废,执行吊销命令:

openssl ca -revoke client1.crt -cert ca.crt -keyfile ca.key \
  -config /etc/ssl/openssl.cnf

执行成功后,index.txt中该证书对应行的状态会从V(有效)变成R(已吊销)。然后生成CRL文件,注意-crldays参数决定了CRL的有效期:

openssl ca -gencrl -out ca.crl -cert ca.crt -keyfile ca.key \
  -config /etc/ssl/openssl.cnf -crldays 30

生成的ca.crl是PEM格式的文本文件,Nginx的ssl_crl指令要求PEM格式,所以可以直接使用。可以用下面的命令查看CRL内容确认吊销记录:

openssl crl -in ca.crl -noout -text

输出中会看到Serial Number字段列出了被吊销证书的序列号,还有Next Update时间。这里有个关键决策:crldays设多长?设得太短,比如1天,意味着你必须每天重新生成并更新CRL文件,运维压力大;设得太长,比如365天,证书泄露后到CRL刷新之间的暴露窗口并没有缩短,但好处是容错高。一般生产环境建议7到30天,再配合自动化脚本定期重新生成CRL并reload Nginx。

Nginx配置ssl_crl完成吊销校验

下面是完整的Nginx server配置,同时开启了双向认证和CRL校验:

server {
    listen 443 ssl;
    server_name mtls.demo.ipipp.com;

    # 服务端证书
    ssl_certificate     /etc/nginx/ssl/server.crt;
    ssl_certificate_key /etc/nginx/ssl/server.key;

    # 要求客户端出示证书,并指定信任的CA
    ssl_client_certificate /etc/nginx/ssl/ca.crt;
    ssl_verify_client on;
    ssl_verify_depth 2;

    # 关键指令:加载CRL吊销列表
    ssl_crl /etc/nginx/ssl/ca.crl;

    location / {
        # $ssl_client_verify值为SUCCESS/FAILED/NONE
        if ($ssl_client_verify != SUCCESS) {
            return 403;
        }
        proxy_pass http://127.0.0.1:8080;
    }
}

几个要点值得展开。第一,ssl_crl指定的文件必须是PEM格式,如果拿到的是DER格式的CRL(二进制),需要转换:openssl crl -in ca.der -inform DER -out ca.pem。第二,配置了ssl_crl之后,只要CRL文件存在,所有证书都会被检查吊销状态,包括尚未被吊销的正常证书,这属于全量校验,不是只针对黑名单里的证书。

第三,可以利用$ssl_client_verify这个内置变量做更细的控制,比如对未携带证书的请求返回自定义页面而不是默认的400错误:

error_page 495 = @no_cert;
error_page 496 = @invalid_cert;

location @no_cert {
    return 403 '{"code":40301,"msg":"client certificate required"}';
}

location @invalid_cert {
    return 403 '{"code":40302,"msg":"client certificate invalid or revoked"}';
}

其中495是Nginx内置的"证书校验失败"状态码,496是"未提供证书"。被CRL命中的证书会触发495,通过这种方式能明确区分错误类型,方便客户端排查问题。

常见问题排查与生产实践建议

最经典的报错是握手阶段直接失败,Nginx的error日志里出现"certificate revoked"字样,这其实说明CRL校验生效了,属于预期行为。但如果日志里出现"CRL has expired",说明CRL文件过了Next Update时间,此时OpenSSL会认为整个吊销列表不可信,所有客户端证书校验都会失败。解决办法是重新生成CRL并reload Nginx。生产上强烈建议用crontab加一个自动任务:

#!/bin/bash
# 每周重新生成CRL并平滑重载Nginx
openssl ca -gencrl -out /etc/nginx/ssl/ca.crl.new \
  -cert /path/ca.crt -keyfile /path/ca.key \
  -config /etc/ssl/openssl.cnf -crldays 30
mv /etc/nginx/ssl/ca.crl.new /etc/nginx/ssl/ca.crl
nginx -t && nginx -s reload

注意生成到临时文件再mv替换,避免Nginx读取到写了一半的文件。另外要提醒的是,nginx -s reload并不会中断现有连接,新配置对新连接生效,所以更新CRL不会影响线上正在进行的请求。

还有一点容易被忽略:如果你的CA层级比较深,比如根CA下面有中间CA,客户端证书由中间CA签发,那么ssl_crl文件中需要包含整条链上所有CA的CRL,把多个CRL的PEM内容直接拼接在一个文件里即可,OpenSSL会按签发者自动匹配。同时ssl_verify_depth要设置得足够大,覆盖完整的证书链深度,否则校验会在链的中间环节就中断。

最后对比一下CRL和OCSP。CRL是定期下载的静态名单,实现简单、不依赖额外网络交互,适合客户端规模可控的内部系统;OCSP是实时查询,及时性更好,但需要维护响应服务。对于Nginx的双向认证场景,客户端证书数量通常有限,CRL方案部署成本最低、稳定性最好,是大多数内部mTLS体系的首选。如果将来规模扩大或者对吊销实时性要求极高,再考虑迁移到OCSP或短周期证书方案也不迟。

Nginx双向认证证书吊销列表CRLSSL证书配置修改时间:2026-09-12 23:54:40

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/20260912/55633.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。