2012-11-06 1 views
5

Mam dwie aplikacje na Google App Engine, obie działają pod tym samym kontem, a jedna wywołuje usługi świadczone przez drugą za pośrednictwem protokołu HTTPS. Jaki jest zalecany sposób zagwarantowania, że ​​tylko pierwsza aplikacja może wywołać drugą?Google App Engine: bezpieczna komunikacja między aplikacjami

Czy istnieje możliwość określenia, że ​​dany punkt końcowy może być wywołany tylko przez aplikację działającą pod tym samym kontem GAE?

Odpowiedz

3

Poproś o sprawdzenie aplikacji pod kątem nagłówka "X-Appengine-Inbound-Appid" i upewnij się, że identyfikator aplikacji jest poprawny. Ten nagłówek istnieje tylko wtedy, gdy żądanie zostało wysłane przez inną aplikację Google App Engine i nie może być modyfikowane przez użytkowników.

Jeśli używasz Pythona, można wykonać następujące czynności:

import webapp2 

AUTHORIZED_APPS = ('my-first-app', 'my-other-app') 

class MyHandler(webapp2.RequestHandler): 
    def dispatch(self): 
     app_id = self.request.headers.get('X-Appengine-Inbound-Appid', None) 

     if app_id in AUTHORIZED_APPS: 
      super(MyHandler, self).dispatch() 
     else: 
      self.abort(403) 

To podniesie 403 dla każdego wniosku, że nie ma to X-AppEngine-Inbound-AppID w jego nagłówku.

Ponadto podczas wysyłania żądań z jednej aplikacji do drugiej przy użyciu urlfetch, należy ustawić follow_redirects = False lub nagłówek nie zostanie dodany.

+0

Czy osoba znająca identyfikatory aplikacji z autoryzowanych aplikacji nie może podszyć się pod nią ręcznie, dodając nagłówek ręcznie? –

+0

Nie. "Ten nagłówek nie może zostać sfałszowany przez inne aplikacje lub usługi zewnętrzne - jest czyszczony przez system App Engine" http://stackoverflow.com/a/7961397/789417 –

+0

Powyższy kod nie będzie działał, jeśli Nagłówek X-Appengine-Inbound-Appid nie występuje. Jeśli nagłówek nie jest obecny, app_id będzie Brak. Sprawdzanie, czy Brak jest w krotce, spowoduje wystąpienie TypeError. To, czego naprawdę potrzebujesz, to AUTHORIZED_APPS, aby być listą. Sprawdzanie, czy brak jest na liście, jest poprawną czynnością w Pythonie. – timbo

1

Najprostszym sposobem (i wystarczająco dobrym w tym przypadku) byłoby zawarcie tajnego klucza w nagłówku HTTP i sprawdzenie go po stronie obsługującej.

+0

Dzięki, że rzeczywiście to, co robię w tej chwili. Zastanawiam się, czy istnieje jakiś sposób obsługi tego mechanizmu, który wykorzystuje fakt, że aplikacje działają na tym samym koncie. –

2

Możesz sprawdzić usługę App Engine za Application Identity.

+0

Dzięki; jest to prawdopodobnie bardziej skomplikowane niż to, czego potrzebuję, ale dobrze jest wiedzieć. –

2

Jak inni zwrócili uwagę, powołując się na nagłówku X-AppEngine-Inbound-AppID jest wypełniony jest najprostszym rozwiązaniem. Ostatnio miałem podobny problem, ale nie mogłem użyć X-Appengine-Inbound-Appid, ponieważ funkcja URLFetch nie była dostępna (GAE Node.js). Oto, jak rozwiązać problem za pomocą kont usług uwierzytelnionych za pośrednictwem protokołu OAuth.

Po stronie nadawcy, czego potrzebujesz skonfigurować konto usługi: https://developers.google.com/identity/protocols/OAuth2ServiceAccount#creatinganaccount

Następnie w tej aplikacji będzie trzeba uzyskać poświadczenia konta usługa: https://developers.google.com/identity/protocols/application-default-credentials

Następnie można użyć poświadczeń, aby authClient, którego można użyć do wysłania żądania. Będziesz musiał dodać zakres OAuth do swojego authClient. Najbardziej logiczne do użycia jest https://www.googleapis.com/auth/userinfo.email. Umożliwi to odbiorcy uzyskanie adresu e-mail konta usługi nadawcy. https://developers.google.com/identity/protocols/googlescopes

Oto kod za to, że pracują w (nadawcę) node.js:

process.env.GOOGLE_APPLICATION_CREDENTIALS = <PATH TO CREDENTIALS FILE> 

google.auth.getApplicationDefault((err, authClient) => { 
    if (err) { 
    console.log("Failed to get default credentials: ", String(err)); 
    return; 
    } 

    if (authClient.createScopedRequired && authClient.createScopedRequired()) { 
    authClient = authClient.createScoped([ 
     'https://www.googleapis.com/auth/userinfo.email' 
    ]); 
    } 

    auth_client.request({ 
    url: <RECEIVER URL>, 
    method: "GET" 
    }, (error, result, response) => { 
    // Process response 
    }); 
}); 

Następnie po stronie odbiornika trzeba zweryfikować adres e-mail zgodny z adresem e-mail z konta usługi nadawcy. Gdy mechanizm aplikacji jest wywoływany lokalnie, żądanie OAuth nie jest poprawnie uwierzytelniane, więc jeśli chcesz przetestować lokalnie, musisz pobrać adres URL, aby samemu zweryfikować żądanie.

Odbiornik Python:

scope = "https://www.googleapis.com/auth/userinfo.email" 
allowed_users = set([ 
    "<SENDER SERVICE ACCOUNT EMAIL>" 
]) 
IS_DEV = os.environ["SERVER_SOFTWARE"][:3] == "Dev" 

class MyHandler(webapp2.RequestHandler): 
    def get(self, clientId): 
     user = self.get_current_user() 
     if user in allowed_users: 
      # Do whatever you wanted 

    def get_current_user(self): 
     if IS_DEV: 
      token = self.request.headers.get("Authorization")[len("Bearer "):] 
      response = urlfetch.fetch(
       "https://www.googleapis.com/oauth2/v3/tokeninfo?access_token=%s" % token 
      ) 
      return json.loads(response.content)["email"] 
     else: 
      return oauth.get_current_user(scope)