Flutter公钥固定插件public_key_pinning的使用
Flutter公钥固定插件public_key_pinning的使用
Https证书固定(Certificate Pinning)在Flutter中的实现可以通过public_key_pinning插件来完成。本文将介绍如何在Flutter项目中使用此插件,并提供完整的示例代码。
1. 添加依赖
在你的Flutter或Dart项目中添加以下依赖:
dependencies:
...
public_key_pinning: ^2.1.3
执行flutter pub get以安装依赖。
2. 获取证书指纹
要获取服务器SSL证书的SHA256指纹,可以在终端运行以下命令:
openssl x509 -noout -fingerprint -sha256 -inform pem -in [certificate-file.crt]
例如,结果可能类似于:
'59:58:57:5A:5B:5C:5D:59:58:57:5A:5B:5C:5D:59:58:57:5A:5B:5C:5D:59:58:57:5A:5B:5C:5D:59:58:57:5A:5B:5C:5D'
3. 使用示例
3.1 使用Dio库
通过CertificatePinningInterceptor拦截器来实现证书固定:
import 'package:dio/dio.dart';
import 'package:public_key_pinning/public_key_pinning.dart';
// 配置Dio客户端并添加证书固定拦截器
Dio getClient(String baseUrl, List<String> allowedSHAFingerprints) {
var dio = Dio(BaseOptions(baseUrl: baseUrl))
..interceptors.add(CertificatePinningInterceptor(allowedSHAFingerprints));
return dio;
}
void myRepositoryMethod() {
final dio = getClient("https://example.com", [
"59:58:57:5A:5B:5C:5D:59:58:57:5A:5B:5C:5D:59:58:57:5A:5B:5C:5D:59:58:57:5A:5B:5C:5D:59:58:57:5A:5B:5C:5D"
]);
dio.get("/api/data").then((response) {
print(response.data);
}).catchError((error) {
print(error);
});
}
3.2 使用Http库
通过SecureHttpClient来实现证书固定:
import 'package:http/http.dart' as http;
import 'package:public_key_pinning/secure_http_client.dart';
// 配置安全HTTP客户端
SecureHttpClient getClient(List<String> allowedSHAFingerprints) {
final secureClient = SecureHttpClient.build(allowedSHAFingerprints);
return secureClient;
}
void myRepositoryMethod() {
final secureClient = getClient([
"59:58:57:5A:5B:5C:5D:59:58:57:5A:5B:5C:5D:59:58:57:5A:5B:5C:5D:59:58:57:5A:5B:5C:5D:59:58:57:5A:5B:5C:5D"
]);
secureClient.get("https://example.com/api/data").then((response) {
print(response.body);
}).catchError((error) {
print(error);
});
}
3.3 自定义实现
如果你使用的是其他HTTP客户端,可以调用HttpCertificatePinning.check方法进行证书固定检查:
import 'package:public_key_pinning/public_key_pinning.dart';
Future<bool> myCustomImplementation(String url, Map<String, String> headers, List<String> allowedSHAFingerprints) async {
try {
final secure = await HttpCertificatePinning.check(
serverURL: url,
headerHttp: headers,
sha: SHA.SHA256,
allowedSHAFingerprints: allowedSHAFingerprints,
timeout: 50,
);
if (secure.contains("CONNECTION_SECURE")) {
return true;
} else {
return false;
}
} catch (e) {
return false;
}
}
4. 完整示例代码
以下是一个完整的示例代码,展示如何在Flutter应用中使用public_key_pinning插件:
import 'package:flutter/material.dart';
import 'package:public_key_pinning/public_key_pinning.dart';
void main() => runApp(const MyApp());
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
[@override](/user/override)
_MyAppState createState() => _MyAppState();
}
class _PiningSslData {
String serverURL = '';
Map<String, String> headerHttp = {};
String allowedSHAFingerprint = '';
int timeout = 0;
SHA? sha;
}
class _MyAppState extends State<MyApp> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final _PiningSslData _data = _PiningSslData();
final _messengerKey = GlobalKey<ScaffoldMessengerState>();
[@override](/user/override)
initState() {
super.initState();
}
// 检查证书固定
check(
String url,
String fingerprint,
SHA sha,
Map<String, String> headerHttp,
int timeout,
) async {
List<String> allowedShA1FingerprintList = [];
allowedShA1FingerprintList.add(fingerprint);
try {
String checkMsg = await HttpCertificatePinning.check(
serverURL: url,
headerHttp: headerHttp,
sha: sha,
allowedSHAFingerprints: allowedShA1FingerprintList,
timeout: timeout,
);
if (!mounted) return;
_messengerKey.currentState?.showSnackBar(
SnackBar(
content: Text(checkMsg),
duration: const Duration(seconds: 1),
backgroundColor: Colors.green,
),
);
} catch (e) {
_messengerKey.currentState?.showSnackBar(
SnackBar(
content: Text(e.toString()),
duration: const Duration(seconds: 1),
backgroundColor: Colors.red,
),
);
}
}
void submit() {
if (_formKey.currentState?.validate() == true) {
_formKey.currentState?.save();
check(
_data.serverURL,
_data.allowedSHAFingerprint,
_data.sha ?? SHA.SHA256,
_data.headerHttp,
_data.timeout,
);
}
}
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
scaffoldMessengerKey: _messengerKey,
home: Scaffold(
appBar: AppBar(
title: const Text('Ssl Pinning Plugin'),
),
body: Builder(
builder: (BuildContext context) {
return Container(
padding: const EdgeInsets.all(20.0),
child: Form(
key: _formKey,
child: ListView(
children: <Widget>[
TextFormField(
keyboardType: TextInputType.url,
controller: TextEditingController(text: "https://example.com"),
decoration: const InputDecoration(
hintText: 'https://yourdomain.com',
labelText: 'URL',
),
validator: (value) {
if (value?.isEmpty == true) {
return 'Please enter some url';
}
return null;
},
onSaved: (value) {
_data.serverURL = value ?? '';
},
),
DropdownButton(
items: [
DropdownMenuItem(
child: Text(SHA.SHA1.toString()),
value: SHA.SHA1,
),
DropdownMenuItem(
child: Text(SHA.SHA256.toString()),
value: SHA.SHA256,
),
],
value: _data.sha,
isExpanded: true,
onChanged: (SHA? val) {
setState(() {
_data.sha = val;
});
},
),
TextFormField(
controller: TextEditingController(
text:
"51 E9 01 5F FE FB 79 70 D8 DF 74 BB 46 94 63 72 B1 E3 2B 31 6A 46 F0 C5 36 E7 C1 D4 DD C5 B2 70",
),
keyboardType: TextInputType.text,
decoration: const InputDecoration(
hintText: 'OO OO OO OO OO OO OO OO OO OO',
labelText: 'Fingerprint',
),
validator: (value) {
if (value?.isEmpty == null) {
return 'Please enter some fingerprint';
}
return null;
},
onSaved: (value) {
_data.allowedSHAFingerprint = value ?? '';
},
),
TextFormField(
keyboardType: TextInputType.number,
initialValue: '60',
decoration: const InputDecoration(
hintText: '60',
labelText: 'Timeout',
),
validator: (value) {
if (value?.isEmpty == true) {
return 'Please enter some timeout';
}
return null;
},
onSaved: (value) {
_data.timeout = int.tryParse(value ?? '') ?? 0;
},
),
Container(
margin: const EdgeInsets.only(top: 20.0),
child: ElevatedButton(
onPressed: () => submit(),
child: const Text(
'Check',
style: TextStyle(color: Colors.white),
),
),
),
],
),
),
);
},
),
),
);
}
}
更多关于Flutter公钥固定插件public_key_pinning的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter公钥固定插件public_key_pinning的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
在Flutter中,public_key_pinning 是一个用于实现公钥固定(Public Key Pinning)的插件。公钥固定是一种安全机制,用于确保客户端只与特定的服务器通信,防止中间人攻击(MITM)。通过固定服务器的公钥,客户端可以验证服务器的身份,确保通信的安全性。
安装插件
首先,你需要在 pubspec.yaml 文件中添加 public_key_pinning 插件的依赖:
dependencies:
flutter:
sdk: flutter
public_key_pinning: ^1.0.0 # 请使用最新版本
然后运行 flutter pub get 来安装插件。
使用插件
以下是如何使用 public_key_pinning 插件的基本步骤:
-
导入插件:
import 'package:public_key_pinning/public_key_pinning.dart'; -
初始化公钥固定:
在应用程序启动时,初始化公钥固定。你需要提供服务器的公钥哈希值(通常是 SHA-256 哈希值)。
void main() async { WidgetsFlutterBinding.ensureInitialized(); // 初始化公钥固定 await PublicKeyPinning.init( sha256: 'your_sha256_hash_here', // 替换为你的公钥 SHA-256 哈希值 httpClient: HttpClient(), // 使用自定义的 HttpClient ); runApp(MyApp()); } -
发送请求:
使用
PublicKeyPinning提供的httpClient来发送请求。这个httpClient会自动验证服务器的公钥。Future<void> fetchData() async { final httpClient = PublicKeyPinning.httpClient; final request = await httpClient.getUrl(Uri.parse('https://your-api-endpoint.com')); final response = await request.close(); if (response.statusCode == 200) { final responseData = await response.transform(utf8.decoder).join(); print('Response: $responseData'); } else { print('Failed to load data: ${response.statusCode}'); } } -
处理异常:
如果服务器的公钥不匹配,
PublicKeyPinning会抛出异常。你可以捕获并处理这些异常。try { await fetchData(); } on PublicKeyPinningException catch (e) { print('Public key pinning failed: ${e.message}'); } catch (e) { print('An error occurred: $e'); }
获取公钥哈希值
要获取服务器的公钥哈希值,你可以使用以下命令:
openssl s_client -connect your-api-endpoint.com:443 < /dev/null | openssl x509 -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64

