在 Flutter 应用程序中存储 API 凭据

Posted

技术标签:

【中文标题】在 Flutter 应用程序中存储 API 凭据【英文标题】:Storing API credentials in a flutter application 【发布时间】:2019-09-03 21:39:24 【问题描述】:

我在我的颤振应用程序中使用 googleapis 服务,这需要一些 JSON 格式的凭据。将此凭据存储在我的应用中的最佳方式是什么?

我可以在我的资产文件夹中保留一个 JSON 文件并在我的主函数中读取它吗?

或者我应该在我的主函数中硬编码凭据吗?我是 Flutter 开发的新手。

我的代码如下所示

import 'package:googleapis/storage/v1.dart';
import 'package:googleapis_auth/auth_io.dart';

final _credentials = new ServiceAccountCredentials.fromJson(r'''

  "private_key_id": ...,
  "private_key": ...,
  "client_email": ...,
  "client_id": ...,
  "type": "service_account"

''');

const _SCOPES = const [StorageApi.DevstorageReadOnlyScope];

void main() 
  clientViaServiceAccount(_credentials, _SCOPES).then((http_client) 
    var storage = new StorageApi(http_client);
    storage.buckets.list('dart-on-cloud').then((buckets) 
      print("Received $buckets.items.length bucket names:");
      for (var file in buckets.items) 
        print(file.name);
      
    );
  );

我应该将以下凭据保存在哪里:


  "private_key_id": ...,
  "private_key": ...,
  "client_email": ...,
  "client_id": ...,
  "type": "service_account"

我不认为像上面这样的硬编码是个好主意。

我认为这应该可行:https://medium.com/@sokrato/storing-your-secret-keys-in-flutter-c0b9af1c0f69

谢谢。

【问题讨论】:

如何让网络成为可能? 【参考方案1】:

要存储凭据等敏感信息,您应该使用 ios 下的 Keychain 和 android 下的 Keystore。

有一个完美的库,叫做flutter_secure_storage

以下是如何使用它:

// Create storage
final storage = new FlutterSecureStorage();

// Store password 
await storage.write(key: "password", value: "my-secret-password");

// Read value 
String myPassword = await storage.read(key: "password");

要使用它,请将flutter_secure_storage: 3.2.1+1 添加到您的pubspec.yaml 并在终端中运行flutter packages get

这里是包和一个关于如何使用它的更详细的例子: https://pub.dartlang.org/packages/flutter_secure_storage

【讨论】:

这是类似于 API 密钥的 API 凭证。这不是我从用户那里得到的东西。我应该把我的 api 密钥放在哪里? 这基本上是一个与 Flutter 无关的问题。如果黑客可以访问您的二进制文件,那么将 API 密钥作为常量字符串存储在代码中的某处总是很容易检测到的。有多种方法可以解决此类问题。例如,您可以使用用户名和密码实现某种 https 登录系统。然后,您的 API 可能会生成一个您可以安全存储的密钥。但这只是其中一种方式。 @RobinReiter 用于身份验证的 API 密钥怎么样?鸡蛋? 这没有回答问题,他需要一种方法来存储 API KEY 而无需对其进行硬编码【参考方案2】:

评论:我不明白 Robin 是如何回答这个问题的。原始发布者需要应用程序具有访问 API 的凭据。使用安全密钥存储不会为应用程序提供任何数据,因此它仍然无法访问 API。如果您在项目中添加文件,则安全密钥存储不会以任何方式保护文件。


2 种方法

环境变量:我建议将环境变量用于根据环境而变化的变量:您可能有 2 个 API_KEYS,因为您有生产和测试环境。但是,您的应用程序的攻击者仍然可以通过“中间人”处理您的请求来窃取此信息,例如,使用 proxyman。攻击者可以嗅探流量或反编译您的应用程序以窃取 API_KEYS 并在他们自己的项目、漏洞利用或加密货币挖矿。因此,如果您使用环境变量,请确保您的 API 密钥没有那么强大。一些 API 提供者将允许您限制该密钥的功能。

后端:因此,如果 API_KEY 功能强大且不受限制,则根本不应该在应用程序上使用它。它应该在您的后端,它代表客户端调用外部 API。您可以托管服务器来执行此操作,或使用无服务器函数(例如 AWS Lambda、GCP 云函数、Azure 函数、Firebase 云函数等等)。


一个例子

这取决于您的威胁模型:您认为可能针对您的应用的威胁类型。就我而言,我并不担心有人反编译我的黑客马拉松项目以窃取我免费获得的天气 API_KEY,但我担心一些 github 爬虫或 api 提供者找到这个 api_key 并禁用它(这发生在我的朋友和她的 Google Cloud Platform 服务帐户凭据)。所以,我正在使用环境变量。

【讨论】:

对于 Flutter 应用程序,环境变量不会隐藏任何内容。秘密值最终仍然是应用程序代码的一部分(就像 SPA 应用程序一样)。唯一正确且安全的方法是您在回复的“后端”部分中提出的建议。 环境变量会一直在设备上,而不仅仅是在 Flutter 中,所以从这个意义上说,Flutter 并没有特别危险。我补充一点说,如果您使用环境变量,请确保它们被锁定。 是的,它确实不是“额外”危险的。我是说,从一开始就这样做是不安全的。 Robin 实际上完美地回答了这个问题。大多数身份验证系统会让您使用您的凭据请求 API 密钥,然后您可以将其存储在钥匙串/密钥库中以供进一步使用。在密钥的 TTL 启动后,您的应用会要求您重新进行身份验证 - 这是一个非常常见的用例。 OP 应该让用户首先使用他们的用户名/密码向 Google 服务进行身份验证,然后处理存储它将用来响应的 API 密钥。 不@ravenblizzard,做await storage.write(key: "password", value: "my-secret-password"); 是完全错误的,那些是硬编码的凭据。在凭据从服务器传递到设备的情况下,确保您可以使用flutter_secure_storage,但问题和 Robin 的回答都没有提到凭据是从服务器传递的,丝毫没有。感谢您的反对。【参考方案3】:
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
/*  
* Example of a secure store as a Mixin 
* Usage: 

import '../mixins/secure_store_mixin.dart';

MyClass extends StatelessWidget with SecureStoreMixin 

  exampleSet()
    setSecureStore('jwt', 'jwt-token-data');
  

  exampleGet()
     getSecureStore('jwt', (token)  print(token); );
  


*/

class SecureStoreMixin

  final secureStore = new FlutterSecureStorage();

  void setSecureStore(String key, String data) async 
    await secureStore.write(key: key, value: data);
  

  void getSecureStore(String key, Function callback) async 
    await secureStore.read(key: key).then(callback);
  


注意:通过添加更多方法来扩展:

全部获取:Map<String, String> allValues = await secureStore.readAll(); 删除:await secureStore.delete(key: key); 全部删除:await secureStore.deleteAll();

【讨论】:

这真的很有用。帮助我了解如何在单独的文件中导入和使用它。

以上是关于在 Flutter 应用程序中存储 API 凭据的主要内容,如果未能解决你的问题,请参考以下文章

在flutter inappWebview中自动填充登录凭据

对于使用错误凭据执行的登录请求,REST API 应返回啥状态代码?

如何在 Flutter 中存储 API 密钥(2020 年 7 月)

使用先前存储在数据库中的凭据执行发送电子邮件的 API 端点。 (使用 Gmail REST API)

Kong 和 JWT - API 应如何从令牌中提取信息

如何在 c# 应用程序中正确保护 api 凭据