Http同源策略與跨域方法

一 概述

同源策略是web安全策略中的一種,也是非常重要的一種,同源策略明確規定了不同域的客戶端在沒有被明確的授權的情況下,不能讀寫對方的資源。、

二 同源分析

同源是指請求的URI(統一資源標識符),網絡協議,主機名(域名),端口號相同。但是IE瀏覽器同源不包括端口號。

例如URL:http://www.example.com:8080/test/index.html,分析一下幾種同源情況:

URL 是否同源 結果分析
http://www.example.com:8080/test/index1.html 同源 相同協議,域名,端口
http://www.example.com:8080/index.html 同源 相同協議,域名,端口
http://www.example.com/test/index.html 看情況 看瀏覽器,默認8080端口或者IE忽略端口的情況下同源
https://www.example.com:8080/test/index.html 不同源 不同協議
http://www.example.com:80/test/index.html 看情況 看瀏覽器,IE忽略端口的情況下同源
http://www.apple.com:8080/index.html 不同源 不同域名

三 同源策略的對非同源的主要限制範圍

  1. Cookie,LocalStorage和IndexDB無法讀取。
  2. DOM無法獲得。
  3. AJAX請求無法發送。

這些限制對於安全方面是很有必要的,但是實際開發過程中,會搭建服務其集羣,會把客戶端頁面放到一個單獨的服務器中,此時就會出現不同源的情況。這時候如果想要不同源的網站之間進行數據交互,我們需要使用到跨域請求。

四 跨域請求方案

      跨域請求報錯:

XMLHttpRequest cannot load http://localhost:8080/test.json. No 'Access-control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8081' is therefore not  allowed access.

      1 JSONP(JSON with Padding)

JSONP可以解決主流瀏覽器的跨域數據訪問問題,實際上js是不可以請求數據但是可以跨域請求js腳本。其原理爲服務端返回一個定義好的js函數的調用 ,並且將服務器的數據封裝成js函數參數的形式傳遞過來,最後執行函數返回後端數據,這個方法需要前後端配合,而且JSONP僅支持Get請求。

var URL_Serv:"http://localhost:8080/test.json";

/**
 *使用ajax內置方法getJSONP返回js腳本實現跨域請求
 *將請求的服務端數據URL_Serv作爲js方法的參數
 *自定義的回調函數test.getDataService。
 *test.getDataService(test.json)。
**/
$.getJSONP(this.URL_Serv, test.getDataService)

      2. CORS跨域資源共享

跨域請求的字段及其含義:

Access-Control-Allow-Origin

該字段是必須的。它的值要麼是請求時Origin字段的值,要麼是一個*,表示接受任意域名的請求。

 /*服務器端 Access-Control-Allow-Credentials = true時,參數Access-Control-Allow- Origin 的值不能爲'*',如果origin.equals('*'),表示所有域名都可以,但跨域不支持cookie。oirgin可以設置特定的域名如:www.example.com,進行跨域請求。*/

Access-Control-Allow-Credentials

該字段可選。它的值是一個布爾值,表示是否允許發送Cookie。默認情況下,Cookie不包括在CORS請求之中。設爲true,即表示服務器明確許可,Cookie可以包含在請求中,一起發給服務器。這個值也只能設爲true,如果服務器不要瀏覽器發送Cookie,刪除該字段即可。

Access-Control-Expose-Headers

該字段可選。CORS請求時,XMLHttpRequest對象的getResponseHeader()方法只能拿到6個基本字段:Cache-ControlContent-LanguageContent-TypeExpiresLast-ModifiedPragma。如果想拿到其他字段,就必須在Access-Control-Expose-Headers裏面指定。上面的例子指定,getResponseHeader('FooBar')可以返回FooBar字段的值。

Access-Control-Allow-Methods

該字段必需,它的值是逗號分隔的一個字符串,表明服務器支持的所有跨域請求的方法。注意,返回的是所有支持的方法,而不單是瀏覽器請求的那個方法。這是爲了避免多次"預檢"請求。

Access-Control-Allow-Headers

如果瀏覽器請求包括Access-Control-Request-Headers字段,則Access-Control-Allow-Headers字段是必需的。它也是一個逗號分隔的字符串,表明服務器支持的所有頭信息字段,不限於瀏覽器在"預檢"中請求的字段。

Access-Control-Max-Age

該字段可選,用來指定本次預檢請求的有效期,單位爲秒。上面結果中,有效期是20天(1728000秒),即允許緩存該條迴應1728000秒(即20天),在此期間,不用發出另一條預檢請求。

XMLHttpRequest是一個JavaScript內置對象,使得JavaScript可以進行異步的HTTP通信。新版的XMLHttpRequest對象,可以向不同域名的服務器發送Http請求。這叫做“跨域資源共享”(Cross-origin resource sharing,簡稱CORS)。

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

實現跨域的前提:1.瀏覽器支持這個功能(兼容IE10+)。2.服務器必須允許這種跨域。

服務器支持跨域過濾前端請求基於註解的代碼,添加請求響應頭:

import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class HeaderFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, 
    FilterChain filterChain) throws IOException, ServletException {

        HttpServletResquest request = (HttpServletRequest)servletRequest;
        HttpServletResponse response = (HttpServletResponse)servletResponse;

        Strign origin = request.getHeader("origin");

        //允許那些域訪問
        response.setHeader("Access-Control-Allow-Origin", origin);
        //允許那些請求方法
        response.setHeader("Access-Control-Allow-Methods", "POST,GET");
        //是否攜帶Cookie
        response.setHeader("Access-Control-Allow-Credentials", "true");
        //它表明了這個詢問結果的有效期,後面瀏覽器在有效期內也可以不必再次詢問
        response.setHeader("Access-Control-Max-Age", "3600");
        //允許那些請求頭字段
        response.setHeader("Access-Control-Allow-Headers", "Content-Type, 
        Access-Control-Allow-Headers, Authorization, X-Requested-With");

        filterChain.doFilter(servletRequest,response);
    }

    @Override
    public void destroy() {

    }
}

CORS的具體實現流程:

  1. 瀏覽器發送跨域請求(實際上瀏覽器不會直接發送請求,而是現發送一個不帶任何參數的試探請求OPTIONS,檢測服務器是否允許跨域,如果允許跨域同時設置的請求和響應頭一致,纔會發送第二次具體的請求。)
  2. 服務端接收到跨域請求之後,在響應頭中添加Access-Control-Allow-Origin Header資源權限配置,發送響應。
  3. 瀏覽器收到響應後,查看是否設置了header('Access-Control-Allow-Origin:請求源域名或者*');如果當前域已經授權了,則將結果返回給瀏覽器,否則瀏覽器忽略此次響應。

實際上,跨域行爲是瀏覽器行爲,響應回來的是瀏覽器安全機制的限制,對跨域響應內容進行了忽略。服務器與服務器之間並不存在跨域問題。

五 JSONP與CORS的比較

  • JSONP能夠支持老版本的瀏覽器,兼容性比較好,而CORS需要瀏覽器支持CORS纔行。
  • JSONP僅僅支持GET請求,發送的數據量有限,使用比較麻煩。
  • CORS使用簡單,只要服務單設置允許跨域,對於客戶端來說,同一般的GET,POST請求類似,沒有什麼區別。

跨域的安全行問題:因爲跨域是需要前端同服務端配合控制的,這樣無論是JSONP還是CORS,如果沒有服務端的允許,瀏覽器都是無法實現跨域的。

提示:微服務項目工作中,可以採用一個獨立的模塊管理不同的請求避免跨域訪問,實際上跨域訪問是存在一定的風險的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章