OAuth2 授權碼模式為什么不直接返回access_token


 

OAuth2的實際應用中,最常見的就是“授權碼模式”了。 
微博是這種模式,微信也是這種模式。 
總結來說,就是簡單的二步: 

Java代碼   收藏代碼
  1. 1.獲取code  
  2. 2.根據code,去獲取access_token  




以微博為例(http://open.weibo.com/wiki/%E6%8E%88%E6%9D%83%E6%9C%BA%E5%88%B6%E8%AF%B4%E6%98%8E):

假設我們開發一個網站(稱為client;相對應的,微博就是server了),網站允許用戶以微博賬號登錄,且需要讀取用戶的微博信息(賬號、評論等等)。 
顯然,這過程中需要用戶授權。 

第一步: 

Java代碼   收藏代碼
  1. https://api.weibo.com/oauth2/authorize?client_id=YOUR_CLIENT_ID&response_type=code&redirect_uri=YOUR_REGISTERED_REDIRECT_URI  


第二步: 

Java代碼   收藏代碼
  1. https://api.weibo.com/oauth2/access_token?client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET&grant_type=authorization_code&redirect_uri=YOUR_REGISTERED_REDIRECT_URI&code=CODE  



這其中有幾個問題: 
1.獲取code時,傳遞的二個變量(clent_id,redirect_url),沒有一個是跟用戶有關的,那微博怎么知道我們請求的是哪個用戶的授權呢? 
這個問題現在看來很可笑,但剛開始確實是蒙圈了。 
其實,在第一步的URI發出后,是要求用戶跳轉到server端登錄的。這很好理解,如果用戶不登錄,那你怎么知道是哪個用戶呢,他又怎么給你授權呢? 
此外,可以看到,第一步的URI,放在我們網站頁面的任何位置都可以;它也不要求傳遞跟session相關的任何信息。 
這個URI對應的頁面是微博開發的,跟我們網站沒關系。 
事實上,這個URI可以直接拷貝到瀏覽器里發起請求;這個時候,是瀏覽器跟微博的一個交互,我們的網站是一無所知的。 
那什么時候我們得知用戶給我們授權了呢? 
第一步URI的請求,瀏覽器得到的是一個http的重定向響應,這個重定向指向的就是我們的網站;此時瀏覽器向我們的網站發起請求: 
類似於: 
https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA&state=xyz 
站在我們網站后台程序的角度來看,我們是“忽然”(在此這前,它一無所知)收到一個code了,而這個code,是跟微博的一個用戶一一對應的,我們拿這個code向微博發起請求,就能獲得用戶的授權,獲得access_token,再發起另一請求,就可以獲取用戶信息了。 

2.為什么在第一個URI請求發出后,微博的302重定向響應中,沒有直接返回access_token,而是只返回一個code呢? 
其實最初我的疑問更可笑:我想,為什么微博不直接返回access_token給我們網站呢? 
這個問題的答案是,發起第一步的URI請求的,是瀏覽器!還記得前面我說的“我們的網站是一無所知”嗎?此時微博是與瀏覽器在通信,而不是我們的網站,當然不能把參數傳返回到我們網站了。 
微博只能通過返回一個302響應,讓瀏覽器重新向我們網站發起請求,把code傳到我們網站來。 

回到第二個問題。 
該博客下有人是這樣回答的: 

Java代碼   收藏代碼
  1. 為什么授權碼模式需要這個授權碼 當然是為了安全性 首先在OAuth體系中access_token是作為訪問獲取資源的唯一憑據 如果在AS授權完成之后 直接通過重定向傳回access_token 那么HTTP 302不是安全的 Attacker有可能會獲取到access_token 但是如果只返回Authorization code 就算別人獲得了也沒什么卵用 因為Authorization code不能獲取到資源 在client向AS請求access_token的過程中 是通過HTTPS來保證安全的 而且獲得access_token是需要client secret與Authorization code一起的 Attacker知道了Authorization code但並不知道client secret 同樣也不能獲得到access_token 所以client與AS是有責任保護好client secret的  
  2. 獲得了access_token之后 向RS發起請求 RS其實會與AS交互 來校驗access_token 所以你想直接偽造一個access_token 那也是不ok的  
  3.   
  4.   
  5. 突然想到漏說了一塊 關於為什么不直接用HTTPS重定向回client  
  6. 是因為不是所有client server都支持HTTPS~所以為了通用性 和安全性 才衍生出來這么一個Auth code  
  7. 但是AS肯定是實現HTTPS的 所以在client向AS提起request 是木有問題的~  



我自己的理解,是這樣的: 
直接返回access_token有可能被黑客攔截到,而拿到access_token就可以獲得用戶信息了,非常不安全。 
那最容易想到的是,微博通過https返回access_token啊,https會對access_token加密,那不就可以了嗎? 
為什么這個方法不可行呢? 
因為有可能我們的網站不支持https!站在微博的角度來看,千千萬萬的第三方網站,你要求每個網站都支持https,是不太現實的。 
stackoverflow上的一個回答(http://stackoverflow.com/questions/13387698/why-is-there-an-authorization-code-flow-in-oauth2-when-implicit-flow-works-s)說這是“一個巨大的痛苦”:“a huge pain”。 

那為什么返回code再去獲取access_token就安全了呢? 
因為這時候再去獲取access_token,就是https請求了,發起方為我們的網站,接收方為微博,而微博作為OAuth server,肯定提供https。 
但是,另一個問題來了,黑客拿到了code,它也向微博發起請求去獲取access_token是不是就可以了呢? 
也是不可以的。 
因為向微博請求access_token時,還要帶上我們網站的“密碼”(client secret)。 
這個密碼,是我們網站在微博開放平台上注冊時獲得的(同時會得到一個client_id,這個值在第一步的URI里用到了)。 
這一點在該博客沒有提出來,最容易讓人困惑。 

3.為什么簡化模式(implicit grant type)是可行的? 
這個在stackoverflow有回答,前面也提到過: 
http://stackoverflow.com/questions/13387698/why-is-there-an-authorization-code-flow-in-oauth2-when-implicit-flow-works-s 

這就涉及到一個知識點: 
瀏覽器不會把URL當中的“hash fragment”發給服務器。hash fragment是只留在瀏覽器的地址欄的,它可以被網頁的js讀取到:window.location.hash。 
既然hash fragment沒有發給服務器,那即使黑客攔截到請求,也獲取不到它。 
什么是hash fragment?就是URL當中#號后面的那一部分。 
博客中的示例: 

Java代碼   收藏代碼
  1. HTTP/1.1 302 Found  
  2. Location: http://example.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA&state=xyz&token_type=example&expires_in=3600  



可以得知,“#access_token=2YotnFZFEjr1zCsicMWpAA”這一部分是留在瀏覽器這邊的。 
當瀏覽器接收到到該響應時,向http://example.com/cb發起請求,而后者的響應頁面當中,應當有讀取hash fragment的代碼。 
這樣,client就拿到了access_token了。 

解決了這三個問題,我本想到實際場景中抓包看看的,但遺憾的是,不管是蘑菇街還是聚美優品,這些允許以微博賬號登錄的網站,都只看到獲取code那一步,沒有看到獲取access_token那一步。 
或許改天有空可以自己在微博開放平台上注冊一個應用來驗證一下。 
不過網上有人驗證過微博的: 
https://segmentfault.com/a/1190000000666685 

此外還有一些關於微信OAuth2的實際例子: 
http://www.cnblogs.com/txw1958/p/weixin71-oauth20.html 
http://zeusjava.com/2015/04/22/wechat-get-userinfo/ 
都講得比較詳細。 

 

zz:https://bylijinnan.iteye.com/blog/2277548


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM