現在掃碼登錄是一種很常見的登錄方式,當用戶需要登錄某個網站時,網站會提供一種掃碼登錄的方式,用戶打開相應的手機App,掃描網站上顯示的二維碼,然后在App中確認登錄,網站監測到用戶確認登錄后,跳轉到登錄成功頁面,從這個形式上看,掃碼登錄就是將用戶在手機App中的登錄狀態同步到網站中,這篇文章就來一窺這個同步是如何發生的,
同一產品中的掃碼登錄
假設有一款產品,這個產品通過手機端App和PC端應用為用戶提供服務,為了方便用戶在PC端上登錄,產品提供了一個掃碼登錄的功能,即PC端應用上展示一個登錄二維碼,用戶使用手機端App掃碼并確認登錄,然后用戶就可以在PC端上登錄成功,在這個例子中,手機端App和PC端應用同屬于一個產品,這是一種常見的產品形態,微信、微博、知乎等等都是這種產品形態的代表,
為了方便介紹,這里再假設PC端應用是一個Web站點,下面就來看一下這種登錄方式的運作原理:

如上圖所示,整個程序比較簡單,這里大概分為如下幾個步驟:
1、用戶發起二維碼登錄:此時網站會先生成一個二維碼,同時把這個二維碼對應的標識保存起來,以便跟蹤二維碼的掃碼狀態,然后將二維碼頁面回傳到瀏覽器中;瀏覽器先展示這個二維碼,再按照Javascript腳本的指示發起掃碼狀態的輪詢,所謂輪詢就是瀏覽器每隔幾秒呼叫網站的API查詢二維碼的掃碼登錄結果,查詢時攜帶二維碼的標識,有的文章說這里可以使用WebSocket,雖然WebSocket回應比較及時,但是從兼容性和復雜度考慮,大部分方案還是會選擇輪詢或者長輪詢,畢竟此時通信稍微延遲下也沒多大關系,
2、用戶掃碼確認登錄:用戶打開手機App,使用App自帶的掃碼功能,掃描瀏覽器中展現的二維碼,然后App提取出二維碼中的登錄資訊,顯示登錄確認的頁面,這個頁面可以是App的Native頁面,也可以是遠程H5頁面,這里采用Native頁面,用戶點擊確認或者同意按鈕后,App將二維碼資訊和當前用戶的Token一起提交到網站API,網站API確認用戶Token有效后,更新在步驟1中創建的二維碼標識的狀態為“確認登錄”,同時系結當前用戶,
3、網站驗證登錄成功:在步驟1中,二維碼登錄頁面啟動了一個掃碼狀態的輪詢,如果用戶已經“確認登錄”,則輪詢訪問網站API時,網站會生成二維碼系結用戶的登錄Session,然后向前端回傳登錄成功訊息,這里登錄狀態維護是采用的Session機制,也可以換成其它的機制,比如JWT,
為了保證登錄的安全,有必要采取一些安全措施,可能包括以下若干方法:
-
對二維碼承載的資訊按照某種規則進行處理,App可以在掃碼時進行驗證,避免任何掃碼都去請求登錄;
-
對二維碼設定一個過期時間,過期就自動洗掉,這樣使其占用的資源保持在合理范圍之內;
-
限制二維碼只能使用一次,防止重放攻擊;
-
二維碼使用足夠長的隨機性字串,防止被惡意窮舉占用;
-
使用HTTPS傳輸,保護登錄資料不被竊聽和篡改,
第三方應用的掃碼登錄
現在很多網站除了提供自身賬號的登錄方式以外,還提供了微信掃碼登錄、微博掃碼登錄等方式,本來這對用戶來說是十分方便的,不過很多站點為了獲取用戶手機號,首次登錄時還需要用手機驗證碼再登錄一次,用戶會有點被欺騙的感覺,不過這個問題不是本文要探討的,
這里以微信掃碼登錄某網站為例,某網站就是第三方應用,所謂第三方是相對微信自身來說的,相比同一產品中的掃碼登錄,網站使用微信掃碼登錄會更復雜一些,因為這涉及到不同應用之間的登錄安全,下面就給出這一登錄方式的詳細運作原理,時序圖比較長,不過只要耐心點就能完全搞清楚,甚至自己實作一個類似的第三方掃碼登錄方案,

這里對一些關鍵點特別說明下:
1、步驟3 生成微信登錄請求記錄:當用戶掃碼并同意登錄之后,步驟25中瀏覽器會重定向到第三方應用,如果之前沒有創建一條登錄請求記錄,網站并不能確定這次登錄就是自己發起的,這可能導致跨站請求偽造攻擊,比如使用某個應用的微信登錄二維碼,騙取用戶的授權,然后最侄訓呼跳轉到其它站點,被回呼站點只能被動接受,雖然下一步驗證授權Code通不過,微信也可能會認為第三方應用出了某種問題,搞不好被封掉,因此第三方應用創建一條登錄請求記錄之后,還要把記錄的標識拼接到訪問微信登錄二維碼的url中,微信會在用戶同意登錄后原樣回傳這個標識,步驟26中第三方應用可以驗證這個標識是不是有效的,
2、步驟17 顯示應用名稱和請求授權資訊:因為微信支持很多的第三方應用,需要明確告知用戶正在登錄哪個應用,應用可以訪問自己的什么資訊,這都是用戶做出登錄決定的必要資訊,因此掃碼之后,微信手機端就需要去微信開放平臺查詢下二維碼對應的第三方應用資訊,
3、步驟24 登錄臨時授權Code:微信開放平臺沒有直接向瀏覽器回傳登錄用戶的資訊,這是因為第三方應用還需要對用戶進行授權并保持會話的狀態,這適合在應用的服務端來處理;而且直接回傳用戶資訊到瀏覽器也是不安全的,并不能保證二維碼登錄請求就是通過指定的第三方應用發起的,第三方應用會在步驟27中攜帶這個授權Code,加上應用的AppId和AppSecret,再去向微信開放平臺發起登錄請求,臨時授權Code只能使用1次,存下來也不能再用,且只能用在指定的應用(即系結了AppId),AppSecret是應用從服務端提取的,用來驗證應用的身份,這些措施保證了微信授權登錄的安全性,不過驗證通過后還是沒有直接回傳用戶資訊,而是回傳了一個access token,應用可以使用這個token再去請求獲取用戶資訊的介面,這是因為開放平臺提供了很多介面,訪問這些介面都需要有授權才行,所以發放了一個access token給第三方應用,這種授權登錄方式叫做OAuth 2.0,基于安全方面的考慮,access token的有效期比較短,開放平臺一般還會發放一個refresh token,access token過期之后,第三方應用可以拿著這個refresh token再去換一個新的access token,如果refresh token也過期了或者用戶取消了授權,則不能獲取到新的access token,第三方應用此時應該注銷用戶的登錄,這些token都不能泄漏,所以需要保存在第三方應用的服務端,
這里有一個有意思的問題:為什么微信的二維碼登錄頁面Url中沒有第三方應用的簽名?
以極客時間的這個微信登錄二維碼頁面的Url為例:
https://open.weixin.qq.com/connect/qrconnect?appid=wx1b4c7610fc671845&redirect_uri=https%3A%2F%2Faccount.geekbang.org%2Faccount%2Foauth%2Fcallback%3Ftype%3Dwechat%26ident%3Dc75c4a%26login%3D0%26cip%3D0%26redirect%3Dhttps%253A%252F%252Faccount.geekbang.org%252Fthirdlogin%253Fremember%253D1%2526type%253Dwechat%2526is_bind%253D0%2526platform%253Dtime%2526redirect%253Dhttps%25253A%25252F%25252Ftime.geekbang.org%25252F%2526failedurl%253Dhttps%253A%252F%252Faccount.geekbang.org%252Fsignin%253Fredirect%253Dhttps%25253A%25252F%25252Ftime.geekbang.org%25252F&response_type=code&scope=snsapi_login&state=5682d8310b75cd477baf30489e673646#wechat_redirect
其中appid是微信開放平臺分配給極客時間的應用Id;redirect_uri是用戶授權登錄后微信回呼的極客時間url,雖然看起來很長,其實就是在極客時間內的頁面之間跳來跳去;state是極客時間生成的一個登錄id,不同的state會生成不同的二維碼,微信回呼極客時間的時候會帶著這個state,
這個url中只有極客時間的appid,沒有極客時間的簽名,也就是說微信會生成極客時間的登錄二維碼,但是不驗證這個二維碼登錄請求是不是極客時間發起的,那么任何人都可以生成極客時間的微信登錄二維碼頁面,這好像不太嚴謹,
這樣安全嗎?攻擊者可以很簡單的獲取某個應用的微信登錄二維碼,然后再騙取用戶的登錄授權(這個也相對簡單,弄個假冒的網站,或者直接話術忽悠,用戶很可能不仔細看掃碼確認的內容),再通過瀏覽器攔截或者DNS攻擊獲取到臨時授權Code,直接越過檢查應用State,前邊這些都相對容易,但是向微信驗證臨時授權Code的時候必須攜帶App Secret,這個就很難了,除非第三方應用開發者自己泄漏了這一核心機密,對于用戶資訊的保護,整體上來說是安全的,攻擊者基本上拿不到訪問用戶資訊的access token,如果在url中加上這個簽名,對用戶資訊的保護作用也沒有加強,授權Code還是很容易獲取;而且簽名一般也是依賴App Secret,如果泄漏了App Secret,簽名也就失去了意義,
如果有人不斷地生成某個應用的微信登錄二維碼怎么辦?這是其他型別的攻擊了,微信可以采取一些限流措施,甚至直接封掉某些IP,這對正常用戶沒什么影響,
微信二維碼登錄的變種
微信除了跳轉到二維碼登錄頁面的方式,還提供了第三方網站中內嵌二維碼的方式,通過微信JS SDK生成二維碼并在網頁的指定區域展現,用戶掃碼同意登錄后,微信JS SDK發起重定向或者在iframe中打開應用回呼頁面,傳遞臨時授權Code和應用State,后續的流程就都一樣了,
另外這里的第三方應用如果是移動端App,微信開放平臺也支持掃碼登錄的方式,區別在于需要集成微信SDK,獲取二維碼和接收用戶授權Code都是通過SDK回呼的方式,后續的流程也都一樣,
以上就是本文的主要內容了,鑒于本人才疏學淺,如有錯漏歡迎指正,
識訓更多架構知識,請關注公眾號 螢火架構,原創內容,轉載請注明出處,
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/420431.html
標籤:其他
上一篇:會計學包含的兩種程式設計思想
