Flutter Web,向具有自签名证书的服务器发出请求时出现问题
Posted
技术标签:
【中文标题】Flutter Web,向具有自签名证书的服务器发出请求时出现问题【英文标题】:Flutter web, problem making request to a server with self signed certificate 【发布时间】:2020-06-05 05:38:14 【问题描述】:我正面临 Flutter Web 的第一个大问题。
我必须通过对具有自签名 ssl 证书的服务器的后调用来使用 oauth2 登录。
使用 http 和 dio 客户端发出请求,我收到 net::ERR_CERT_AUTHORITY_INVALID。我在网上找到的唯一方法是使用 HttpClient,它适用于 android 和 IO,但 dart:io 不适用于 web 构建。 有没有办法信任我的 ssl 证书用于颤振网络?
// My simple line of code
var response = await client.post(authorizationEndpoint.toString(), body: body, headers: headers);
// What I am looking for
var response = await client.post(authorizationEndpoint.toString(),
body: body, headers: headers,
---> trustanyCA: true);
【问题讨论】:
github.com/flutterchina/dio/issues/32 它使用了HttpClient,实际上在新的dio包(从版本3)中,changelog说现在支持flutter web并且不存在onHttpClientCreate功能。 pub.dev/packages/dio#-changelog-tab- 您找到解决方案了吗? Web 上的 DIO(错误:需要一个“DefaultHttpClientAdapter”类型的值,但得到一个“BrowserHttpClientAdapter”类型的值) 为什么不让我们加密证书?它们是免费的,但它们完全有效且受信任。所以你只需解决删除它的问题 @StefanoMiceli 我和你有同样的问题,你找到合适的了吗? 【参考方案1】:在网页版中无法做到这一点。浏览器的 XMLHttpRequest
只是不允许绕过不受信任的证书,但可以通过其他 http 客户端来做到这一点。
如果仅用于调试目的,您可以尝试将 SSL 证书添加到系统的受信任证书中(对于 macOS,将其放入 Keychain Access 中的 System certificate) ,以及覆盖浏览器的安全选项。请参阅this question 了解如何在 Chrome 中覆盖它。
对于生产用途,您仍然需要一个受信任的有效证书。
【讨论】:
真是个悲伤的消息。我同意你的观点,它应该只用于调试和测试目的,但总而言之,我可以在任何平台上解决它,从 ios、Android 到 php 等。Flutter web 是第一个不可能完成任务的平台。我知道它处于测试阶段,但这是一项基本任务...... @Tom 这是浏览器的限制,而不是 Flutter 框架的限制。在浏览器中执行的代码无法绕过其安全性,除非它使用某种漏洞,因此在客户端 javascript 中不可能做到这一点(但在服务器端 nodejs 代码中是可能的)。【参考方案2】:您可以使用https://pub.dev/packages/universal_io 包。除了 Android 和 iOS,它还支持 Web。
dependencies:
universal_io: ^1.0.1
执行以下导入而不是 dart:io
:
import 'package:universal_io/io.dart';
它的工作方式相同。
import 'package:universal_io/io.dart';
Future<void> main() async
final request = HttpClient().getUrl(Uri.parse('https://example.com/path'));
if (request is BrowserHttpClientRequest)
request.credentialsMode = BrowserHttpClientCredentialsMode.include;
final response = await request.close();
// ...
编辑:
试试这个,因为它似乎不适用于 String,尝试使用 Bytes
方法并遵循证书路径。
ByteData data = await rootBundle.load('assets/raw/certificate.crt');
SecurityContext context = SecurityContext.defaultContext;
context.setTrustedCertificatesBytes(data.buffer.asUint8List());
client = HttpClient(context: context);
EDIT2:
如果你使用HttpClient.badCertificateCallback 会怎样 这是接受任何证书的代码:
_client = new HttpClient();
_client.badCertificateCallback = (X509Certificate cert, String host, int port) => true;
EDIT3:
class MyHttpOverrides extends HttpOverrides
@override
HttpClient createHttpClient(SecurityContext context)
return super.createHttpClient(context)
..badCertificateCallback = (X509Certificate cert, String host, int port)=> true;
void main()
HttpOverrides.global = new MyHttpOverrides();
runApp(new MyApp());
【讨论】:
谢谢。您的代码中有拼写错误,缺少等待: final request = await HttpClient().getUrl(Uri.parse('example.com/path'));而且它仍然存在自签名证书的问题:加载资源失败:net::ERR_CERT_AUTHORITY_INVALID 当然,不客气!我用另一个想法编辑了我的答案。请检查一下。 谢谢。它在 var context = SecurityContext.defaultContext; 处引发错误错误:Object.throw_ 处的 UnimplementedError [as throw] (localhost:62417/dart_sdk.js:4773:11) 您是否存储 .pfx 文件? [...]将您的 PKCS12 客户端密钥库(pfx 文件)存储在您的应用程序中的某个位置,可能作为资产,并在启动时加载它。创建一个 SecurityContext,然后调用 useCertificateChainBytes 和 usePrivateKeyBytes 将相同的值传递给两者(pfx 文件的内容和密码)。[...] 是的,我想帮助你解决任何想法:D 你能像我向你展示的那样使用 HttpClient.badCertificateCallback 传递它吗?【参考方案3】:如果您使用自签名证书进行开发和测试,您可以将您的操作系统设置为始终信任该证书,并且浏览器会尊重这一点。
或者,您可以使用 Let's Encrypt 生成有效证书,然后让本地 Web 服务器使用它。
最后 - 如果您想要一个快速简单的解决方案,ngrok 将为您提供通往 localhost 的安全隧道,您可以将其用于开发和测试。
【讨论】:
【参考方案4】:此外,如果您使用的是 google chrome,则转到您的本地主机站点设置并将不安全内容从阻止更改为允许可能会有所帮助。
【讨论】:
以上是关于Flutter Web,向具有自签名证书的服务器发出请求时出现问题的主要内容,如果未能解决你的问题,请参考以下文章
PHP - 使用 STARTTLS 和自签名证书的 Swiftmailer
可以将 CA(客户端)颁发的证书与自签名证书(服务器)进行通信吗?