過去曾使用「Google 試算表」來打造及存放會員系統,而會員註冊的部分可利用「FB API 製作登入按鈕」取得帳號資訊。但 FB API 限制較多也不好操作,後來使用「Google API 製作登入按鈕」取得基本資訊,並搭配「People API」取得更多個人資訊。 有第三方 API 處理會員註冊問題真的方便又安心,不用經手棘手的帳號密碼問題,可參考「FB API 製作登入按鈕」的詳細說明。不過久了可能會面臨一種狀況:「被大量惡意註冊怎麼辦?」當提供的服務如果出名、爆紅了,就會有各種原因出現大量註冊,例如用來鑽漏洞、或是被公關公司盯上成為目標。 前端經第三方 API 取得的使用者資訊不會有什麼問題,但傳送到後端的資料就無法保證了,一方面所有中繼傳輸設備都可能被攔截,一方面有心人說不定已寫好了執行腳本,跳過前端直接發送大量的假帳號註冊請求給後端,一次註冊了幾百個帳號也說不定。 依照這樣的攻擊手法,我們有可能在後端辨識出,這幾百個註冊的 Google 帳號是真是假嗎? (圖片出處: pixabay.com) ID 、暱稱 、頭像 、Email 。接著儲存到資料庫後,要拿 ID 或 Email 做為單一不重複的帳號依據都可。 然而前端傳送到後端的註冊請求,資訊想造假並不困難,"暱稱"、"頭像"、"Email" 就不用說了,如果 "ID" 資訊是假的,後端有辦法判斷嗎?畢竟 ID 是第三方 API 產生的,我們不會知道運算邏輯,所以哪知道這字串是真是假~ 好消息是,實際上別說 "ID",我們連 "暱稱"、"頭像"、"Email" 全部的資訊都有辦法辨別真偽!趕快來看看是怎麼回事。
一、Google API 使用者資訊
首先複習一下「Google API 登入按鈕」,Google 登入後可以取得這些公開資訊:二、後端進行身份驗證
根據 Google 官網文件「使用後端服務器進行身份驗證」,官方明確告知我們要如何對使用者進行身份驗證:如果您將Google登錄用於與後端服務器通信的應用或網站,則可能需要識別服務器上當前登錄的用戶。為了安全地執行此操作,請在用戶成功登錄後,使用HTTPS將用戶的ID令牌發送到您的服務器。然後,在服務器上,驗證ID令牌的完整性,並使用令牌中包含的用戶信息建立會話或創建新帳戶意思就是說,使用者在前端登入 Google 帳號後取得的資訊,其中包含了 "ID令牌",也就是 ID token,必須傳到後端伺服器進行驗證。驗證無誤後,再將 ID token 中包含的使用者資訊(這才是不會被竄改的資訊)進行註冊之用。 根據官網說明,驗證 ID token 的網址如下:
https://oauth2.googleapis.com/tokeninfo?id_token=這裡是 ID token 字串
如果 id_token 驗證無誤,就會傳回使用者資訊,此時可以跟前端接收到的使用者資訊一一比對,就能驗證 Google 帳號的註冊資料真假了。官網也提供該網址回傳的資料範例,大概長這樣: { "iss": "https://accounts.google.com", "sub": "110169484474386276334", "azp": "1008719970978-hb24n2dstb40o45d4feuo2ukqmcc6381.apps.googleusercontent.com", "aud": "1008719970978-hb24n2dstb40o45d4feuo2ukqmcc6381.apps.googleusercontent.com", "iat": "1433978353", "exp": "1433981953", "email": "testuser@gmail.com", "email_verified": "true", "name" : "Test User", "picture": "https://lh4.googleusercontent.com/-kYgzyAWpZzJ/ABCDEFGHI/AAAJKLMNOP/tIXL9Ir44LE/s99-c/photo.jpg", "given_name": "Test", "family_name": "User", "locale": "en"}
主要看看 name、email、picture(頭像網址) 這幾項是否吻合就可以了。 三、取得 id token 範例程式碼
修改一下「Google API 登入按鈕」的範例程式碼,就可取得 id_token、access_token 等資訊:<script src="https://apis.google.com/js/platform.js" async="async"></script> <meta name="google-signin-client_id" content="5432xxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com"/> <div class="g-signin2" data-onsuccess="onSignIn"></div> 目前狀態: <span id="GOOGLE_STATUS_1"></span> <script> // 登入之後 function onSignIn(googleUser) { var profile = googleUser.getBasicProfile(), target = document.getElementById("GOOGLE_STATUS_1"), html = ""; html += "ID: " + profile.getId() + "<br/>"; html += "會員暱稱: " + profile.getName() + "<br/>"; html += "會員頭像:" + profile.getImageUrl() + "<br/>"; html += "會員 email:" + profile.getEmail() + "<br/>"; html += "id token:" + googleUser.getAuthResponse().id_token + "<br/>"; html += "access token:" + googleUser.getAuthResponse(true).access_token + "<br/>"; target.innerHTML = html; } </script>
- 紅色字串改為自己的「用戶端 ID」,請參考前一篇所有流程注意事項
四、驗證 id token
下面是以上範例程式碼「官方 Google 登入按鈕」的效果,執行登入可取得各項資料: 目前狀態: 如前面「二、後端進行身份驗證」的說明,以下紅字改為自己的 id token 字串即可取得驗證結果:https://oauth2.googleapis.com/tokeninfo?id_token=這裡是 ID token 字串
五、驗證 access token
前面的範例程式碼附帶提供了 access token 資訊,取得的方式請參考討論串「How to properly get Access Token from logged in Google Sign In」。 這裡額外說明如何驗證 access token 真偽。此討論串「How can I verify a Google authentication API access token?」提到 Google 兩個版本的驗證網址:https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=這裡是 access token 字串https://www.googleapis.com/oauth2/v3/tokeninfo?access_token=這裡是 access token 字串
任選一個將紅字改為自己的 access token 字串即可取得驗證結果。 更多「資訊安全」相關文章: