我正在寻找SSL固定,并使用自行生成的证书来快速运行我们的api。
答案 0 :(得分:4)
这个问题没有足够的细节,所以这个答案基于一些假设:
package:http
用作http客户端 package:http
在后台使用dart:io HttpClient
,而HttpClient
具有多种功能可用于证书验证。由于客户端将不信任自签名服务器证书,因此客户端将调用badCertificateCallback
,让您自己验证服务器证书,例如:
HttpClient httpClient = new HttpClient()
..badCertificateCallback =
((X509Certificate cert, String host, int port) {
// tests that cert is self signed, correct subject and correct date(s)
return (cert.issuer == cert.subject &&
cert.subject == 'MySelfSignedCertCN' &&
cert.endValidity.millisecondsSinceEpoch == 1234567890);
});
IOClient ioClient = new IOClient(httpClient);
// use ioClient to perform get/post operations from package:http
// don't forget to call ioClient.close() when done
// note, this also closes the underlying HttpClient
答案 1 :(得分:1)
您可以使用SSL Pinning Plugin来执行此操作。只需将您的自签名证书指纹放在以下电话中即可:
await SslPinningPlugin.check(serverURL: url, headerHttp : new Map(), allowedSHA1Fingerprint: new List<String>, timeout : 50);
该呼叫返回:
答案 2 :(得分:0)
每年创建一个自签名证书,并使客户仅信任今年和去年的证书:
import 'dart:io'
show
BytesBuilder,
File,
HttpClient,
HttpClientRequest,
HttpClientResponse,
HttpHeaders,
HttpRequest,
HttpServer,
InternetAddress,
Process,
stderr,
stdout,
SecurityContext;
import 'dart:convert' show utf8;
Future<void> shellCommand(String command) async {
print('Executing command $command');
final Process process = await Process.start('sh', ['-c', command]);
stdout.addStream(process.stdout);
stderr.addStream(process.stderr);
final int exitCode = await process.exitCode;
if (exitCode != 0) {
throw new Exception('Process exited with status $exitCode');
}
}
void main() async {
// Last year's certificate:
await shellCommand(
'openssl req -newkey rsa:2048 -passout pass:password -keyout privatekey2018.pem -subj "/CN=localhost" -days 731 -x509 -out certificate2018.pem');
// This year's certificate:
await shellCommand(
'openssl req -newkey rsa:2048 -passout pass:password -keyout privatekey2019.pem -subj "/CN=localhost" -days 731 -x509 -out certificate2019.pem');
final SecurityContext serverSecurityContext = new SecurityContext();
serverSecurityContext.useCertificateChainBytes(
await new File('certificate2019.pem').readAsBytes());
serverSecurityContext.usePrivateKey('privatekey2019.pem',
password: 'password');
final HttpServer httpServer = await HttpServer.bindSecure(
InternetAddress.loopbackIPv4, 0, serverSecurityContext);
httpServer.listen((HttpRequest request) {
request.response.write('body1');
request.response.close();
});
print('Server listening at https://localhost:${httpServer.port}/');
print('Making request.');
final SecurityContext clientSecurityContext =
new SecurityContext(withTrustedRoots: false);
clientSecurityContext.setTrustedCertificatesBytes(
await new File('certificate2018.pem').readAsBytes());
clientSecurityContext.setTrustedCertificatesBytes(
await new File('certificate2019.pem').readAsBytes());
final HttpClient httpClient = new HttpClient(context: clientSecurityContext);
final HttpClientRequest request = await httpClient.getUrl(Uri(
scheme: 'https', host: 'localhost', port: httpServer.port, path: '/'));
final HttpClientResponse response = await request.close();
final List<int> bytes = await response.fold(new BytesBuilder(),
(BytesBuilder bytesBuilder, List<int> bytes) {
bytesBuilder.add(bytes);
return bytesBuilder;
}).then((BytesBuilder bytesBuilder) => bytesBuilder.takeBytes());
final String contenType =
response.headers.value(HttpHeaders.contentTypeHeader) ?? '';
print('${response.statusCode} ${response.reasonPhrase} '
'content-type="$contenType" body="${utf8.decode(bytes)}"');
httpServer.close(force: true);
}
创建自签名证书,并使客户端仅信任那些证书,并忽略请求中的主机名。当使用Terraform将服务器部署到AWS Elastic Beanstalk时,这很有用。服务器二进制Blob必须包含证书,但是直到部署完成才知道服务器的主机名。
import 'dart:io'
show
BytesBuilder,
File,
HttpClient,
HttpClientRequest,
HttpClientResponse,
HttpHeaders,
HttpRequest,
HttpServer,
InternetAddress,
Process,
stderr,
stdout,
SecurityContext,
X509Certificate;
import 'dart:convert' show utf8;
Future<void> shellCommand(String command) async {
print('Executing command $command');
final Process process = await Process.start('sh', ['-c', command]);
stdout.addStream(process.stdout);
stderr.addStream(process.stderr);
final int exitCode = await process.exitCode;
if (exitCode != 0) {
throw new Exception('Process exited with status $exitCode');
}
}
void main() async {
// Last year's certificate:
await shellCommand(
'openssl req -newkey rsa:2048 -passout pass:password -keyout privatekey2018.pem -subj "/CN=localhost" -days 731 -x509 -out certificate2018.pem');
// This year's certificate:
await shellCommand(
'openssl req -newkey rsa:2048 -passout pass:password -keyout privatekey2019.pem -subj "/CN=localhost" -days 731 -x509 -out certificate2019.pem');
final SecurityContext serverSecurityContext = new SecurityContext();
serverSecurityContext.useCertificateChainBytes(
await new File('certificate2019.pem').readAsBytes());
serverSecurityContext.usePrivateKey('privatekey2019.pem',
password: 'password');
final HttpServer httpServer = await HttpServer.bindSecure(
InternetAddress.loopbackIPv4, 0, serverSecurityContext);
httpServer.listen((HttpRequest request) {
request.response.write('body1');
request.response.close();
});
print('Server listening at https://localhost:${httpServer.port}/');
print('Making request.');
final SecurityContext clientSecurityContext =
new SecurityContext(withTrustedRoots: false);
final HttpClient httpClient = new HttpClient(context: clientSecurityContext);
final List<String> certificatePemStrings = [
await new File('certificate2018.pem').readAsString(),
await new File('certificate2019.pem').readAsString()
];
httpClient.badCertificateCallback =
(X509Certificate cert, String host, int port) => certificatePemStrings
.any((certificatePemString) => cert.pem == certificatePemString);
final HttpClientRequest request = await httpClient.getUrl(Uri(
scheme: 'https', host: 'localhost', port: httpServer.port, path: '/'));
final HttpClientResponse response = await request.close();
final List<int> bytes = await response.fold(new BytesBuilder(),
(BytesBuilder bytesBuilder, List<int> bytes) {
bytesBuilder.add(bytes);
return bytesBuilder;
}).then((BytesBuilder bytesBuilder) => bytesBuilder.takeBytes());
final String contenType =
response.headers.value(HttpHeaders.contentTypeHeader) ?? '';
print('${response.statusCode} ${response.reasonPhrase} '
'content-type="$contenType" body="${utf8.decode(bytes)}"');
httpServer.close(force: true);
}
在安全的笔记本电脑上创建证书颁发机构文件,并将其保存在安全的可移动驱动器中。每当需要新证书时,请获取可移动驱动器并生成并签署新服务器证书。这是运行openssl
命令的示例,以及如何将Dart配置为仅信任由证书颁发机构签名的证书:
import 'dart:io'
show
BytesBuilder,
File,
HttpClient,
HttpClientRequest,
HttpClientResponse,
HttpHeaders,
HttpRequest,
HttpServer,
InternetAddress,
Process,
SecurityContext,
stderr,
stdout;
import 'dart:convert' show utf8;
Future<void> shellCommand(String command) async {
print('Executing command $command');
final Process process = await Process.start('sh', ['-c', command]);
stdout.addStream(process.stdout);
stderr.addStream(process.stderr);
final int exitCode = await process.exitCode;
if (exitCode != 0) {
throw new Exception('Process exited with status $exitCode');
}
}
void main() async {
// Last year's certificates:
await shellCommand(
'openssl req -newkey rsa:2048 -nodes -keyout ca2018.privatekey.pem -subj "/OU=CA" -days 731 -x509 -out ca2018.certificate.pem');
// This year's certificates:
await shellCommand(
'openssl req -newkey rsa:2048 -nodes -keyout ca2019.privatekey.pem -subj "/OU=CA" -days 731 -x509 -out ca2019.certificate.pem');
await shellCommand(
'openssl req -newkey rsa:2048 -passout pass:password -keyout privatekey.pem -subj "/CN=localhost" -days 731 -sha256 -new -out csr2019.pem');
await shellCommand(
'openssl x509 -req -in csr2019.pem -CA ca2019.certificate.pem -CAkey ca2019.privatekey.pem -set_serial 1 -days 730 -sha256 -out certificate2019.pem');
await shellCommand(
'cat certificate2019.pem ca2019.certificate.pem > certificate2019.chain.pem');
final SecurityContext serverSecurityContext = new SecurityContext();
serverSecurityContext.useCertificateChainBytes(
await new File('certificate2019.chain.pem').readAsBytes());
serverSecurityContext.usePrivateKey('privatekey.pem', password: 'password');
final HttpServer httpServer = await HttpServer.bindSecure(
InternetAddress.loopbackIPv4, 0, serverSecurityContext);
httpServer.listen((HttpRequest request) {
request.response.write('body1');
request.response.close();
});
print('Server listening at https://localhost:${httpServer.port}/');
print('Making request.');
final SecurityContext clientSecurityContext =
new SecurityContext(withTrustedRoots: false);
clientSecurityContext.setTrustedCertificatesBytes(
await new File('ca2018.certificate.pem').readAsBytes());
clientSecurityContext.setTrustedCertificatesBytes(
await new File('ca2019.certificate.pem').readAsBytes());
final HttpClient httpClient = new HttpClient(context: clientSecurityContext);
final HttpClientRequest request = await httpClient.getUrl(Uri(
scheme: 'https', host: 'localhost', port: httpServer.port, path: '/'));
final HttpClientResponse response = await request.close();
final List<int> bytes = await response.fold(new BytesBuilder(),
(BytesBuilder bytesBuilder, List<int> bytes) {
bytesBuilder.add(bytes);
return bytesBuilder;
}).then((BytesBuilder bytesBuilder) => bytesBuilder.takeBytes());
final String contenType =
response.headers.value(HttpHeaders.contentTypeHeader) ?? '';
print('${response.statusCode} ${response.reasonPhrase} '
'content-type="$contenType" body="${utf8.decode(bytes)}"');
httpServer.close(force: true);
}
答案 3 :(得分:-1)
您可以使用此lib:
https://pub.dev/packages/http_certificate_pinning
具有用于DIO的拦截器和用于HTTP的客户端
// Add CertificatePinningInterceptor in dio Client
Dio getClient(String baseUrl, List<String> allowedSHAFingerprints){
var dio = Dio(BaseOptions(baseUrl: baseUrl))
..interceptors.add(CertificatePinningInterceptor(allowedSHAFingerprints));
return dio;
}
```