顯示具有 JSONP 標籤的文章。 顯示所有文章
顯示具有 JSONP 標籤的文章。 顯示所有文章

2015年2月16日

Web Authentication in Chrome extension 外掛環境的網站授權筆記

這篇筆記主要紀錄在 Google Chrome Extension 環境如何取得使用者 identity 以及使用Google Oauth2 授權。

chrome.identity


在 Google Chrome 想要拿到一個使用者身分最基本的情況只要使用 chrome.identity 就可以了,可以取得 access_token 後丟給 server 取得身分。

1. chrome.identity.getAuthToken 取得 access_token ,這個 token 會被 cache 在 Chrome identity API裡面一陣子,第二次之後取得會很快,相對需要手動 removeCachedAuthToken 來刪除。scope 則是在 plugin 的 manifest.json 中定義。

2. 取得 access_token 後可以在 server 或是 client 使用 'Authorization' header 向 Google API URI 要資料。

在 background page 呼叫 chrome.identity 可以指定 interactive 和登入身分,但是這個登入身分和類似API中的 login_hint 不同,chrome.identity 限制這個身分是當下 Chrome Browser 使用者的身分之一,而且使用者必須要在登入狀態,跟我們常看到的一個頁面給使用者選擇要登入不同身分登入的情況不同,開發者即使知道欲取得的 user email or user ID 也無法提示使用者這個已知,使用者也無法選擇。


Web Server Oauth Process


另一個方法使用 Google Oauth2 的 web process ,引導使用者跳轉或是開啟一個授權頁面,使用者授權後 Google 會把一組 code 丟給 redirect_uri (你的server),然後再用這組 code 去取得 access_token and/or refresh_token ,這個方法使用者就可以選擇登入的帳號了,如果知道使用者的 email 還可以先提示 login_hint ,這樣使用者可以少一個選帳號的動作,使用者如果授權過同樣的 scope 這個 interactive 過程會直接帶過,而且一個 Chrome Browser 可以取得多組 Google Account 身分和授權,不受限制。

Server 知道身分之後要怎麼給 client 呢?可以透過 session 讓 client 知道使用者登入了等一些資訊,有點被動,還是要用 long polling / websocket 等牛刀,另外 background page 是沒有存 web cookie 的獨立環境,授權流程如果放進 web page 裡面,還要考慮 Content Security Policy ,我就把外掛裝在 business Gmail 的時候可以運作,但是一登入 @gmail.com 的 Gmail 頁面就噴 Content Security Policy Error 了,同樣是 Gmail 介面沒想到 Content Security Policy 官版的比較嚴格。


Mix JSONP Authentication Process

我的網站沒有提供 Google Account 登入,因為估計目標市場只有很少使用人使用 Google Account for work。我在網站提供一組 JSONP 讓,Chrome Extension 來抓,這個抓授權的 javascript 只能放在 content script 裡面,不能放在 web page 或 background page , web page 可能有 http/https 限制、Content Security Policy。Google Oauth則在需要取得授權的時候才跑 Web Server Oauth Process.

manifest.json 裡面的 content_security_policy 是限制開發者自帶的 script 的環境,如果要配合 gmail.js 把 script 都丟進 web page ,那就要受到 web page 的環境的(web owner 決定) policy 管制。



2013年6月25日

CORS and JSONP

第一次遇到cross origin resource sharing問題是在2010年的時候,我配合amazon affiliate program做了一個很陽春廣告聯播系統,我提供一組js,嵌入這個js的網站可以展示我選的商品,當時就是用JSONP做的,而最後其實也只放在我的一個網站上而已,那時我深信我挑選的商品CPA獲利會比google的廣告CPC還要好,不過後來證明我大大的錯了,一個商品都沒有賣出,自製的廣告聯播系統的開發也就沒有再開發了。


CORS

Cross origin resource sharing,CORS 主要是為了可以取得 cross-domain 的資源,阻止我們用javascript 直接取的 cross-domain 遠端資源的主因是 same origin policy,CORS 提供一種方法可以讓 server 決定是否允許這種 cross-origin 的 request ,這比較麻煩,但是比沒有 same origin policy 來的安全。

CORS 的實作方式比較麻煩,主因是一些特立獨行的瀏覽器的緣故,現行最新的瀏覽器都提供了 XMLHttpRequest 物件,但是IE8自創了一組 XDomainRequest 物件逼你使用,一般檢測方式是看 XMLHttpRequest 創造出來的物件實例是否含有 withCredentials 屬性,沒有的話就要撤退到XDomainRequest,要注意兩者 callback function 返回的參數不同,要另外處理。

再來就是更有古早味的瀏覽器Opera10, < IE 8, < FireFox 3.5,沒有這些功能,必須要用flash來hack,要是遇到沒裝flash的話,基本上就gg。所以 CORS 對於老瀏覽器的支援並不好。另外在server端也要配合,處理這樣的 request,就是我們以前會看到的 crossdomain.xml ,放在domain 根目錄,e.g mydomain.com/crossdomain.xml。

crossdomain.xml 要設定

<?xml version="1.0"?> <!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd"> <cross-domain-policy> <allow-access-from domain="*" /> <allow-http-request-headers-from domain="*" headers="*" /> </cross-domain-policy> 

並且需要修改request 回應的 header


Access-Control-Allow-Methods: GET, POST, OPTIONS Access-Control-Allow-Credentials: true Access-Control-Allow-Origin: http://domain-of-the-resource.com Access-Control-Allow-Headers: Content-Type, *

要注意的是Access Control Allow Origin不能使用 wildcard ,IE說不行


JSONP

JSON-P 支援所有瀏覽器,他是利用呼叫遠端的 javascript function 來達到 cross-domain ,這個 function  在回傳時候會被執行,我們可以藉此來或的包覆在其中的資料,要注意的是被包覆的資料不一定要是 JSON 格式,有時候我們不會使用 JSON ,而是返回字串,因為原生JSON 支援是在 IE8+, Firefox 3.1+, Safari 4+, Chrome 3+, Opera 10.5+ 才有的。

server 端的回應處理很簡單,用收到的 callback function name 消毒後把原本的回應包起來就可以了,這裡要小心回應的XSS攻擊,因為 callback function name 可能是任何字串,也可能是一段程式。

由於引用了一段 resource server 的程式碼,resource server 基本上可以對網站做任何事情,使用JSONP 必須要完全信任 resource server 的安全性。

另外要注意的是,JSONP只支援GET request,而且也要小心CSRF,登入的使用者在造訪惡意頁面的時候會被獲取和操作在 resource server 上的資料,由於使用者造訪的網頁不是 resource server 所產生的,所以並沒有一個簡單的方法來防止CSRF,因此第一,不要放敏感的資料,敏感資料使用一般方式傳遞,第二,通常的配合方法是你給這些 partner 網站一組public/private key pair,他們在 request 的時候把 public key 和加密過的訊息傳給你驗證,並且整個流程透過 ssl 來使用。