同源策略:
所謂同源策略,它是瀏覽器的一種最核心最基本的安全策略。它對來至不同源的文檔或這腳本對當前文檔的讀寫操作做了限制。
同協議、ip、端口的腳本纔會執行。
只要協議、域名、端口有任何一個不同,都被當作是不同的域.
js跨域是指通過js在不同的域之間進行數據傳輸或通信.
-
-
- 爲什麼限制跨域
-
爲什麼要有這個策略,想必你已經知道,那就是因爲保證用戶的信息安全。
假如沒有同源策略
- 假設現在有a.com和b.com兩個域,如果沒有這一安全策略,那麼當用戶在訪問a.com時,a.com的一段腳本就可以在不加載b.com的頁面而隨意修改或者獲取b.com上面的內容。這樣將會導致b.com頁面的頁面發生混亂,甚至信息被獲取,包括服務器端發來的session。這樣的話,我們的web世界將是一片混亂。也是因爲瀏覽器的同源策略,保證來至不同源的對象不會互相干擾,保證了我們訪問頁面最基本的安全。
- 比如,cookie一般用於狀態控制,常用於存儲登錄的信息,如果允許跨域訪問,那麼別的網站只需要一段腳本就可以獲取你的cookie,從而冒充你的身份去登錄網站,造成非常大的安全問題,因此,現代瀏覽器均推行同源策略。
-
- 什麼會限制跨域
-
限制跨域
- cookie
- localStorage
- ajax請求
src可以跨域
在這裏需要注意的是,文檔中的所有帶“src”屬性的標籤都可以跨域加載資源,而不受同源策略的限制。
如<script>、<img>、<iframe>、<link>等。如果你在頁面定義了這些標籤,在頁面加載時都對不同源的資源發起了一次GET請求。但是通過src加載的資源,瀏覽器限制了腳本對其返回的內容無法讀寫。特別是在ajax請求的時候,特別要注意XMLHttpRequest的時候是無法跨域訪問的。
-
-
- 怎麼解決跨域
- 通過修改document.domain來跨子域
- 怎麼解決跨域
-
同源策略認爲域和子域屬於不同的域,如:
child1.a.com 與 a.com,
child1.a.com 與 child2.a.com,
xxx.child1.a.com 與 child1.a.com
兩兩不同源,可以通過設置 document.damain='a.com',瀏覽器就會認爲它們都是同一個源。想要實現以上任意兩個頁面之間的通信,兩個頁面必須都設置documen.damain='a.com'。
此方式的特點:
1. 只能在父域名與子域名之間使用,且將 xxx.child1.a.com域名設置爲a.com後,不能再設置成child1.a.com。
2. 存在安全性問題,當一個站點被攻擊後,另一個站點會引起安全漏洞。
3. 這種方法只適用於 Cookie 和 iframe 窗口。
-
-
-
- 使用window.name來進行跨域
-
-
window對象有個name屬性,該屬性有個特徵:即在一個窗口(window)的生命週期內,窗口載入的所有的頁面都是共享一個window.name的,每個頁面對window.name都有讀寫的權限,window.name是持久存在一個窗口載入過的所有頁面中的,並不會因新頁面的載入而進行重置。
// 打開必應 https://www.bing.com/
// 保留控制檯log(勾上Preserve log
> window.name
""
> window.name='text';
"text"
> location.href='http://www.google.com';
"http://www.google.com"
Navigated to https://www.google.com/
> window.name
"text
我們知道,使用iframe的src屬性,可以加載不同域中的網頁,
我們也可以使用$('iframe').contentWindow來拿到iframe中頁面的window對象,
只是這個window對象中可以訪問的屬性是很少的。
window.name這個屬性不是一個簡單的全局屬性 ---
只要在一個window下,無論url怎麼變化,只要設置好了window.name,那麼後續就一直都不會改變,同理,在iframe中,即使url在變化,iframe中的window.name也是一個固定的值,利用這個,我們就可以實現跨域了。
下面是localhost:8088/test2.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>test2</title>
</head>
<body>
<h2>test2頁面</h2>
<script>
var person = {
name: 'wayne zhu',
age: 22,
school: 'xjtu'
}
window.name = JSON.stringify(person)
</script>
</body>
</html>
即我們希望吧test2.html中的數據傳遞出去,到localhost:8081/test1.html中去。
下面是localhost:8081/test1.html
這裏的意圖很明確,就是使用iframe將test2.html加載過來,因爲只是爲了實現跨域,所以將之隱藏,但是,這時已經完成了最重要的一步,就是將iframe中window.name已經成功設置,但是現在還獲取不了,因爲是跨域的,所以,我們可以把src設置爲當前域的proxy.html。
另外,這裏之所以要設置flag,是因爲每當改變location的時候,就會重新來一次onload,所以我們希望獲取到數據之後,就直接close(),故採用此種方法。
這個proxy.html內容如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>proxy</title>
</head>
<body>
<p>這是proxy頁面</p>
</body>
</html>
是的,什麼都沒有,當然,我們也可以把src就替換成test1.html,但是這樣的壞處很明顯,就是需要把test1.html中的數據加載一遍,這不是我們所希望的。
-
-
-
- 使用HTML5新提供的postMessage api
-
-
/* 子窗口 */
window.onmessage = function(e) {
if (e.origin !== 'http://bbb.com') return;
var payload = JSON.parse(e.data);
switch (payload.method) {
case 'set':
localStorage.setItem(payload.key, JSON.stringify(payload.data));
break;
case 'get':
var parent = window.parent;
var data = localStorage.getItem(payload.key);
parent.postMessage(data, 'http://aaa.com');
break;
case 'remove':
localStorage.removeItem(payload.key);
break;
}
};
/* 父窗口 */
var win = document.getElementsByTagName('iframe')[0].contentWindow;
var obj = { name: 'Jack' };
// 存入對象
win.postMessage(JSON.stringify({key: 'storage', method: 'set', data: obj}), 'http://bbb.com');
// 讀取對象
win.postMessage(JSON.stringify({key: 'storage', method: "get"}), "*");
window.onmessage = function(e) {
if (e.origin != 'http://aaa.com') return;
// "Jack"
console.log(JSON.parse(e.data).name);
};
-
-
-
- 1. 通過jsonp跨域
-
-
jsonp在頁面上引入不同域上的js腳本文件實現請求不同域上的數據
(1) 通過script標籤引入一個js文件
(2) js文件載入成功後會執行我們在url參數中指定的函數,並且會把我們需要的json數據作爲參數傳入
注:需要服務器端的頁面進行相應的配合。
JSONP的原理:(舉例:a.com/jsonp.html想得到b.com/main.js中的數據)在a.com的jsonp.html裏創建一個回調函數xxx,動態添加<script>元素,向服務器發送請求,請求地址後面加上查詢字符串,通過callback參數指定回調函數的名字。請求地址爲http://b.com/main.js?callback=xxx。在main.js中調用這個回調函數xxx,並且以JSON數據形式作爲參數傳遞,完成回調。
function addScriptTag(src) {
var script = document.createElement('script');
script.setAttribute("type","text/javascript");
script.src = src;
document.body.appendChild(script);
}
window.onload = function () {
addScriptTag('http://example.com/ip?callback=foo');
}
//window.onload是爲了讓頁面加載完成後再執行
function foo(data) {
console.log(data.name+"歡迎您");
};
//b.com/main.js中的代碼
foo({name:"hl"})
這樣便實現了跨域的參數傳遞。
採用jsonp跨域也存在問題:
1. 使用這種方法,只要是個網站都可以拿到b.com裏的數據,存在安全性問題。需要網站雙方商議基礎token的身份驗證,這裏不詳述。
2. 只能是GET,不能POST。
3. 可能被注入惡意代碼,篡改頁面內容,可以採用字符串過濾來規避此問題。
客戶端頁面完整代碼
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"> <title>JSONP 實例</title>
</head>
<body>
<div id="divCustomers"></div>
<script type="text/javascript">
function callbackFunction(result, methodName) {
var html = '<ul>';
for(var i = 0; i < result.length; i++) {
html += '<li>' + result[i] + '</li>';
}
html += '</ul>';
document.getElementById('divCustomers').innerHTML = html; }
</script>
<script type="text/javascript" src="http://www.runoob.com/try/ajax/jsonp.php?jsoncallback=callbackFunction">
</script>
</body>
</html>
-
-
-
- WebSocket
-
-
WebSocket是HTML5開始提供的一種在單個 TCP 連接上進行全雙工通訊的協議。
在WebSocket API中,瀏覽器和服務器只需要做一個握手的動作,然後,瀏覽器和服務器之間就形成了一條快速通道。兩者之間就直接可以數據互相傳送。
瀏覽器通過 JavaScript 向服務器發出建立 WebSocket 連接的請求,連接建立以後,客戶端和服務器端就可以通過 TCP 連接直接交換數據。
-
-
-
- CORS
-
-
CORS全稱cross-origin resource sharing,意爲跨站點資源共享,是w3c官方推薦的一種跨域方案,目前所有瀏覽器對其兼容性都表現良好,而且支持所有的請求方式,可以預見是未來最爲廣泛使用的跨域方案。
在支持CORS方案的瀏覽器中發送AJAX請求,請求地址爲目標域的絕對路徑時,請求頭中會帶有一個字段:withCredentials: true,這個字段會讓瀏覽器發送身份信息到服務端,如SSL、cookie等。與此同時,在服務端中設置響應頭中的Access-Control-Allow-Origin: *,則可以實現一個跨域請求。
注意:在實際使用中,最好對Access-Control-Allow-Origin進行指定域名的設置,如:Access-Control-Allow-Origin: www.test.com。如果使用Access-Control-Allow-Origin: *,則會允許所有來源進行跨域訪問,這會帶來比較大的安全問題。
-
-
-
- 服務器代理
-
-
Nginx proxy_pass
# 80 cat
upstream pig-client {
server 127.0.0.1:80 fail_timeout=0;
}
# app
upstream pig-control {
server 127.0.0.1:8080 fail_timeout=0;
}
#page 新陽藍光項目
upstream pig-xinyang {
server 127.0.0.1:4200 fail_timeout=0;
}
server {
listen 80;
server_name hardboy.cn;
index index.html index.htm;
location / {
proxy_pass http://pig-client;
try_files $uri $uri/ /index.html =404;
}
}
server {
listen 80;
server_name notapig.cn;
index index.html index.htm;
location / {
proxy_pass http://pig-xinyang;
try_files $uri $uri/ /index.html =404;
}
}