如何限制Google App Engine端点API只能访问我的Android应用程序?

时间:2014-02-17 09:26:02

标签: android google-app-engine google-cloud-endpoints

我是一名Android开发人员,为我的应用构建了我的第一个Google App Engine(java)后端。除了我的应用程序之外,我不希望任何其他人访问此API。 (我计划在我的Android应用程序中使用App引擎验证InApp购买)。我的数据与用户无关,所以 即使用户使用自己的Google帐户(在网络或Android设备上)登录,我也不希望用户能够访问我的API。

我按照“在API后端指定授权客户端”中提到的步骤进行操作 (https://developers.google.com/appengine/docs/java/endpoints/auth) 比如生成客户端ID并将其添加到@Api(clientIds和audiences)中 除了“添加用户参数” - 因为我不需要用户身份验证。

然后我部署了App引擎,我仍然可以通过API资源管理器(https://your_app_id.appspot.com/_ah/api/explorer)访问API (我没有添加API_EXPLORER客户端ID)

我使用在使用端点库构建的APK进行测试后再添加客户端ID,并且仍然可以访问API。

  • 是否必须向所有端点API添加“用户参数”?实现我的目的(将API限制为仅限我的Android应用程序)。

  • 我可以从Android客户端传递null作为userAccount名称并忽略服务器上的用户参数值(因为它将为null)?这是否确保API只能从我的Android应用程序访问(因为我的包名称和APK的SHA1生成了客户端ID?)

  • 我是否应该为此目的使用类似服务帐户的东西?

文档说,对于Android,必须添加Android和Web客户端ID,并且受众必须与Web客户端ID相同。这是否可以访问任何其他Web客户端?我可以跳过提及Web客户端ID并仍然实现我的目的吗?

感谢您的时间和帮助。

......随着我的进一步调查而更新......

我做了以下事情:

  • 在后端向API添加了User参数 - 但未检查空值。仍然可以访问API而无需传递任何凭据(来自Android调试APK和API资源管理器)

  • 然后,我尝试了

    mCredential = GoogleAccountCredential.usingAudience(this,“server:client_id:”+ WEB_CLIENT_ID); mCredential.setSelectedAccountName(NULL);

并将此凭据传递给API构建器(如其他一些帖子所示) 致命的致命异常。所以,我们不能传递空账号。

  • 我可以在没有OAuth的情况下使用API​​资源管理器调用API。但是当我启用OAuth时,它提示错误,说不允许此客户端ID! (我尚未在client_ids {}中添加com.google.api.server.spi.Constant.API_EXPLORER_CLIENT_ID)

  • 然后我添加了代码,如果用户为null,则在后端抛出OAuthRequestException。这导致API资源管理器在没有OAuth的情况下收到错误。在将API_EXPLORER_CLIENT_ID添加到client_ids后,它可以在启用OAuth的情况下使用)

  • 添加了从我的Android应用程序传递有效用户帐户名(电子邮件)的代码。然后,我只能使用我的发布APK访问API。即使是调试APK也会有异常! - 这是我的预期。所以,我认为没有其他Android应用程序能够访问此API。

因此,不检查后端API上的null用户是个坏主意(如其他帖子所示)。它没有提到任何client_ids而没有User param。

目前唯一的问题是:如果有人可以从APK中找出WEB_CLIENT_ID,他们是否可以使用它来构建一个Web客户端来访问我的API(我没有在任何地方提到客户端秘密)代码。所以我认为这是不可能的。)


我确实搜索了Google网上论坛和Stackoverflow,但目前还不清楚。

5 个答案:

答案 0 :(得分:8)

我有类似的问题,不是在Android和App Engine之间,而是在单独的服务器和App Engine之间。我处理它的方法是将签名哈希字段作为参数添加到每个API调用。如果请求有不正确的签名,则会被拒绝。

例如,假设您的API端点为example.com/api/do_thing?param1=foo。我会将整个url与一个密钥一起散列,然后将哈希的结果附加到请求中:example.com/api/do_thing?param1=foo&hash=[some long hex value]

然后,在服务器端,我首先从url请求中删除哈希,然后对剩余的所有内容运行哈希。最后,检查计算的散列是否与随请求一起发送的散列匹配,如果不匹配,则可以拒绝该请求。

然而,您的密钥仍然保密是非常重要的。您必须在Android上小心这一点,因为有人可能会尝试反编译您的APK。

答案 1 :(得分:3)

面对同样的问题!不使用Google用户帐户验证Android端点是不可能的!

所以这是我解决这个问题的方法,没有任何用户交互(也许不是正确的但是有效,而且你有强大的身份验证(SHA1 + Google帐户)):

这是我的安卓代码

获取并构建有效凭据

  //Get all accounts from my Android Phone
         String validGoogleAccount = null;
         Pattern emailPattern = Patterns.EMAIL_ADDRESS; // API level 8+
         Account[] accounts = AccountManager.get(context).getAccounts();
         for (Account account : accounts) {
             if (emailPattern.matcher(account.name).matches()) {
                 //Just store mail if countain gmail.com
                 if (account.name.toString().contains("gmail.com")&&account.type.toString().contains("com.google")){
                     validGoogleAccount=account.name.toString();
                 }

             }
         }

        //Build Credential with valid google account
        GoogleAccountCredential credential = GoogleAccountCredential.usingAudience(this,"server:client_id:301991144702-5qkqclsogd0b4fnkhrja7hppshrvp4kh.apps.googleusercontent.com");
        credential.setSelectedAccountName(validGoogleAccount);

使用此凭据进行安全通话

Campagneendpoint.Builder endpointBuilder = new Campagneendpoint.Builder(AndroidHttp.newCompatibleTransport(), new JacksonFactory(), credential);

这是我的API后备代码: API注释

@Api(
        scopes=CONSTANTES.EMAIL_SCOPE,
        clientIds = {CONSTANTES.ANDROID_CLIENT_ID, 
                     CONSTANTES.WEB_CLIENT_ID,
                     com.google.api.server.spi.Constant.API_EXPLORER_CLIENT_ID},
        audiences = {CONSTANTES.ANDROID_AUDIENCE},      
        name = "campagneendpoint",
        version = "v1"
     )

方法代码:

public Collection<Campagne> getCampagnes(@Named("NumPortable")String NumPortable, User user) throws  UnauthorizedException {
        if (user == null) throw new UnauthorizedException("User is Not Valid");

      return CampagneCRUD.getInstance().findCampagne(NumPortable);
     }

目前,它仅适用于Android(我不知道我们将如何处理IOS ..)..

希望它会对你有帮助!

答案 2 :(得分:3)

Google为AndroidwebiOS提供了执行此操作的方法 步骤包括:

  1. 为您希望允许向API发出请求的应用指定客户端ID
  2. 将User参数添加到要通过授权保护的所有公开方法。
  3. 再次为任何Android客户端生成客户端库
  4. 重新部署后端API。
  5. 将重新生成的jar文件更新为Android客户端的Android项目。
  6. 这些步骤在Google Using Auth with Endpoints以及此blog

    上详细列出。

答案 3 :(得分:1)

面对同样的问题,这是我研究的结果:

  • 在Google控制台中添加了带有SHA1指纹的Android cliend id
  • 在API注释中使用它

但是:

  • 如果我不向方法添加用户参数:检查Android应用程序客户端ID不起作用

  • 如果我添加USER参数但不要求用户选择其Google帐户来创建凭据...也不起作用...

结论:似乎必须连接用户帐户以检查要执行的应用程序客户端ID ...我真的不明白为什么因为2个进程之间不存在链接

答案 4 :(得分:0)

Access this site

选择您的项目,转到凭证部分

创建一个新的api密钥

创建一个新的Android密钥

点击&#34;编辑允许的Android应用程序&#34;并输入您的SHA1密钥;你的android包名称

如果这解决了问题,请告诉我。