Browser Security-同源策略、偽URL的域

wyzsk發表於2020-08-19
作者: 瞌睡龍 · 2013/06/19 19:09

同源策略


同源策略的文件模型

同源策略(Same Origin policy,SOP),也稱為單源策略(Single Origin policy),它是一種用於Web瀏覽器程式語言(如JavaScript和Ajax)的安全措施,以保護資訊的保密性和完整性。

同源策略能阻止網站指令碼訪問其他站點使用的指令碼,同時也阻止它與其他站點指令碼互動。

原始資源 要訪問的資源 非IE瀏覽器 IE瀏覽器
http://example.com/a/ http://example.com/b/ 可以訪問 可以訪問
http://example.com/ http://www.example.com/ 主機不匹配 主機不匹配
http://example.com/a/ https://example.com/a/ 協議不匹配 協議不匹配
http://example.com:81/ http://example.com/ 埠不匹配 可以訪問

同源策略一開始是為了管理DOM之間的訪問,後來逐漸擴充套件到Javascript物件,但並非是全部。

例如非同源的指令碼之間可以呼叫location.assign()和location.replace()。

同源策略在提高了安全性,但同時也降低了靈活性。

例如很難將login.example.com與payments.example.com兩個域之間的資料可以方便的傳送。

介紹兩種解決方式:document.domain和postMessage()。

javascript允許子域之間使用頂級域名。

例如login.example.com和payments.example.com都可以進行如下設定:

document.domain="example.com"

設定這個屬性之後,子域之間可以方便的通訊,需注意的是協議和埠號必須相同。

原始資源 訪問的資源 結果
URL document.domain URL document.domain
http://www.example.com/ example.com http://payments.example.com/ example.com 可以訪問
http://www.example.com/ example.com https://payments.example.com/ example.com 協議不匹配
http://payments.example.com example.com http://example.com/ (不設定) 拒絕訪問
http://www.example.com/ (不設定) http://www.example.com example.com 拒絕訪問

postMessage()是HTML5的一個API介面,由於比較新,所以在IE6和IE7中不支援。 1 向另外一個iframe傳送訊息:

var message = 'Hello' + (new Date().getTime());
    window.parent.frames[1].postMessage(message, '*');

iframe1.html需要向iframe2.html傳送訊息,也就是第二個iframe,所以是window.parent.frames[1]。

如果是向父頁面傳送訊息就是window.parent。

postMessage這個函式接收二個引數,缺一不可,第一個引數即你要傳送的資料。

第二個引數是非常重要,主要是出於安全的考慮,一般填寫允許通訊的域名。

這裡為了簡化,所以使用’*',即不對訪問的域進行判斷。

2 另外一個iframe監聽訊息事件:

iframe2.html中寫個監聽message事件,當有訊息傳到iframe2.html時就會觸發這個事件。
var onmessage = function(e) {
    var data = e.data,p = document.createElement('p');
    p.innerHTML = data;
    document.getElementById('display').appendChild(p);
};
 //監聽postMessage訊息事件
if (typeof window.addEventListener != 'undefined') {
    window.addEventListener('message', onmessage, false);
 } else if (typeof window.attachEvent != 'undefined') {
    window.attachEvent('onmessage', onmessage);
}

如果你有加域名限,比如下面的程式碼:

window.parent.frames[1].postMessage(message, 'http://www.test.com');

就要在onmessage中追加個判斷:

if(event.origin !== 'http://www.test.com') return;

XMLHttpRequest的同源策略

一個簡單的同步XMLHttpRequest請求:

var x = new XMLHttpRequest();
x.open("POST", "/some_script.cgi", false);
x.setRequestHeader("X-Random-Header", "Hi mom!");
x.send("...POST payload here...");
alert(x.responseText);

XMLHttpRequest請求嚴格遵守同源策略,非同源不可以請求。

這個API也做過很多測試與改進,下面列出之前的測試方法:

var x = new XMLHttpRequest();
x.open("POST", "http://www.example.com/", false);
// 定義傳送內容長度為7
x.setRequestHeader("Content-Length", "7");
// 構造的http請求。
x.send(
"Gotcha!\n" +
"GET /evil_response.html HTTP/1.1\n" +
"Host: www.bunnyoutlet.com\n\n"
);

現在的瀏覽器都不存在上面的隱患,包括基本都禁用了TRACE方法,防止httponly的cookie洩漏問題等。

Web Storage的同源策略

Web Storage是由Mozilla的工程師在Firefox1.5中加入的,並且加入了HTML5中,現在的瀏覽器都支援,除了IE6與IE7。

JavaScript可以透過localStorage與sessionStorage對Web Storage進行建立,檢索和刪除:

localStorage.setItem("message", "Hi mom!"); 
alert(localStorage.getItem("message")); 
localstorage.removeItem("message");

localStorage物件可以長時間儲存,並且遵守同源策略。

但是在IE8中localStorage會把域名相同但是協議分別為HTTP和HTTPS的內容放在一起,IE9中已修改。

在Firefox中,localStorage沒有問題,但是sessionStorage也是會把域名相同的HTTP與HTTPS放在一起。

Cookie的安全策略

設定Cookie總結

在foo.example.com設定cookie,domain設定為:

最終cookie的範圍

非IE瀏覽器

IE瀏覽器

設定為空

foo.example.com(一個域)

*.foo.example.com

bar.foo.example.com

cookie設定失敗,設定的域是當前域的一個子域

foo.example.com

*.foo.example.com

baz.example.com

cookie設定失敗,域名不匹配

example.com

*.example.com

ample.com

cookie設定失敗,域名不匹配

.com

設定失敗,域名太廣,存在安全風險。

Cookie中的path引數可以設定指定目錄的cookie。

例如設定domain為example.com,path為/some/path/ 在訪問下面url的時候會帶上設定的cookie:

http://foo.example.com/some/path/subdirectory/hello_world.txt

存在一定的安全風險,因為path的設定沒有考慮到同源策略。

httponly屬性可以防止透過document.cookie的API訪問設定的cookie。

secure屬性設定後只有在透過https傳輸時才會帶上設定的cookie,可以防止中間人攻擊。

Adobe Flash

AllowScriptAccess引數:用來控制flash透過ExternallInterface.call()函式呼叫javascript的時的限制。

有三個值:always,never和sameorigin,最後一個值只允許同域的JavaScript操作(08年之前預設為always,現在預設為sameorigin)。

AllowNetworking引數:用來控制flash與外部的網路通訊。

可選的值為:all(允許使用所有的網路通訊,預設值),internal(flash不能與瀏覽器通訊如navigateToURL,但是可以呼叫其他的API),none(禁止任何的網路通訊)

本地檔案

由於本地檔案都是透過file:協議進行訪問的,由於不存在host,所以無法遵循同源策略。

所以本地儲存的一個HTML檔案,在瀏覽器中透過file:協議訪問後,可以透過XMLHttpRequest或DOM對本地其他檔案進行操作。

與此同時,也可以對網際網路的其他資源做同樣的操作。各瀏覽器廠商意識到這個問題,並努力做了修改:

測試程式碼:

1.html(1.txt隨機寫一些字串即可)

<script>
function createXHR(){
  return window.XMLHttpRequest?
  new XMLHttpRequest():
  new ActiveXObject("Microsoft.XMLHTTP");
}
function getlocal(url){
  xmlHttp = createXHR();
  xmlHttp.open("GET",url,false);
  xmlHttp.send();
  result = xmlHttp.responseText;
  return result;
}
function main(){
  url = "file://路徑/1.txt";
  alert(url);
  result = getlocal(url);
  alert(result);
}
main();
</script>

結論:

1 Chrome瀏覽器(使用WebKit核心的瀏覽器)
完全禁止跨文件的XMLHttpRequest和DOM操作,並禁止了document.cookie和<meta http-equiv="Set-Cookie" ...>的操作。
2 Firefox
允許訪問同目錄與子目錄裡的檔案。也可透過document.cookie與<meta http- equiv="Set-Cookie" ...>設定cookie,file:協議下cookie共享,storage也是。
3 IE7及以上
允許本地檔案之間的訪問,但是在執行JavaScript之前會有一個提示,使用者點選透過之後可以執行,cookie域Firefox類似,但是file:協議下不支援storage。
4 IE6
允許本地檔案的訪問,同時也允許對http協議的訪問,cookie也是一樣。

偽URL的域


一些web應用用到了偽URL例如about:,javascript:,和data:來建立HTML文件。

這種方法是為了不需要再與伺服器通訊,可以節約時間更快的響應,但是也帶進了很多安全隱患。

about:blank

about協議在現在的瀏覽器中有很多用途,但是其中大部分不是為了獲取正常的頁面。

about:blank這個URL可以用來被建立DOM物件,例如:

<iframe src="about:blank" name="test"></iframe>
<script> 
frames["test"].document.body.innerHTML = "<h1>Hi!</h1>";
</script>

在瀏覽器中,建立一個about:blank頁面,它繼承的域為建立它的頁面的域。

例如,點選一個連結,提交一個表單,建立一個新視窗,但是當使用者手動輸入about:或者書籤中開啟的話,他的域是一個特殊的域,任何其他的頁面都不可以訪問。

data:協議

data:協議是設計用來放置小資料的,例如圖示之類的,可以減少http請求數量,例如:

<img src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEBLAEsAAD...">

用以下程式碼研究域的問題:

<iframe src="data:text/html;charset=utf-8,<script>alert(document.domain)</script>" >  

在Chrome與Safari中,所有的data:都會賦予一個單獨的,不可獲取的域,而不是從父域中繼承的。

Firefox與Opera中,域是繼承於當前頁面。

IE8之前的版本不支援data:協議。

javascript:和vbscript:

javascript:協議允許後面執行javascript程式碼,並且繼承了呼叫的當前域。

有些情況會對後面的內容處理兩次,如果程式碼正確的話,會把後面的程式碼當成html解析,覆蓋掉原來的html程式碼:

<iframe src='javascript:"<b>2 + 2 = " + (2+2) + "</b>"'> 
</iframe>
本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!

相關文章