如何正确限制 Google 地图(地点、地理编码)API 对 Android 和 iOS 应用程序(用 Flutter 编写)的调用?
How to properly restrict Google Maps (Places, Geocoding) API calls to Android and iOS Apps (written in Flutter)?
我有一个用 Flutter 编写的移动应用程序。我正在为地点和地理编码调用 Google API。由于对这些服务的调用是通过将密钥包含在 url 中进行的,因此限制此密钥非常重要,这样任何人都不能仅仅拦截并使用它们进行多次调用并为我们和 Google.
API 调用的示例是:
https://maps.googleapis.com/maps/api/place/autocomplete/json?input=$input&types=address&language=$lang&components=country:za&key=$apiKey
和
https://maps.googleapis.com/maps/api/geocode/json?latlng=$lat,$lon&key=$apiKey
(其中 $apiKey=our Google Maps API Credentials Key $input, $lang, $lat and $lon 代表其他变量)
Google 当前允许对 API 凭据进行以下应用程序限制:
- None
- HTTP 推荐人
- IP 地址
- Android 应用
- iOS 应用
当我的密钥(选项“None”)没有任何限制时,我的移动应用程序可以正常运行。但是,如果我选择将其限制为 iOS 个应用程序(并为我的应用程序指定捆绑包标识符),我会收到错误消息“此 IP、站点或移动应用程序无权使用此 API 键”。当我将密钥限制为 Android 应用程序并为 Android 应用程序指定我的包 ID 和 SHA1 签名时,也会发生同样的情况。
我错过了什么?根据 https://developers.google.com/maps/api-key-best-practices#restrict_apikey,我应该可以将密钥限制在我的特定移动应用程序中。 Google 地图似乎没有接收到我确实是从正确的移动应用程序拨打电话。无论我 运行 在模拟器中还是在处于调试或发布模式的实际设备上,都会发生错误。 (我也从 Test Flight 测试了应用程序的 iOS 版本。当我删除限制时,我的 api 调用工作;当我将它限制为我的 iOS 应用程序的捆绑标识符时它停止工作。)还有什么我需要配置的吗?问题可能是应用程序是用 Flutter 编写的?
我发现一些链接(如 this)建议移动应用程序永远不要直接在 url 中使用密钥,而应该使用我们自己的服务器作为 [=61= 的代理] 然后我们应该限制对我们服务器 IP 的访问。这似乎是一个不必要的开销,因为将密钥限制为特定应用程序 ID 和平台的选项的存在表明这应该是可能的(我参考的 Google 文档也是如此)。
如果您想为特定 Android/iOS 应用程序利用 Google 地图服务 API 配置,您需要使用本机 Android 和本机iOS 依赖于 SHA 指纹和包名称或包 ID 的 SDK。
由于 Google 地点 API 似乎很受欢迎,存在许多 third-party 尝试:https://pub.dev/packages?q=google+places
地理编码存在类似情况:https://pub.dev/packages?q=google+geocoding
您可以查看是否有任何适合您的应用程序,或者您需要创建自己的平台渠道以获得支持:https://flutter.dev/docs/development/platform-integration/platform-channels
我最终创建了一个代理服务器。 (更多内容见下文)。
批判性地思考它,我意识到 API 真的没有任何方法可以辨别传入的请求是否来自特定的移动应用程序,所以我不认为对特定的限制iOS 或 Android 应用程序确实可以用于 https 请求。
我还调查了一些提供的 flutter 插件,但大多数似乎在后台使用 google_maps_webservice。 google_maps_webservice 需要应用程序代码中的密钥或指定代理。大多数源自 google_maps_webservice 的插件甚至不提供代理选项并且需要指定密钥。因此,即使使用了这些插件,最终也会“泄露”您在应用程序代码中的密钥,这使得 reverse-engineer 并获取您的代码成为可能。 (它最终出现在 iOS 上的 AppDelegate.m 文件和 Android 上的 AndroidManifest.xml 中)。 Google 建议不要以这种方式分发您的 api 密钥。
所以我最终创建了一个代理服务器。在没有密钥的情况下向我的代理发出请求,然后代理在添加密钥后将请求传递给 Google。代理然后 returns 对应用程序的响应。应用程序和应用程序与服务器之间的流量从不包含密钥。
幸运的是,我的应用程序已经在使用 AWS,并且用户正在使用 Cognito 登录。因此,我可以在 API 网关中轻松创建代理,并让应用使用 Cognito 向我的代理服务器进行身份验证。这确保只有在 Cognito 中有效登录我的应用程序的用户才能调用代理,并且密钥始终保密。
我有一个用 Flutter 编写的移动应用程序。我正在为地点和地理编码调用 Google API。由于对这些服务的调用是通过将密钥包含在 url 中进行的,因此限制此密钥非常重要,这样任何人都不能仅仅拦截并使用它们进行多次调用并为我们和 Google.
API 调用的示例是:
https://maps.googleapis.com/maps/api/place/autocomplete/json?input=$input&types=address&language=$lang&components=country:za&key=$apiKey 和 https://maps.googleapis.com/maps/api/geocode/json?latlng=$lat,$lon&key=$apiKey
(其中 $apiKey=our Google Maps API Credentials Key $input, $lang, $lat and $lon 代表其他变量)
Google 当前允许对 API 凭据进行以下应用程序限制:
- None
- HTTP 推荐人
- IP 地址
- Android 应用
- iOS 应用
当我的密钥(选项“None”)没有任何限制时,我的移动应用程序可以正常运行。但是,如果我选择将其限制为 iOS 个应用程序(并为我的应用程序指定捆绑包标识符),我会收到错误消息“此 IP、站点或移动应用程序无权使用此 API 键”。当我将密钥限制为 Android 应用程序并为 Android 应用程序指定我的包 ID 和 SHA1 签名时,也会发生同样的情况。
我错过了什么?根据 https://developers.google.com/maps/api-key-best-practices#restrict_apikey,我应该可以将密钥限制在我的特定移动应用程序中。 Google 地图似乎没有接收到我确实是从正确的移动应用程序拨打电话。无论我 运行 在模拟器中还是在处于调试或发布模式的实际设备上,都会发生错误。 (我也从 Test Flight 测试了应用程序的 iOS 版本。当我删除限制时,我的 api 调用工作;当我将它限制为我的 iOS 应用程序的捆绑标识符时它停止工作。)还有什么我需要配置的吗?问题可能是应用程序是用 Flutter 编写的?
我发现一些链接(如 this)建议移动应用程序永远不要直接在 url 中使用密钥,而应该使用我们自己的服务器作为 [=61= 的代理] 然后我们应该限制对我们服务器 IP 的访问。这似乎是一个不必要的开销,因为将密钥限制为特定应用程序 ID 和平台的选项的存在表明这应该是可能的(我参考的 Google 文档也是如此)。
如果您想为特定 Android/iOS 应用程序利用 Google 地图服务 API 配置,您需要使用本机 Android 和本机iOS 依赖于 SHA 指纹和包名称或包 ID 的 SDK。
由于 Google 地点 API 似乎很受欢迎,存在许多 third-party 尝试:https://pub.dev/packages?q=google+places
地理编码存在类似情况:https://pub.dev/packages?q=google+geocoding
您可以查看是否有任何适合您的应用程序,或者您需要创建自己的平台渠道以获得支持:https://flutter.dev/docs/development/platform-integration/platform-channels
我最终创建了一个代理服务器。 (更多内容见下文)。
批判性地思考它,我意识到 API 真的没有任何方法可以辨别传入的请求是否来自特定的移动应用程序,所以我不认为对特定的限制iOS 或 Android 应用程序确实可以用于 https 请求。
我还调查了一些提供的 flutter 插件,但大多数似乎在后台使用 google_maps_webservice。 google_maps_webservice 需要应用程序代码中的密钥或指定代理。大多数源自 google_maps_webservice 的插件甚至不提供代理选项并且需要指定密钥。因此,即使使用了这些插件,最终也会“泄露”您在应用程序代码中的密钥,这使得 reverse-engineer 并获取您的代码成为可能。 (它最终出现在 iOS 上的 AppDelegate.m 文件和 Android 上的 AndroidManifest.xml 中)。 Google 建议不要以这种方式分发您的 api 密钥。
所以我最终创建了一个代理服务器。在没有密钥的情况下向我的代理发出请求,然后代理在添加密钥后将请求传递给 Google。代理然后 returns 对应用程序的响应。应用程序和应用程序与服务器之间的流量从不包含密钥。
幸运的是,我的应用程序已经在使用 AWS,并且用户正在使用 Cognito 登录。因此,我可以在 API 网关中轻松创建代理,并让应用使用 Cognito 向我的代理服务器进行身份验证。这确保只有在 Cognito 中有效登录我的应用程序的用户才能调用代理,并且密钥始终保密。