反向工程解析QQ掃碼登陸的OAuth2流程

1. 引言-與OAuth2有關

  OAuth 2.0協議(RFC 6749)被普遍應用於互聯網應用中,最多見的可能就是第三方受權登陸應用了。在許多應用網站中用戶登陸時,能夠使用支付寶、微信、QQ的已有帳號進行登陸,這些應用網站與阿里、騰訊共享了用戶的信息和資源。
  OAuth 2.0協議的中心思想是讓請求用戶資源的一方(在RFC 6749中被稱爲client)向資源擁有方請求訪問權限,請求訪問權限的過程不是經過使用用戶在資源擁有方的訪問權證得到,而是將用戶引向資源擁有方的受權服務器(Authorization Server),經過受權服務器受權後獲得。
  在整個OAuth 2流程中,用戶若是想讓第三方(這裏第三方指用戶、用戶註冊方(支付寶、微信、QQ)以外的第三方)網站使用本身在支付寶、微信、QQ上資源(如帳號、暱稱、頭像)等信息,就須要參與一個與支付寶、微信、QQ受權服務器交互的受權過程。
  圖1以RFC 6749中受權碼方式受權(Authorization Code Grant)方式描述了第三方網站的受權流程。
圖1 受權流程
  咱們以用戶在K網站上使用QQ帳號登陸爲例,用一個典型的開發流程解釋圖1:
  A. 用戶在已進入K網站頁面的瀏覽器上向QQ的受權服務發起用戶資源請求:這裏Client Identifier表示K網站在QQ受權服務器(Authorization Server,實際應用中QQ可能有多個服務器,這裏抽象爲一個受權服務器)上註冊的標識,Redirection URI表示用戶受權成功後K網站的重定向URI,K網站使用該URI來接收受權碼(Authorization Code)。具體的請求參數和格式可參見RFC 6749。
  B. 瀏覽器跳入QQ受權服務器提供的受權頁面,通常該頁面提供兩種方式供用戶受權認證:用戶名/密碼登陸方式和二維碼掃碼登陸方式。
  C. 在獲取到用戶在步驟B中的受權認證後,QQ受權服務器重定向到步驟A中攜帶的重定向URI,並在重定向地址中攜帶受權碼參數。
  D. K網站使用獲取的受權碼向QQ受權服務器請求Access Token,請求中帶上的重定向URI要和步驟A中的重定向URI一致。
  E. QQ受權服務器對參數驗證無誤後,向K網站發送Access Token。
  上面的步驟中,步驟C後向重定向URI進行重定向的操做是由瀏覽器完成的,步驟D的操做在K網站的後臺中完成。K網站的後臺在步驟C後接收受權碼的同時,也得到了瀏覽器的當前session(根據瀏覽器中的Cookie),在步驟E中獲得Access Token後,K網站的後臺向QQ受權服務器獲取對應用戶信息(暱稱、頭像等),將用戶信息放入當前session中後,而後重定向到K網站的主頁面,這時主頁面上就顯示QQ用戶的信息了。html

2. QQ掃碼登陸流程分析

  上一節中,咱們描述了一個典型的基於OAuth2的QQ用戶第三方登陸流程。流程中最核心部分是步驟B,即如何引導用戶向QQ的受權服務器提供受權認證。圖2顯示了QQ提供的認證登陸頁面。
圖2 QQ認證登陸頁面
  QQ的受權服務器提供了兩種受權認證方式:一種是帳號密碼登陸方式,一種是二維碼掃碼方式。對於帳號密碼登陸方式較好理解,由於用戶的受權認證操做是在瀏覽器上進行的,可由瀏覽器直接和QQ受權服務器交互。而二維碼掃碼方式,狀況就更復雜一些,由於多了一個角色參與,這個角色就是用戶手機。實際上用戶的受權認證操做是手機APP(移動QQ)上完成的,可是提供二維碼的瀏覽器須要知道用戶手機的掃描和認證結果,瀏覽器獲取掃描和受權認證結果的途徑是QQ受權服務器。
  反向工程前須要大膽設想,咱們設想QQ二維碼掃碼登陸時的大體流程是這樣的:QQ認證登陸頁面獲取QQ受權服務器產生的二維碼;用戶手機APP掃描該二維碼,並在手機APP上確認受權,該受權信息存儲在QQ受權服務器;QQ認證登陸頁面獲取QQ受權服務器上的本次受權信息,向受權服務器發送獲取受權碼請求。
  在這個流程中,QQ認證登陸頁面和手機APP是分離的兩個客戶端,這兩個客戶端之間經過二維碼聯繫在一塊兒並共享二維碼的掃描結果,QQ認證登陸頁面會使用什麼手段從QQ受權服務器上獲取手機APP上的受權認證結果是須要咱們經過反向工程去探索的。api

3. 反向工程解析

3.1. 流程分析

  在一個提供QQ、微信用戶登陸的第三方網站上執行QQ用戶掃碼登陸,並採集流程中的HTTP消息,可整理出如圖3所示的消息流程(圖中消息10至11流程根據OAuth2協議設計,非反向工程獲取)。
圖3 信令流程
  根據圖3,可描述爲以下流程:
  1. 用戶進入第三方網站主頁,並經過主頁上的登陸按鈕重定向到QQ認證登陸頁面。對應圖3中消息1。
  2. QQ認證登陸頁面向QQ受權服務器請求生成二維碼,該二維碼有惟一標識。對應圖3中消息2。
  3. 用戶使用手機APP掃描該二維碼,並在APP中承認授予的權限,該掃描用戶信息與承認的受權信息保存到QQ受權服務器。
  4. QQ認證登陸頁面根據二維碼標識不斷輪詢QQ受權服務器,看看是否有本次受權認證的信息。對應圖3中消息3。
  5. QQ認證登陸頁面在QQ受權服務器上獲取到本次已經受權的信息後,獲取由服務器返回的登陸用戶信息。對應圖3中消息4,5,6。
  6. QQ認證登陸頁面根據QQ受權服務器返回的信息向QQ受權服務器請求本次OAuth2的受權碼,QQ受權服務器重定向到第三方應用註冊的重定向(回調)URI。對應圖3中消息7,8,9。
  7. 第三方網站後臺根據受權碼向QQ受權服務器獲取Access Token,並根據Access Token獲取用戶信息。對應圖3中消息10,11。須要注意的是:消息10和11流程根據OAuth2協議設計,非反向工程獲取。
  8. 第三方網站後臺向QQ認證登陸頁面返回重定向到第三方網站主頁的請求,QQ認證登陸頁面重定向到第三方網站主頁,這時該主頁中已包含認證登陸的QQ用戶信息。瀏覽器

3.2. 消息分析

  經過上一節的消息流程分析,咱們重點關注一下QQ掃碼登陸的相關消息。
  a) QQ認證登陸頁面請求,對應圖3中消息1。請求格式以下:服務器

GET /oauth2.0/show?which=Login&display=pc&client_id=xxx&redirect_uri=xxx&response_type=code&scope=get_user_info%2Cadd_share HTTP/1.1

  b) 二維碼請求,對應圖3中消息2。
  請求格式以下:微信

GET /ptqrshow?appid=xxxxxx&e=2&l=M&s=3&d=72&v=4&t=0.27689339003885305&daid=383&pt_3rd_aid=101372833

  該請求的迴應中會設置cookie,做爲該二維碼的惟一標識,在後面的二維碼狀態查詢中會用到。以下所示:cookie

set-cookie: qrsig=Ht-tcKP8HsOucEnJLNd4RdqfbCwooJgQ3Z2Qjp5QApi0UoDGCIgPYu8VvQ6dAE8q;Path=/;Domain=ptlogin2.qq.com;

  c) 查詢二維碼掃描受權狀態,對應圖中消息3,4。
  請求格式以下:session

GET /ptqrlogin?u1=https%3A%2F%2Fgraph.qq.com%2Foauth2.0%2Flogin_jump&ptqrtoken=1441332869&ptredirect=0&h=1&t=1&g=1&from_ui=1&ptlang=2052&action=1-0-1533114559274&js_ver=10276&js_type=1&login_sig=EJ7zhLYsxLLTzyvFt57te*RfFnoefvlyL5EPQtIynibZvYDVTFwqp73mYhBZrw15&pt_uistyle=40&aid=716027609&daid=383&pt_3rd_aid=101372833&

  請求中cookie信息以下:app

cookie: pt_login_sig=EJ7zhLYsxLLTzyvFt57te*RfFnoefvlyL5EPQtIynibZvYDVTFwqp73mYhBZrw15; pt_clientip=78f767d654ee2f3d; pt_serverip=612d0af17164d8cd; pt_local_token=55538618; uikey=a295803bda0158cc66a043eadd466549793036cdc18cf00adc324fe62c3dfdbb; pt_guid_sig=f1fb580c215810be91bdc81c31b0dbbf864e8530ff5bbe12a752ec79aa84096f; pgv_pvi=4603649024; pgv_si=s8250232832; _qpsvr_localtk=0.6218837724703585; qrsig=Ht-tcKP8HsOucEnJLNd4RdqfbCwooJgQ3Z2Qjp5QApi0UoDGCIgPYu8VvQ6dAE8q

  cookie中的pt_login_sig和qrsig做爲查詢參數,保證一次生成的二維碼只綁定一個帳號。
  請求的結果中包含當前二維碼的狀態,以下所示:ide

ptuiCB('67','0','','0','二維碼認證中。(1759531849)', '')

  若是用戶已經在手機APP上受權認證,請求的迴應中會返回用戶本次的登陸受權標識,放在頭部的set-cookie中,以下所示(其中出現了掃描用戶的QQ號):網站

set-cookie: pt_guid_sig=ad3f568b9d1d721593fde21261e9110921367f8e918ee573d0290ddde03fe5a9;Expires=Fri, 31 Aug 2018 09:06:36 GMT;Path=/;Domain=ptlogin2.qq.com;
set-cookie: uin=o0545602528;Path=/;Domain=qq.com;
set-cookie: skey=@Xb8aQtVvd;Path=/;Domain=qq.com;
set-cookie: superuin=o0545602528;Path=/;Domain=ptlogin2.qq.com;
set-cookie: pt2gguin=o0545602528;Expires=Tue, 19 Jan 2038 03:14:07 GMT;Path=/;Domain=qq.com;
set-cookie: superkey=iXw-EiDFksitURyqw9dWBfOH7OIowHjqdYZPbu2U2iQ_;Path=/;Domain=ptlogin2.qq.com;HttpOnly;
set-cookie: pt_recent_uins=a82cd26c99dc9b53af5f945be98ce71176658eb32199788d1c479b025d8b0f7a7872d4e9cf761581865bdcff1157eae7684374b9637a77f2;Expires=Fri, 31 Aug 2018 09:06:36 GMT;Path=/;Domain=ptlogin2.qq.com;HttpOnly;
set-cookie: ETK=;Path=/;Domain=ptlogin2.qq.com;
set-cookie: RK=jcDM6tiRa/;Expires=Tue, 19 Jan 2038 03:14:07 GMT;Path=/;Domain=qq.com;
set-cookie: ptnick_545602528=e88b8fe5b79ee7a791e8bebe2de5bca0e587af;Path=/;Domain=ptlogin2.qq.com;
set-cookie: ptcz=cc528e09239038601ee0ab4b7665c65404e847c2963a19d71a266c628029ee22;Expires=Tue, 19 Jan 2038 03:14:07 GMT;Path=/;Domain=qq.com;
set-cookie: ptcz=;Expires=Thu, 01 Jan 1970 00:00:00 GMT;Path=/;Domain=ptlogin2.qq.com;
set-cookie: airkey=;Expires=Thu, 01 Jan 1970 00:00:00 GMT;Path=/;Domain=qq.com;
set-cookie: supertoken=3346071835;Path=/;Domain=ptlogin2.qq.com;

  d) 更新頁面上的cookie,對應圖3中消息5,6。返回的請求頭中包含了一系列的set-cookie與登陸用戶有關,這裏就不貼出來了。
  e) 向QQ受權服務器獲取受權碼,對應圖3中消息7,8。
  請求格式以下:

POST /oauth2.0/authorize

  請求中表單數據以下:

response_type: code
client_id: xxxxxxxxx
redirect_uri: http://www.XXX.com/oauth/callback/type/qq.html
scope: get_user_info,add_share
state: 
switch: 
from_ptlogin: 1
src: 1
update_auth: 1
openapi: 80901010
g_tk: 1934165869
auth_time: 1533114565802
ui: EBF619C8-8BF2-4882-9D8D-8D7E6C0D05E1

  包含的cookie信息以下:

Cookie: ui=EBF619C8-8BF2-4882-9D8D-8D7E6C0D05E1; pgv_pvi=4603649024; pgv_si=s8250232832; _qpsvr_localtk=0.6218837724703585; pt2gguin=o0545602528; uin=o0545602528; skey=@Xb8aQtVvd; RK=jcDM6tiRa/; ptcz=cc528e09239038601ee0ab4b7665c65404e847c2963a19d71a266c628029ee22; p_uin=o0545602528; pt4_token=kME-OHaPJ3rFmtsksNxnUcWYTP6JEWRvd2EX8DHyfAE_; p_skey=oA8SEkIxHh7-2v-XneForJ9gUH4PTgROUPCQ6YdpUzI_

  QQ受權服務器根據請求中表單和cookie中的標識肯定本次掃描確認結果,返回受權碼。迴應消息格式以下:

HTTP/1.1 302 Moved Temporarily
Server: tws
Date: Wed, 01 Aug 2018 09:06:37 GMT
Content-Type: text/html
Content-Length: 0
Connection: keep-alive
Keep-Alive: timeout=50
Content-Encoding: gzip
Location:http://www.XXX.com/oauth/callback/type/qq.html?code=653D0AAEA1EF7D12A4AF99AD4CDC4D41

4. 小結

  咱們經過反向工程結合OAuth2流程分析了在第三方網站上使用QQ掃碼登陸的功能,分析了消息流程與相關消息,明確了大體的實現思路。消息中有些參數(如cookie中的一些鍵值)是QQ特有的,含義也沒法根據流程推斷出來,這就須要騰訊的兄弟去給你們解釋了。

相關文章
相關標籤/搜索