搭建本地网站环境,做公司网站哪里好,门户网站建设主要内容,网站管理系统模板前言 Flutter项目中服务器使用了自签名证书#xff0c;如果直接使用https请求或者wss请求的话会报证书签名错误。
HandshakeException: Handshake error in client (OS Error: I/flutter (28959): │ #x1f4a1; CERTIFICATE_VERIFY_FAILED: unable to get local issuer c…前言 Flutter项目中服务器使用了自签名证书如果直接使用https请求或者wss请求的话会报证书签名错误。
HandshakeException: Handshake error in client (OS Error: I/flutter (28959): │ CERTIFICATE_VERIFY_FAILED: unable to get local issuer certificate(handshake.cc:359))
或者
CERTIFICATE_VERIFY_FAILED: self signed certificate in certificate chain(handshake.cc:354)) 信任自签名证书 1.忽略证书校验 你可以通过以下步骤忽略证书验证。从而接受自签名证书
首先创建一个class 重写HttpOverrides
class MyHttpOverrides extends HttpOverrides {overrideHttpClient createHttpClient(SecurityContext context) {return super.createHttpClient(context)..badCertificateCallback (X509Certificate cert, String host, int port) {//add your certificate verification logic herereturn true;};}
}然后在main 方法将MyHttpOverrides 设置成全局的HttpOverrides。
HttpOverrides.global new DevHttpOverrides(); 当系统检测证书有问题时会通过回调badCertificateCallback让我们有机会接受或拒绝这个错误的证书当返回true时表示我们接受这个证书会继续完成通讯请求当返回false时表示我们不接受错误的证书https通讯将失败。
当然你也可以在badCertificateCallback添加自己的证书校验逻辑。强烈不建议在正式环境将badCertificateCallback直接返回true因为这样会接受所有的证书相当于SSL加密层形同虚设很容易造成中间人攻击。
2.使用本地CA根证书验证服务器证书 我们可以将服务器用来生成自签名证书的CA证书放在本地设置为受信任的证书然后用这个证书校验服务器证书。代码如下
class MyHttpOverrides extends HttpOverrides {overrideHttpClient createHttpClient(SecurityContext context) {//加载本地根证书ByteData data await rootBundle.load(assets/data/ca-cert.pem);final SecurityContext clientContext SecurityContext()//使用此方法设置受信任根证书..setTrustedCertificatesBytes(data.buffer.asUint8List())return super.createHttpClient(context)..badCertificateCallback (X509Certificate cert, String host, int port) {//add your certificate verification logic herereturn false;};}
}这种方式能极大提高安全性。
常见问题 CERTIFICATE_VERIFY_FAILED: Hostname mismatch
Flutter ssl默认会检测证书 subject 中的CN字段和请求url 中的host 是否一致。 如果不一致会报这个错误。
如果请求的url时https://baidu.com/tanslate , 那么服务器的证书CN字段必须包含Baidu.com。
很可惜目前基于flutter3.0 没有提供相应的API 去忽略hostname 检测我们能做的就是在badCertificateCallback 添加自己的校验逻辑如下 ..badCertificateCallback (X509Certificate cert, String host, int port) {if(hostbaidu.com)return true;else return false;};2.本地CA根证书验证服务器证书时当服务器证书的签名不对时会回调到badCertificateCallback, 而其他证书错误也会回调到badCertificateCallback, 如果要如何区分不同的证书错误原因则需要手动去校验证书的签名等信息。
class MyHttpOverrides extends HttpOverrides {MyHttpOverrides() {}overrideHttpClient createHttpClient(SecurityContext? context) {ByteData data await rootBundle.load(assets/data/ca-cert.pem);final SecurityContext clientContext SecurityContext()..setTrustedCertificatesBytes(caCertificate);return super.createHttpClient(clientContext)..badCertificateCallback (X509Certificate cert, String host, int port) //根据根证书校验服务器证书bool isverify verifyCertificate(ca_cert, cert.pem);if (!isverify){//签名错误return false;}if (currentIp ! host) {return false;} else {return true;}};}
}其中verifyCertificate 方法如下用到了x509这个package。传送门
import dart:convert;
import dart:typed_data;
import package:x509b/x509.dart as x509;
import package:asn1lib/asn1lib.dart;import flutter_log.dart;bool verifyCertificate(String caCert, String serverCert) {// var strX1PublicKeyInfo -----BEGIN CERTIFICATE-----\nSOME PUBLIC KEY\n-----END CERTIFICATE-----;// var strX2Certificate -----BEGIN CERTIFICATE-----\nSOME CERTIFICATE\n-----END CERTIFICATE-----;var x1PublicKey (x509.parsePem(caCert).single as x509.X509Certificate).publicKey as x509.RsaPublicKey;var x2Certificate x509.parsePem(serverCert).single as x509.X509Certificate;var x2CertificateDER decodePEM(serverCert);var asn1Parser ASN1Parser(x2CertificateDER);var seq asn1Parser.nextObject() as ASN1Sequence;var tbsSequence seq.elements[0] as ASN1Sequence;var signature x509.Signature(Uint8List.fromList(x2Certificate.signatureValue!));var verifier x1PublicKey.createVerifier(x509.algorithms.signing.rsa.sha256);return verifier.verify(tbsSequence.encodedBytes, signature);
}Uint8List decodePEM(String pem) {var startsWith [-----BEGIN PUBLIC KEY-----,-----BEGIN PRIVATE KEY-----,-----BEGIN CERTIFICATE-----,];var endsWith [-----END PUBLIC KEY-----,-----END PRIVATE KEY-----,-----END CERTIFICATE-----];pempem.trim();//HACKfor (var s in startsWith) {if (pem.startsWith(s)) pem pem.substring(s.length);}for (var s in endsWith) {if (pem.trim().endsWith(s)) {Log().i(certificate:substring);pem pem.trim().split(s)[0];}}//Dart base64 decoder does not support line breakspem pem.replaceAll(\n, );pem pem.replaceAll(\r, );return Uint8List.fromList(base64.decode(pem));
}作者星辰大海TT 链接https://www.jianshu.com/p/5dfb882671a3