简体   繁体   English

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

[英]How do I restrict Google App Engine Endpoints API access to only my Android applications?

I am an Android developer building my first Google App Engine (java) back-end for my apps. 我是一名Android开发人员,为我的应用构建了我的第一个Google App Engine(java)后端。 I don't want anybody else to access this API other than my app. 除了我的应用程序之外,我不希望任何其他人访问此API。 (I plan to use App engine for verifying InApp purchases in my Android app). (我计划在我的Android应用程序中使用App引擎验证InApp购买)。 My data is not relevant to users so, I don't want users to be able to access my API even if they are logged in with their Google accounts (on web or Android devices). 我的数据与用户无关,因此我不希望用户即使使用他们的Google帐户(在网络或Android设备上)登录也能访问我的API。

I followed the steps mentioned in - "Specifying authorized clients in the API backend" ( https://developers.google.com/appengine/docs/java/endpoints/auth ) like generating client IDs and add them in @Api (clientIds and audiences) except "Add a User parameter" - since I don't need user authentication. 我按照“在API后端中指定授权客户端”( https://developers.google.com/appengine/docs/java/endpoints/auth )中提到的步骤进行操作,例如生成客户端ID并将其添加到@Api(clientIds和观众)除了“添加用户参数” - 因为我不需要用户身份验证。

Then I deployed App engine and I am still able to access the API through API explorer ( https://your_app_id.appspot.com/_ah/api/explorer ) (I haven't added API_EXPLORER client ID) 然后我部署了App引擎,我仍然可以通过API资源管理器访问API( https://your_app_id.appspot.com/_ah/api/explorer )(我还没有添加API_EXPLORER客户端ID)

I tested with the APK that was built with the endpoint libs before adding client IDs and can still access the API. 我在添加客户端ID之前使用使用端点库构建的APK进行了测试,并且仍然可以访问API。

  • Is adding a "User parameter" to all endpoint APIs a must? 是否必须向所有端点API添加“用户参数”? to achieve my purpose (restrict API to only my Android apps). 实现我的目的(限制API到我的Android应用程序)。

  • Can I pass null as userAccount name from Android client and ignore user parameter value on server (since it will be null)? 我可以从Android客户端传递null作为userAccount名称并忽略服务器上的用户参数值(因为它将为null)? Will this ensure that the API is accessible only from my android apps (since the client ID is generated for my package name and SHA1 of the APK?) 这是否确保API只能从我的Android应用程序访问(因为客户端ID是为我的包名和APK的SHA1生成的?)

  • Should I use something like a service account for this purpose? 我应该为此目的使用类似服务帐户的东西吗?

The documentation says for Android, both Android and Web client IDs must be added and audience must be the same as web client ID. 文档说,对于Android,必须添加Android和Web客户端ID,并且受众必须与Web客户端ID相同。 Does this open access to any other web client? 这是否可以访问任何其他Web客户端? can I skip mentioning web client ID and still achieve my purpose? 我可以跳过提及Web客户端ID并仍然达到我的目的吗?

Appreciate your time and help. 感谢您的时间和帮助。

...... updating with my further investigation ... ......随着我的进一步调查而更新......

I did the following: 我做了以下事情:

  • Added User parameter to APIs on backend - but did not check for null value. 在后端的API中添加了User参数 - 但没有检查空值。 API can still be accessed without passing any credentials (from Android debug APK and API explorer) 无需传递任何凭据即可访问API(来自Android调试APK和API资源管理器)

  • Then, I tried 然后,我试过了

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

and passed this credential to API builder (as suggested in some other posts) Caused FATAL EXCEPTION. 并将此凭据传递给API构建器(如其他一些帖子中所建议的)导致致命异常。 So, we can't pass null account name. 所以,我们不能传递null帐户名。

  • I could call the API using API explorer without OAuth. 我可以在没有OAuth的情况下使用API​​资源管理器调用API。 But when I enabled OAuth, it gave error saying this client ID is not allowed! 但是当我启用OAuth时,它提示错误,说不允许此客户端ID! ( I haven't yet added com.google.api.server.spi.Constant.API_EXPLORER_CLIENT_ID in client_ids{}) (我还没有在client_ids {}中添加com.google.api.server.spi.Constant.API_EXPLORER_CLIENT_ID)

  • Then I added code to throw OAuthRequestException on the backend if the user is null. 然后我添加了代码,如果用户为null,则在后端抛出OAuthRequestException。 This resulted in API explorer getting errors without OAuth. 这导致API资源管理器在没有OAuth的情况下收到错误。 It works with OAuth enabled after adding API_EXPLORER_CLIENT_ID to client_ids) 将API_EXPLORER_CLIENT_ID添加到client_ids后,它可以启用OAuth

  • Added code to pass valid user account name(email) from my Android app. 添加了从我的Android应用程序传递有效用户帐户名(电子邮件)的代码。 Then, I am able to access API only with my release APK. 然后,我只能使用我的发布APK访问API。 Even the debug APK gets exceptions! 即使是调试APK也有例外! - which is what I expected..So, I assume no other Android apps will be able to access this API. - 这是我的预期。所以,我认为没有其他Android应用程序能够访问此API。

So, not checking for null user on back-end API is a bad idea (as suggested in other posts). 因此,不检查后端API上的null用户是个坏主意(如其他帖子所示)。 It is as good as not mentioning any client_ids and not having User param. 它没有提到任何client_ids而没有User param。

Only question I have at this moment is: If some one can figure out the WEB_CLIENT_ID from the APK, will they be able to use it to build a web client to access my API (I haven't mentioned client secret anywhere in the code. So I am thinking this is not possible). 我现在唯一的问题是:如果有人可以从APK中找出WEB_CLIENT_ID,他们是否可以使用它来构建一个Web客户端来访问我的API(我没有在代码中的任何地方提到过客户端秘密。所以我认为这是不可能的)。


I did search Google groups and Stackoverflow, but still it is not clear. 我确实搜索了Google群组和Stackoverflow,但目前尚不清楚。

I had a similar issue, not between Android and App Engine, but between a separate server and App Engine. 我有类似的问题,不是在Android和App Engine之间,而是在单独的服务器和App Engine之间。 The way I handled it was to add a signature hash field as a parameter to each API call. 我处理它的方法是将签名哈希字段作为参数添加到每个API调用。 If the request had an improper signature, it would be denied. 如果请求有不正确的签名,则会被拒绝。

For example, suppose your API end-point is example.com/api/do_thing?param1=foo . 例如,假设您的API端点是example.com/api/do_thing?param1=foo I would hash the entire url, along with a secret key, and then append the result of the hash to the request: example.com/api/do_thing?param1=foo&hash=[some long hex value] . 我将散列整个url以及一个密钥,然后将哈希的结果附加到请求: example.com/api/do_thing?param1=foo&hash=[some long hex value] hash=[ example.com/api/do_thing?param1=foo&hash=[some long hex value]

Then, on the server side, I would first remove the hash from the url request, then run the hash on everything that was remaining. 然后,在服务器端,我首先从url请求中删除哈希,然后对剩余的所有内容运行哈希。 Finally, you check whether the calculated hash matches the one that was sent with the request and if they don't, you can deny the request. 最后,检查计算的散列是否与随请求一起发送的散列匹配,如果不匹配,则可以拒绝该请求。

It is very important however that your secret key remain secret. 但是,您的密钥仍然保密,这一点非常重要。 You have to be careful with this on Android because someone could attempt to decompile your APK. 您必须在Android上小心这一点,因为有人可能会尝试反编译您的APK。

Facing the same problem than you ! 面对同样的问题比你! Authenticate Android End point without Google User Account is just impossible ! 在没有Google用户帐户的情况下验证Android端点是不可能的!

So here is my way to resolv this problem, without any user interaction (Maybe not the right but that works, and you've got strong authentication (SHA1 + Google Account)): 所以这是我解决这个问题的方法,没有任何用户交互(也许不是正确但有效,你有强大的身份验证(SHA1 + Google帐户)):

HERE IS MY ANDROID CODE 这是我的安卓代码

Get and Build Valid Credential 获取并构建有效凭据

  //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);

Use this credential for secure calls 使用此凭据进行安全呼叫

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

HERE IS MY API BACKEND CODE: API Annotation 这是我的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"
     )

Method code: 方法代码:

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);
     }

For the moment, it only works on Android (I don't know how we gonna do on IOS..).. 目前,它只适用于Android(我不知道我们将如何做IOS ..)..

Hope It will help you ! 希望它会对你有所帮助!

Google provides ways to do this for Android , web and iOS The steps involves: Google提供了针对AndroidwebiOS执行此操作的方法。步骤包括:

  1. Specifying a client Id for apps you want to allow to make requests to your API 为要允许向API发出请求的应用指定客户端ID
  2. Adding a User parameter to all exposed methods to be protected by authorization. 将User参数添加到要受授权保护的所有公开方法。
  3. Generating the client library again for any Android clients 为任何Android客户端再次生成客户端库
  4. Redeploying your backend API. 重新部署后端API。
  5. Updating the regenerated jar file to your Android project for your Android client. 将重新生成的jar文件更新为Android客户端的Android项目。

These steps are laid out in clear detail on Google's Using Auth with Endpoints and also on this blog 这些步骤在Google的Using Auth with Endpoints和此博客都有详细的详细说明

Facing the same problem, here are the result of my research : 面对同样的问题,这是我研究的结果:

  • Added Android cliend id with SHA1 fingerprint in Google console 在Google控制台中添加了带有SHA1指纹的Android cliend id
  • Use of it in the API annotation 在API注释中使用它

BUT : 但是:

  • If i dont add user parameter to methods : the check about android app client id does not work 如果我没有向方法添加用户参数:检查有关Android应用程序客户端ID不起作用

  • If I add the USER parameter but do not ask the user to choose its google account to create the credential ... also it does not work ... 如果我添加USER参数但不要求用户选择其谷歌帐户来创建凭证...也不起作用...

Conclusion : It seems to be mandatory to connect a user account for the check about the app client id to be executed ... I really do not understand why because no link exist between the 2 processes 结论:似乎必须连接用户帐户以检查要执行的应用程序客户端ID ...我真的不明白为什么因为2个进程之间不存在链接

Access this site 访问此站点

Choose your project, go to credentials section 选择您的项目,转到凭证部分

Create a new api key 创建一个新的api密钥

Create a new android key 创建一个新的Android密钥

Click on "Edit allowed android applications" and enter your SHA1 key; 单击“编辑允许的Android应用程序”并输入您的SHA1密钥; your android package name 你的android包名

Let me know if this solves the issues. 如果这解决了问题,请告诉我。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 将对Google云端点的访问权限限制为Android应用 - Restrict access to google cloud endpoints to Android app 保护我的Google App Engine API端点 - Protecting my Google App Engine API Endpoints 如何将对ContentProvider的访问权限仅限于我的应用程序? - How do I restrict access to my ContentProvider to only my apps? 限制对Android App的API端点访问 - Restrict access to my API Endpoint to Android App 如何将对REST API的访问限制为仅授权的客户端? - How do I restrict access to my REST API to only authorized clients? 如何从我的应用程序访问谷歌驱动器 api - How do I access google drive api from my app 将GAE API(端点)限制为Android应用 - Restrict GAE API (Endpoints) to Android app 如何将Google Maps时区API密钥限制为Android应用程序? - How do I restrict my Google Maps Time Zone API key to an Android application? 仅限访问我的Android应用程序的端点 - Limit access to my endpoints to my Android app only 如何从服务器端(Google App Engine,Cloud Endpoints)向我的客户端发送信息? - How can I send from the server-side (Google App Engine, Cloud Endpoints) the information to my client?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM