2012-11-06 77 views
5

我在Google App Engine上有兩個應用程序,它們都在同一個帳戶下運行,並且一個通過HTTPS調用其他應用程序提供的服務。什麼是確保只有第一個應用程序被允許調用第二個應用程序的建議方法?Google App Engine:安全的應用程序間通信

另外,有沒有一種方法可以指定給定的端點只能由在同一個GAE帳戶下運行的應用程序調用?

回答

3

讓您的應用程序檢查'X-Appengine-Inbound-Appid'標題並確保應用程序ID是正確的。此標頭僅在該請求是由其他Google App Engine應用程序進行且不能由用戶修改時才存在。

如果您正在使用Python,你可以做到以下幾點:

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) 

這將提高403爲不具有X-AppEngine上,入站的appid在其頭部的任何請求。

此外,使用urlfetch從一個應用程序向另一個應用程序發出請求時,請確保您設置了follow_redirects = False或者未添加標頭。

+0

知道授權應用程序的應用程序ID的人不能通過手動添加標題來模擬它們嗎? –

+0

編號「此標頭不能被其他應用程序或外部服務僞造 - 它由App Engine系統消毒」http://stackoverflow.com/a/7961397/789417 –

+0

上述代碼實際上不起作用X-Appengine-Inbound-Appid頭不存在。如果標題不存在,app_id將爲None。檢查無是否在元組中會產生TypeError。你真正想要的是將AUTHORIZED_APPS作爲一個列表。檢查無是否在列表中是在Python中執行的有效事情。 – timbo

1

最簡單的方法(在這種情況下足夠好)將包括在HTTP標頭中的祕密,並在服務端檢查它。

+0

謝謝,實際上我此刻在做什麼。我想知道是否有一些特定於App Engine的方式來處理這個問題,它利用了應用程序在同一個帳戶下運行的事實。 –

2

您可能希望查看App Engine的Application Identity服務。

+0

謝謝;這可能比我需要的更復雜,但是很好理解。 –

2

正如其他人所指出的那樣,依靠頭部X-AppEngine上,入站的appid正在填寫是最簡單的解決方案。我最近有類似的問題,但我無法使用X-Appengine-Inbound-Appid,因爲URLFetch不可用(GAE Node.js)。以下是使用通過OAuth驗證的服務帳戶解決問題的方法。

你需要建立一個服務帳戶的發送方: https://developers.google.com/identity/protocols/OAuth2ServiceAccount#creatinganaccount

然後在應用程序,你將需要得到服務帳戶憑據: https://developers.google.com/identity/protocols/application-default-credentials

然後你可以使用的憑據,使一個authClient,可以用來發送請求。您需要將OAuth範圍添加到authClient。最合理的使用是https://www.googleapis.com/auth/userinfo.email。這將使接收者能夠獲得發件人服務帳戶的電子郵件地址。 https://developers.google.com/identity/protocols/googlescopes

這裏是使其工作在(發件人)代碼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 
    }); 
}); 

然後在接收端則需要驗證的電子郵件地址發送者的服務帳戶的電子郵件地址相匹配。當應用引擎在本地被調用時,OAuth請求沒有被正確認證,所以如果你想在本地進行測試,你將不得不做一次url提取來自己驗證請求。

接收機的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) 
相關問題