Подтвердить что ты не робот

Как защитить свой API, который был создан с использованием Google Cloud Endpoints?

API - это бэкэнд для мобильного приложения. Мне не нужна аутентификация пользователей. Мне просто нужен способ защитить доступ к этому API. В настоящее время мой бэкэнд выставлен.

документация, похоже, говорит только об аутентификации пользователей и авторизации, что здесь не так. Мне просто нужно обеспечить, чтобы только мое мобильное приложение могло разговаривать с этим бэкэнд и ни с кем другим.

4b9b3361

Ответ 1

Да, вы можете сделать это: использовать аутентификацию для защиты своих конечных точек без проверки подлинности пользователя.

Я обнаружил, что этот способ сделать это плохо документирован, и я на самом деле не сделал этого сам, но я намерен так, что я обратил внимание, когда увидел, что он обсуждается на некоторых видео IO13 (я думаю, что там, где я его видел):

Здесь мое понимание того, что связано:

  • Создайте проект API Google (хотя на самом деле это не связано с их API, кроме собственно аутентификации).
  • Создайте идентификатор клиента OATH, привязанный к вашему приложению с помощью его имени пакета и отпечатка пальца SHA1 сертификата, с которым вы подпишете приложение.

Этот идентификатор клиента будет добавлен в список допустимых идентификаторов для ваших конечных точек. Вы добавите параметр User в свои конечные точки, но он будет пустым, поскольку пользователь не указан.

@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

Ваше клиентское приложение будет указывать эти идентификаторы клиента при формулировании вызова службы конечной точки. Все данные OATH будут позаботиться о месте вашего клиентского устройства за кадром, чтобы ваш идентификатор клиента был переведен на токены аутентификации.

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

Этот код клиента - это только мое лучшее предположение - извините. Если у кого-то еще есть ссылка на то, что должен выглядеть клиентский код, то мне тоже будет интересно.

Ответ 2

Извините, что Google не предоставляет решение вашей проблемы (это тоже моя проблема). Вы можете использовать их механизм ключей API (см. https://developers.google.com/console/help/new/#usingkeys), но есть огромная дыра в этой стратегии, предоставляемая Google собственным API-исследователем ( см. https://developers.google.com/apis-explorer/#p/), который является отличным инструментом для тестирования API, но предоставляет все API-интерфейсы Cloud Endpoint API, а не только API-интерфейсы служб Google. Это означает, что любой, кто имеет название вашего проекта, может просматривать и вызывать ваш API на досуге, так как API-интерфейс обходит защиту ключа API. Я нашел обходное решение (на основе отличного ответа bossylobster на этот пост: API простого доступа (ключ разработчика) с облачной конечной точкой Google (Python)), который должен передать запрос поле, которое не является частью определения запроса сообщения в вашем клиентском API, а затем читайте его на сервере API. Если вы не нашли недокументированное поле, вы поднимаете несанкционированное исключение. Это закроет отверстие, созданное исследователем API. В iOS (который я использую для своего приложения) вы добавляете свойство к каждому классу запросов (те, которые создаются с помощью инструмента генератора API 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!')

Надеюсь, это положит вас на правильный путь

Ответ 3

Документация предназначена только для клиента. Мне нужна документация о том, как обеспечить функциональность учетной записи службы на стороне сервера.

Это может означать пару разных вещей, но я хотел бы остановиться на том, что, по моему мнению, задает вопрос. Если вы хотите, чтобы ваша учетная запись службы имела доступ к вашему сервису, вы можете просто добавить клиентскую учетную запись службы в ваши аннотации @Api/@ApiMethod, создать GoogleCredential и вызвать свою службу, как обычно. В частности...

В консоли разработчика Google создайте новую учетную запись службы. Это создаст файл .p12, который будет автоматически загружен. Это используется клиентом в документации, к которой вы привязались. Если вы не можете защитить .p12, то это не намного безопаснее пароля. Я предполагаю, что это явно не указано в документации Cloud Endpoints.

Вы добавляете идентификатор CLIENT, отображаемый в консоли разработчика Google, в clientIds в аннотации @Api или @ApiMethod.

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 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("[email protected]count.com");    credentialBuilder.setServiceAccountScopes(Collections.singleton("https://www.googleapis.com/auth/userinfo.email"));
credentialBuilder.setServiceAccountPrivateKeyFromP12File(p12file);
GoogleCredential credential = credentialBuilder.build();

Теперь вызовите сгенерированный клиент таким же образом вы будете иметь незащищенную версию, за исключением того, что строитель принимает наши учетные данные google сверху как последний аргумент

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