如何保护使用Google Cloud Endpoints构建的API?

时间:2013-06-03 04:51:21

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

API是移动应用的后端。我不需要用户身份验证。我只需要一种方法来保护对此API的访问。目前,我的后端曝光了。

documentation似乎只谈论用户身份验证和授权,这不是我需要的。我只需要确保只有我的移动应用可以与此后端进行通信,而不是其他任何人。

3 个答案:

答案 0 :(得分:4)

是的,您可以这样做:使用身份验证来保护您的终端,而无需进行用户身份验证。

我发现这样做的方式没有很好的记录,我自己也没有真正做过,但我打算这样,当我看到在一些IO13视频上进行讨论时我就注意了(我想那就是我看到的地方):

以下是我对所涉及内容的理解:

  • 创建一个Google API项目(虽然这不涉及他们的API,除了身份验证本身)。
  • 创建与您的应用程序绑定的OATH客户端ID,其名称和您将使用该应用程序签署的证书的SHA1指纹。

您将这些客户端ID添加到端点的可接受ID列表中。您将User参数添加到端点,但由于未指定用户,因此它将为null。

@ApiMethod(
   name = "sendInfo",
   clientIds = { Config.WEB_CLIENT_ID, Config.MY_APP_CLIENT_ID, Config.MY_DEBUG_CLIENT_ID },
   audiences = { Config.WEB_CLIENT_ID } 
   // Yes, you specify a 'web' ID even if this isn't a Web client.
)
public void sendInfo(User user, Info greeting) {

关于上述内容,有一些不错的文档,在这里: https://developers.google.com/appengine/docs/java/endpoints/auth

您的客户端应用程序将在制定端点服务调用时指定这些客户端ID。所有OATH详细信息都将在客户端设备的幕后得到处理,以便将您的客户端ID转换为身份验证令牌。

HttpTransport transport = AndroidHttp.newCompatibleTransport();
JsonFactory jsonFactory = new JacksonFactory();
GoogleAccountCredential credential = GoogleAccountCredential.usingAudience( ctx, Config.WEB_CLIENT_ID );
//credential.setSelectedAccountName( user );  // not specify a user
Myendpoint.Builder builder = new Myendpoint.Builder( transport, jsonFactory, credential );  

这个客户端代码只是我最好的猜测 - 抱歉。如果其他人有关于客户端代码应该是什么样子的参考,那么我也会感兴趣。

答案 1 :(得分:2)

我很遗憾地说Google没有为您的问题提供解决方案(这也是我的问题)。 你可以使用他们的API密钥机制(参见https://developers.google.com/console/help/new/#usingkeys),但这个策略有一个很大的漏洞,由Google自己的API资源管理器提供(参见https://developers.google.com/apis-explorer/#p/),这是一个很好的开发工具测试API,但公开所有Cloud Endpoint API,而不仅仅是Google的服务API。这意味着任何拥有项目名称的人都可以在闲暇时浏览和调用您的API,因为API资源管理器会规避API密钥安全性。 我找到了一个解决方法(基于bossylobster对这篇文章的很好的回应:Simple Access API (Developer Key) with Google Cloud Endpoint (Python)),它是传递一个请求字段,它不是客户端API中消息请求定义的一部分,然后读取它在您的API服务器中。如果您没有找到未记录的字段,则会引发未经授权的异常。这将插入API资源管理器创建的漏洞。 在iOS(我用于我的应用)中,您为每个请求类添加了一个属性(由Google的API生成器工具创建的属性),如下所示:

@property (copy) NSString *hiddenProperty;

并将其值设置为您选择的键。在您的服务器代码(在我的情况下是python)中,如果您没有看到它或它未设置为您的服务器和客户端将同意的值,则检查它是否存在和barf:

mykey,keytype = request.get_unrecognized_field_info('hiddenProperty')
        if mykey != 'my_supersecret_key':
            raise endpoints.UnauthorizedException('No, you dont!')

希望这能让你走上正轨

答案 2 :(得分:2)

  

该文档仅适用于客户。我需要的是文档   关于如何在服务器端提供服务帐户功能。

这可能意味着几件不同的事情,但我想谈谈我认为问题所在的问题。如果您只希望自己的服务帐户访问您的服务,那么您只需将服务帐户的clientId添加到@ Api / @ ApiMethod注释,构建GoogleCredential,并像往常一样调用您的服务。具体地说...

在Google开发人员的控制台中,创建一个新的服务帐户。这将创建一个自动下载的.p12文件。客户端在您链接的文档中使用它。 如果你不能保持.p12安全,那么这比密码安全得多。我猜这就是为什么云端点文档中没有明确规定这一点。

您可以将google开发人员控制台中显示的客户ID添加到@Api或@ApiMethod注释中的clientIds

import com.google.appengine.api.users.User

@ApiMethod(name = "doIt", scopes = { Constants.EMAIL_SCOPE }, 
     clientIds = { "12345678901-12acg1ez8lf51spfl06lznd1dsasdfj.apps.googleusercontent.com" })
public void doIt(User user){ //by convention, add User parameter to existing params
    // if no client id is passed or the oauth2 token doesn't 
    // match your clientId then user will be null and the dev server 
    // will print a warning message like this:
    // WARNING: getCurrentUser: clientId 1234654321.apps.googleusercontent.com not allowed
    //..
}

您使用与不安全版本相同的方式构建客户端,唯一的区别是您创建了一个GoogleCredential对象以传递给您的服务的MyService.Builder。

HttpTransport httpTransport = new NetHttpTransport(); // or build AndroidHttpClient on Android however you wish
JsonFactory jsonFactory = new JacksonFactory();

// assuming you put the .p12 for your service acccount 
// (from the developer's console) on the classpath; 
// when you deploy you'll have to figure out where you are really
// going to put this and load it in the appropriate manner 
URL url = getClass().class.getResource("/YOURAPP-b12345677654.p12");
File p12file = new File(url.toURI());

GoogleCredential.Builder credentialBuilder = new GoogleCredential.Builder();
credentialBuilder.setTransport(httpTransport);
credentialBuilder.setJsonFactory(jsonFactory);
//NOTE: use service account EMAIL (not client id)
credentialBuilder.setServiceAccountId("12345678901-12acg1ez8lf51spfl06lznd1dsasdfj@developer.gserviceaccount.com");    credentialBuilder.setServiceAccountScopes(Collections.singleton("https://www.googleapis.com/auth/userinfo.email"));
credentialBuilder.setServiceAccountPrivateKeyFromP12File(p12file);
GoogleCredential credential = credentialBuilder.build();

现在以相同的方式调用生成的客户端 除了构建器之外,您将使用不安全的版本 我们将谷歌凭证作为最后一个参数

MyService.Builder builder = new MyService.Builder(httpTransport, jsonFactory, credential);
builder.setApplicationName("APP NAME");
builder.setRootUrl("http://localhost:8080/_ah/api");

final MyService service = builder.build();
// invoke service same as unsecured version