一、CORS 是什麼?
出於安全原因,瀏覽器會限制指令碼發起的跨域 HTTP 請求,除非伺服器同意訪問。譬如伺服器對預檢請求的響應 Header 中有 Access-Control-Allow-Origin: *
,那麼跨域請求即可正確訪問。
二、危害舉例
如果惡意網頁中含有這樣的指令碼程式碼 fetch("example.com")
,而你已經登入了 example.com
網站還沒有退出,如果此時沒有 CORS 限制,那麼惡意網頁中的指令碼程式碼就會順利透過伺服器執行,您的大量個人資訊會被洩露。
三、預檢請求是什麼?
為了避免跨域請求對伺服器的資料產生不可知的影響,瀏覽器會用 OPTIONS 方法,先傳送一個預檢請求(preflight request),待伺服器確認可以訪問後,再傳送實際請求。
下面這個 POST 請求,就會先傳送預見請求,可以在控制檯的網路連線中檢視具體連線和資訊。
var invocation = new XMLHttpRequest();
var url = 'http://bar.other/resources/post-here/';
var body = '<?xml version="1.0"?><person><name>Arun</name></person>';
function callOtherDomain() {
if (invocation) {
invocation.open('POST', url, true);
invocation.setRequestHeader('X-PINGOTHER', 'pingpong');
invocation.setRequestHeader('Content-Type', 'application/xml');
invocation.onreadystatechange = handler;
invocation.send(body);
}
}
四、怎麼用 CORS?
CORS 的工作主要在服務端,透過返回不同的 Header 來告知請求者,是否可以訪問?下面兩個部分列出了 CORS 所有用到的 Header 及其含義。
1、其他使用場景
CORS 可以配合 token 來防止 CSRF 攻擊。詳情,看這裡!
五、客戶端跨域請求
跨域請求用到如下 Header ,無須手動設定,瀏覽器會自動設定。
1、origin
預檢請求和實際請求中的源站名稱,不包含任何路徑資訊,只是伺服器名稱。
Origin: <origin>
2、Access-Control-Request-Method
用於預檢請求,告訴伺服器,實際請求 使用什麼方法:post、get 等。
Access-Control-Request-Method: <method>
3、Access-Control-Request-Headers
用於預檢請求,告訴伺服器,將實際請求所攜帶的首部欄位。
Access-Control-Request-Headers: <field-name>[, <field-name>]*
六、伺服器響應跨域請求
1、Access-Control-Allow-Origin
用於響應預檢請求,表示允許該資源的外域 URI
// 允許所有 Access-Control-Allow-Origin: * // 只允許 http://mozilla.com Access-Control-Allow-Origin: http://mozilla.com
2、Access-Control-Expose-Headers
對於自定義的 Header ,必須這裡設定,客戶端才能正常訪問
Access-Control-Expose-Headers: X-My-Custom-Header, X-Another-Custom-Header
3、Access-Control-Max-Age
設定預檢請求的結果能夠被快取多少秒?
Access-Control-Max-Age: <delta-seconds>
4、Access-Control-Allow-Credentials
當跨域請求中設定了
credentials=true
,但服務端響應中沒有Access-Control-Allow-Credentials: true
,那麼瀏覽器是不會把伺服器返回的資料發回給請求者。Access-Control-Allow-Credentials: true
5、Access-Control-Allow-Methods
用於響應預檢請求,指明實際請求所允許使用的 HTTP 方法
Access-Control-Allow-Methods: <method>[, <method>]*
6、Access-Control-Allow-Headers
用於響應預檢請求,指明實際請求中允許攜帶的 Header
Access-Control-Allow-Headers: <field-name>[, <field-name>]*