如何在Django View中查看传入请求的SSL证书内容?
在Django View中获取并验证请求方SSL证书的方法
要实现这个需求,核心是两步:让Web服务器将客户端证书信息传递给Django,然后在View中提取并验证证书。
前提配置:让反向代理传递客户端证书
生产环境中,Django通常搭配Nginx/Apache这类反向代理处理SSL请求。你需要配置反向代理:
- 要求客户端在建立SSL连接时提供证书
- 将客户端证书的PEM格式内容通过HTTP请求头传递给Django
以Nginx为例,添加以下配置:
server { listen 443 ssl; server_name your-api-domain.com; # 配置服务器证书 ssl_certificate /path/to/your/server.crt; ssl_certificate_key /path/to/your/server.key; # 要求客户端提供证书,并指定信任的CA证书 ssl_client_certificate /path/to/your/trusted-ca.crt; ssl_verify_client on; # 将客户端证书传递给Django location / { proxy_pass http://your-django-server:8000; proxy_set_header SSL_CLIENT_CERT $ssl_client_cert; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }
在Django View中获取并验证证书
配置完成后,客户端证书会以PEM格式字符串的形式出现在request.META中,对应的键是HTTP_SSL_CLIENT_CERT(反向代理的请求头会被WSGI转换为大写并添加HTTP_前缀)。
示例View代码:
from django.http import HttpResponseForbidden, HttpResponse from cryptography import x509 from cryptography.hazmat.backends import default_backend import datetime def validated_post_endpoint(request): if request.method != "POST": return HttpResponseForbidden("Only POST requests are allowed") # 提取客户端证书 cert_pem = request.META.get("HTTP_SSL_CLIENT_CERT") if not cert_pem: return HttpResponseForbidden("No client certificate provided") try: # 解析PEM格式证书 cert = x509.load_pem_x509_certificate(cert_pem.encode(), default_backend()) # 1. 验证证书由信任的CA签发 with open("/path/to/your/trusted-ca.crt", "rb") as ca_file: ca_cert = x509.load_pem_x509_certificate(ca_file.read(), default_backend()) cert.verify_directly_issued_by(ca_cert) # 2. 验证证书有效期 now = datetime.datetime.now(datetime.timezone.utc) if not (cert.not_valid_before <= now <= cert.not_valid_after): return HttpResponseForbidden("Certificate has expired or is not yet valid") # 3. 验证证书主题(比如检查CN是否为指定服务器) common_name = cert.subject.get_attributes_for_oid(x509.NameOID.COMMON_NAME)[0].value if common_name != "authorized-server.example.com": return HttpResponseForbidden("Invalid certificate subject") except Exception as e: return HttpResponseForbidden(f"Certificate validation failed: {str(e)}") # 证书验证通过,处理POST请求业务逻辑 # ... 你的业务代码 ... return HttpResponse("Request authenticated successfully")
关键注意事项
- 生产环境禁止用Django自带runserver处理SSL:runserver仅用于开发,必须用反向代理处理SSL连接。
- 不要仅检查证书存在:必须验证证书的签发机构、有效期、主题等核心信息,防止伪造证书绕过验证。
- 依赖
cryptography库:需要先执行pip install cryptography安装证书解析和验证工具。
内容的提问来源于stack exchange,提问作者AmrElsayed
相关产品推荐
相关产品推荐

