hyper-rustls客户端是否不接受自签名证书?如何跳过证书校验
问题解答
1. 默认校验规则
hyper-rustls 默认会严格执行服务端TLS证书校验。你当前代码中使用了.with_native_roots()配置,该选项只会加载操作系统内置的受信任根证书列表,自签名证书的签发根CA不在这个信任列表中,自然会抛出UnknownIssuer的无效证书错误,这是组件默认的安全设计,不属于异常。
2. 浏览器、curl与客户端表现差异的原因
三者表现不一致完全是信任配置差异导致的:
- 浏览器可正常访问,是因为你此前已经手动点击过证书风险页的「继续访问」选项,将该自签名站点加入了浏览器的临时信任列表;或是你已经手动将自签名根CA导入了系统/浏览器的受信任根证书存储。
- curl可正常返回200,要么是你执行命令时携带了
-k/--insecure参数主动跳过了证书校验,要么是你已经将自签名根CA导入了系统信任库,curl默认读取系统根证书所以校验通过。 - 你写的测试客户端没有加载自定义的自签名根CA,也没有关闭校验,所以会直接抛出证书不信任错误。
3. 配置方法
(1)不安全模式:关闭证书校验(仅本地测试使用,禁止生产环境用)
该模式会完全跳过服务端证书有效性校验,存在中间人攻击风险,仅适合本地调试场景。
替换原有的连接器构建代码即可:
use std::sync::Arc; use rustls::client::{ServerCertVerifier, ServerCertVerified, HandshakeSignatureValid}; use rustls::{Certificate, ServerName, DigitallySignedStruct, Error as RustlsError}; // 实现空校验逻辑,直接返回校验通过 struct NoCheckCertVerifier; impl ServerCertVerifier for NoCheckCertVerifier { fn verify_server_cert( &self, _end_entity: &Certificate, _intermediates: &[Certificate], _server_name: &ServerName, _scts: &mut dyn Iterator<Item = &[u8]>, _ocsp_response: &[u8], _now: std::time::SystemTime, ) -> Result<ServerCertVerified, RustlsError> { Ok(ServerCertVerified::assertion()) } fn verify_tls12_signature( &self, _message: &[u8], _cert: &Certificate, _dss: &DigitallySignedStruct, ) -> Result<HandshakeSignatureValid, RustlsError> { Ok(HandshakeSignatureValid::assertion()) } fn verify_tls13_signature( &self, _message: &[u8], _cert: &Certificate, _dss: &DigitallySignedStruct, ) -> Result<HandshakeSignatureValid, RustlsError> { Ok(HandshakeSignatureValid::assertion()) } fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> { rustls::crypto::ring::default_provider() .signature_verification_algorithms .supported_schemes() } } // 构建自定义TLS配置 let tls_conf = rustls::ClientConfig::builder() .with_safe_defaults() .with_custom_certificate_verifier(Arc::new(NoCheckCertVerifier)) .with_no_client_auth(); let https = hyper_rustls::HttpsConnectorBuilder::new() .with_tls_config(tls_conf) .https_only() .enable_http1() .build(); let client: Client<_, hyper::Body> = Client::builder().build(https);
(2)安全模式:信任自定义自签名根CA(推荐)
不需要关闭证书校验,只需要把你自己签发证书用的根CA加入客户端的信任列表即可,兼顾安全性和可用性:
use std::fs::File; use std::io::BufReader; use rustls::RootCertStore; // 读取本地存储的自签名根CA证书(PEM格式) let ca_file = File::open("./your-self-signed-root-ca.crt").unwrap(); let mut ca_reader = BufReader::new(ca_file); let mut root_store = RootCertStore::empty(); for cert in rustls_pemfile::certs(&mut ca_reader).unwrap() { root_store.add(&rustls::Certificate(cert)).unwrap(); } // 构建带自定义根证书的TLS配置 let tls_conf = rustls::ClientConfig::builder() .with_safe_defaults() .with_root_certificates(root_store) .with_no_client_auth(); let https = hyper_rustls::HttpsConnectorBuilder::new() .with_tls_config(tls_conf) .https_only() .enable_http1() .build(); let client: Client<_, hyper::Body> = Client::builder().build(https);
内容的提问来源于stack exchange,提问作者yjlee
相关产品推荐
相关产品推荐

