如何在 flutter/dart 中执行 SSL public 键固定?
How to do SSL public key pinning in flutter/dart?
这里是 Flutter 的新手(以及一般的编程)。只熟悉更基本的东西,但我现在遇到了使用 CertificatePinner 的需要,例如 flutter/dart:
https://square.github.io/okhttp/3.x/okhttp/okhttp3/CertificatePinner.html(我在之前 kotlin/java 工作室的 kotlin/java 项目中成功实现了这一点)。 我的目标是固定 public 密钥(不是证书)
我只有 public 字符串形式的键,如下所示,没有别的:
"sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
我该如何实现这一目标?我已经在 github 上的一个未决问题中提出这个问题,但还没有得到任何答复 (https://github.com/dart-lang/sdk/issues/35981)。希望有人已经设法实现这一目标。
我还搜索了其他来源。我认为对我来说最接近解决方案的是
但我不太明白那里正在做什么,我不能发表评论在那里提问,因为我还没有足够的声誉。
为了比较,我想做的就是在 flutter/dart 中使用以下几行代码实现我在 java/kotlin 中可以实现的相同目标:
String hostname = "publicobject.com";
CertificatePinner certificatePinner = new CertificatePinner.Builder()
.add(hostname, "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")
.build();
感谢您的帮助
从您引用的答案中的代码开始。获取 DER 格式的证书并开始对其进行解码。
ASN1Parser p = ASN1Parser(der);
ASN1Sequence signedCert = p.nextObject() as ASN1Sequence;
ASN1Sequence cert = signedCert.elements[0] as ASN1Sequence;
ASN1Sequence pubKeyElement = cert.elements[6] as ASN1Sequence;
// this is the Subject Public Key element, which describes the type of key and actual value
例如,如果我们解码pub.dev
的证书,我们发现它是一个模数为65537,值为2347的RSA密钥......:
SEQUENCE (2 elem)
SEQUENCE (2 elem)
OBJECT IDENTIFIER 1.2.840.113549.1.1.1 rsaEncryption (PKCS #1)
NULL
BIT STRING (1 elem)
SEQUENCE (2 elem)
INTEGER (2048 bit) 234782553149463204049153749736864715384123240676730175743244004248041…
INTEGER 65537
根据 RFC,SPKI 指纹是整个元素的 SHA-256 哈希值。
// you need to import dart:convert and package:crypto/crypto.dart
var hash = base64.encode(sha256.convert(pubKeyElement.contentBytes()).bytes);
var spkiFingerprint = 'sha256/$hash'; // should match the value you have
注意事项
badCertificateCallback
不会提供整个证书链,因此您无法遍历整个链。更糟糕的是,它似乎并不总是提供叶子证书!有时它会提供中间证书。
这里是 Flutter 的新手(以及一般的编程)。只熟悉更基本的东西,但我现在遇到了使用 CertificatePinner 的需要,例如 flutter/dart: https://square.github.io/okhttp/3.x/okhttp/okhttp3/CertificatePinner.html(我在之前 kotlin/java 工作室的 kotlin/java 项目中成功实现了这一点)。 我的目标是固定 public 密钥(不是证书)
我只有 public 字符串形式的键,如下所示,没有别的:
"sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
我该如何实现这一目标?我已经在 github 上的一个未决问题中提出这个问题,但还没有得到任何答复 (https://github.com/dart-lang/sdk/issues/35981)。希望有人已经设法实现这一目标。
我还搜索了其他来源。我认为对我来说最接近解决方案的是
为了比较,我想做的就是在 flutter/dart 中使用以下几行代码实现我在 java/kotlin 中可以实现的相同目标:
String hostname = "publicobject.com";
CertificatePinner certificatePinner = new CertificatePinner.Builder()
.add(hostname, "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")
.build();
感谢您的帮助
从您引用的答案中的代码开始。获取 DER 格式的证书并开始对其进行解码。
ASN1Parser p = ASN1Parser(der);
ASN1Sequence signedCert = p.nextObject() as ASN1Sequence;
ASN1Sequence cert = signedCert.elements[0] as ASN1Sequence;
ASN1Sequence pubKeyElement = cert.elements[6] as ASN1Sequence;
// this is the Subject Public Key element, which describes the type of key and actual value
例如,如果我们解码pub.dev
的证书,我们发现它是一个模数为65537,值为2347的RSA密钥......:
SEQUENCE (2 elem)
SEQUENCE (2 elem)
OBJECT IDENTIFIER 1.2.840.113549.1.1.1 rsaEncryption (PKCS #1)
NULL
BIT STRING (1 elem)
SEQUENCE (2 elem)
INTEGER (2048 bit) 234782553149463204049153749736864715384123240676730175743244004248041…
INTEGER 65537
根据 RFC,SPKI 指纹是整个元素的 SHA-256 哈希值。
// you need to import dart:convert and package:crypto/crypto.dart
var hash = base64.encode(sha256.convert(pubKeyElement.contentBytes()).bytes);
var spkiFingerprint = 'sha256/$hash'; // should match the value you have
注意事项
badCertificateCallback
不会提供整个证书链,因此您无法遍历整个链。更糟糕的是,它似乎并不总是提供叶子证书!有时它会提供中间证书。