1. 程式人生 > >AJAX跨域訪問被禁止的原因

AJAX跨域訪問被禁止的原因

為什麼AJAX訪問不能跨域呢?要講清楚這個問題,首先要談談Cookie

 

1.客戶向A網站的伺服器傳送登入請求,並攜帶賬號密碼資料

2.A網站的伺服器校驗賬號密碼正確後,返回響應並給本地添加了Cookie

3.之後客戶再次向A網站發起請求會自動帶上A網站儲存在本地的cookie

4.A網站的伺服器從cookie中獲取賬號密碼資料後,返回登陸成功介面。

下圖為cookie的工作機制 

  

  假設有一個黑客叫做小黑,他從網上抓取了一堆美女圖做了一個網站,每日訪問量爆表。

  為了維護網站執行,小黑掛了一張收款碼,覺得網站不錯的可以適當資助一點,可是無奈伸手黨太多,小黑的網站入不敷出。

  於是他非常生氣的在網頁中寫了一段js程式碼,使用ajax向淘寶發起登陸請求,因為很多數人都訪問過淘寶,所以電腦中存有淘寶的cookie,不需要輸入賬號密碼直接就自動登入了,然後小黑在ajax回撥函式中解析了淘寶返回的資料,得到了很多人的隱私資訊,轉手一賣,小黑的網站終於盈利了。

  如果跨域也可以傳送AJAX請求的話,小黑就真的獲取到了使用者的隱私併成功獲利了!!!

  為了防止小黑這種黑客侵犯使用者的隱私,同源政策出現了。

  同源政策:不是同協議 同域名 同埠 的網頁無法相互訪問。

  用form表單提交到不同源的網頁是被允許的,因為 form 提交到另一個域名之後,原頁面的指令碼無法獲取新頁面中的內容,所以瀏覽器認為這是安全的。

  而 AJAX 是可以讀取響應內容的,因此瀏覽器不能允許你這樣做。如果你細心的話你會發現,其實請求已經發送出去了,你只是拿不到響應而已。

  所以瀏覽器這個策略的本質是,一個域名的 JS ,在未經允許的情況下,不得讀取另一個域名的內容。但瀏覽器並不阻止你向另一個域名傳送請求。

 

 

Cookie的簡單使用案例:記住密碼

登入請求提交到伺服器時,如果賬號密碼正確並且勾選了記住密碼,就會把賬號密碼儲存到cookie中

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
    String name = request.getParameter("name");
    String pwd = request.getParameter("pwd");
    String flag = request.getParameter("isLogin");

    if (!"admin".equals(name) && !"123".equals(pwd)) {
        response.sendRedirect("error.jsp");
    } else {
        //判斷是否勾選了記住密碼單選框,如果flag為"y"意為勾選了記住密碼單選框
        //如果勾選了記住密碼,就應該儲存cookie
        if ("y".equals(flag)) {
            //建立兩個Cookie物件
            Cookie nameCookie = new Cookie("username", name);
            //設定Cookie的有效期為3天
            nameCookie.setMaxAge(60 * 60 * 24 * 3);
            Cookie pwdCookie = new Cookie("password", pwd);
            pwdCookie.setMaxAge(60 * 60 * 24 * 3);
            response.addCookie(nameCookie);
            response.addCookie(pwdCookie);
        }
        response.sendRedirect("success.jsp");
    }
%>

訪問網站時:會取出客戶端的cookie,檢視有沒有賬號密碼相關的cookie,如果有的話,可以進行自動登入,或者把賬號密碼放到輸入框裡。

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>

<%
    String username = "";
    String password = "";
    //獲取當前站點的所有Cookie
    Cookie[] cookies = request.getCookies();
    for (int i = 0; i < cookies.length; i++) {//對cookies中的資料進行遍歷,找到使用者名稱、密碼的資料
        if ("username".equals(cookies[i].getName())) {
            username = cookies[i].getValue();
        } else if ("password".equals(cookies[i].getName())) {
            password = cookies[i].getValue();
        }
    }
%>

</head>
<body>
    <form action="login_handler.jsp" method="post">
        username:<input type="text" name="name" value="<%=username%>" /><br/>
        password:<input type="password" name="pwd" value="<%=password%>" /><br/>
        <input type="checkbox" value="y" name="isLogin">自動登入<br/> 
        <input type="submit" value="登入" />
    </form>
</body>
</html>

 

上面的案例是Cookie的簡單使用,下面談論Cookie的特性

 

Cookie的不可跨域名性

很多網站都會使用Cookie。例如,淘寶會向客戶端頒發Cookie,京東也會向客戶端頒發Cookie。那瀏覽器訪問淘寶會不會也攜帶上京東頒發的Cookie呢?或者淘寶能不能修改京東頒發的Cookie呢?

答案是否定的。Cookie具有不可跨域名性。根據Cookie規範,瀏覽器訪問淘寶只會攜帶淘寶的Cookie,而不會攜帶京東的Cookie。京東也只能操作京東的Cookie,而不能操作淘寶的Cookie。

Cookie在客戶端是由瀏覽器來管理的。瀏覽器能夠保證Google只會操作Google的Cookie而不會操作Baidu的Cookie,從而保證使用者的隱私安全。瀏覽器判斷一個網站是否能操作另一個網站Cookie的依據是域名。Google與Baidu的域名不一樣,因此Google不能操作Baidu的Cookie。

需要注意的是,雖然網站images.google.com與網站www.google.com同屬於Google,但是域名不一樣,二者同樣不能互相操作彼此的Cookie。

注意:使用者登入網站www.google.com之後會發現訪問images.google.com時登入資訊仍然有效,而普通的Cookie是做不到的。這是因為Google做了特殊處理。本章後面也會對Cookie做類似的處理。

Cookie的有效期

Cookie的maxAge決定著Cookie的有效期,單位為秒(Second)。Cookie中通過getMaxAge()方法與setMaxAge(int maxAge)方法來讀寫maxAge屬性。 如果maxAge屬性為正數,則表示該Cookie會在maxAge秒之後自動失效。瀏覽器會將maxAge為正數的Cookie持久化,即寫到對應的Cookie檔案中。無論客戶關閉了瀏覽器還是電腦,只要還在maxAge秒之前,登入網站時該Cookie仍然有效。下面程式碼中的Cookie資訊將永遠有效。

Cookie cookie = new Cookie("username","helloweenvsfei"); // 新建Cookie
cookie.setMaxAge(Integer.MAX_VALUE); // 設定生命週期為MAX_VALUE
response.addCookie(cookie); // 輸出到客戶端

如果maxAge為負數,則表示該Cookie僅在本瀏覽器視窗以及本視窗開啟的子視窗內有效,關閉視窗後該Cookie即失效。maxAge為負數的Cookie,為臨時性Cookie,不會被持久化,不會被寫到Cookie檔案中。Cookie資訊儲存在瀏覽器記憶體中,因此關閉瀏覽器該Cookie就消失了。Cookie預設的maxAge值為–1。

如果maxAge為0,則表示刪除該Cookie。Cookie機制沒有提供刪除Cookie的方法,因此通過設定該Cookie即時失效實現刪除Cookie的效果。失效的Cookie會被瀏覽器從Cookie檔案或者記憶體中刪除:

Cookie cookie = new Cookie("username","helloweenvsfei"); // 新建Cookie
cookie.setMaxAge(0); // 設定生命週期為0,不能為負數
response.addCookie(cookie); // 必須執行這一句

response物件提供的Cookie操作方法只有一個新增操作add(Cookie cookie)。要想修改Cookie只能使用一個同名的Cookie來覆蓋原來的Cookie,達到修改的目的。刪除時只需要把maxAge修改為0即可。

注意:從客戶端讀取Cookie時,包括maxAge在內的其他屬性都是不可讀的,也不會被提交。瀏覽器提交Cookie時只會提交name與value屬性。maxAge屬性只被瀏覽器用來判斷Cookie是否過期。

Cookie的域名

Cookie是不可跨域名的。域名www.google.com頒發的Cookie不會被提交到域名www.baidu.com去。這是由Cookie的隱私安全機制決定的。隱私安全機制能夠禁止網站非法獲取其他網站的Cookie。

正常情況下,同一個一級域名下的兩個二級域名如www.helloweenvsfei.com和images.helloweenvsfei.com也不能互動使用Cookie,因為二者的域名並不嚴格相同。如果想所有helloweenvsfei.com名下的二級域名都可以使用該Cookie,需要設定Cookie的domain引數,例如:

Cookie cookie = new Cookie("time","20080808"); // 新建Cookie
cookie.setDomain(".helloweenvsfei.com"); // 設定域名
cookie.setPath("/"); // 設定路徑
cookie.setMaxAge(Integer.MAX_VALUE); // 設定有效期
response.addCookie(cookie); // 輸出到客戶端

讀者可以修改本機C:\WINDOWS\system32\drivers\etc下的hosts檔案來配置多個臨時域名,然後使用setCookie.jsp程式來設定跨域名Cookie驗證domain屬性。

注意:domain引數必須以點(".")開始。另外,name相同但domain不同的兩個Cookie是兩個不同的Cookie。如果想要兩個域名完全不同的網站共有Cookie,可以生成兩個Cookie,domain屬性分別為兩個域名,輸出到客戶端。

Cookie的路徑

domain屬性決定執行訪問Cookie的域名,而path屬性決定允許訪問Cookie的路徑(ContextPath)。例如,如果只允許/sessionWeb/下的程式使用Cookie,可以這麼寫:

Cookie cookie = new Cookie("time","20080808"); // 新建Cookie
cookie.setPath("/session/"); // 設定路徑
response.addCookie(cookie); // 輸出到客戶端

設定為“/”時允許所有路徑使用Cookie。path屬性需要使用符號“/”結尾。name相同但domain不同的兩個Cookie也是兩個不同的Cookie。

注意:頁面只能獲取它屬於的Path的Cookie。例如/session/test/a.jsp不能獲取到路徑為/session/abc/的Cookie。使用時一定要注意。

  1. domain表示的是cookie所在的域,預設為請求的地址,如網址為www.test.com/test/test.aspx,那麼domain預設為www.test.com。而跨域訪問,如域A為t1.test.com,域B為t2.test.com,那麼在域A生產一個令域A和域B都能訪問的cookie就要將該cookie的domain設定為.test.com;如果要在域A生產一個令域A不能訪問而域B能訪問的cookie就要將該cookie的domain設定為t2.test.com。

  2. path表示cookie所在的目錄,預設為/,就是根目錄。在同一個伺服器上有目錄如下:/test/,/test/cd/,/test/dd/,現設一個cookie1的path為/test/,cookie2的path為/test/cd/,那麼test下的所有頁面都可以訪問到cookie1,而/test/和/test/dd/的子頁面不能訪問cookie2。這是因為cookie能讓其path路徑下的頁面訪問。

  3. 瀏覽器會將domain和path都相同的cookie儲存在一個檔案裡,cookie間用*隔開。

JavaScript操作Cookie

Cookie是儲存在瀏覽器端的,因此瀏覽器具有操作Cookie的先決條件。瀏覽器可以使用指令碼程式如JavaScript或者VBScript等操作Cookie。這裡以JavaScript為例介紹常用的Cookie操作。例如下面的程式碼會輸出本頁面所有的Cookie。

<script>document.write(document.cookie);</script>

由於JavaScript能夠任意地讀寫Cookie,有些好事者便想使用JavaScript程式去窺探使用者在其他網站的Cookie。不過這是徒勞的,W3C組織早就意識到JavaScript對Cookie的讀寫所帶來的安全隱患並加以防備了,W3C標準的瀏覽器會阻止JavaScript讀寫任何不屬於自己網站的Cookie。換句話說,A網站的JavaScript程式讀寫B網站的Cookie不會有任何結果。

 

 

 

 

 

 

 

假設你寫了一個網站A,你在網站裡寫了一段ajax程式碼,去訪問京東