同源策略
同源策略(same origin policy),是一种约定,它是浏览器最核心也是最基本的安全功能。同源策略会阻止一个域的JavaScript脚本和另一个域的内容进行交互,是用于隔离潜在恶意文件的关键安全机制;关于这一点我们后面会举例说明。如果缺少了同源策略浏览器的安全使用会受到很大的影响。可以说web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。
同源策略限制了来自不同源的“document”或者“script”,对当前“document”读取或者设置某些属性。如果没有同源策略,一段其他网站的JavaScript脚本可以随意读取甚至修改另一网站的页面。为了防止这种情况发生,浏览器提出了“Origin”-源,这个概念来自不同源的对象无法互相干扰。
对于下面JavaScript来说,以下情况认为是同源与不同源的(与https://tsuk1.cn/),当JavaScript被浏览器认为来着不同源时,请求就会被拦截
URL | 是否同源 | 原因 |
https://tsuk1.cn/topics/123.html | 是 | |
https://tsuk1.cn/fourms/123.html | 是 | |
http://tsuk1.cn/topics/123.html | 否 | 协议不同 |
https://tsuk1.cn:80/topics/123.html | 否 | 端口不同 |
https://tsuk1.com/topics/123.html | 否 | 域名不同 |
但是,对于JavaScript文件来说,存放脚本的域不重要,重要的是加载脚本的域。比如,在tsuk1.cn中加载另一域上的脚本,但是这一脚本是运行在tsuk1.cn中的,因此会被认定为同源。
<script src="https://tsuk1.com/main.js"></script>
在浏览器中,<script>、<iframe>、<img>、<link>
等标签都可以跨域加载资源,因为这些资源在加载的时候,就相当于浏览器发起了一次GET请求。
不同于XMLHttpRequest
的是,通过src加载的资源,浏览器限制了JavaScript的权限,使其不能读、写返回的内容。
XHR可以访问同源对象的内容
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="res">none</div>
<button onclick="loadXMLDoc()">click me</button>
<script>
function loadXMLDoc() {
var xmlhttp;
if (window.XMLHttpRequest) {
// IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码
xmlhttp = new XMLHttpRequest();
}
else {
// IE6, IE5 浏览器执行代码
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
document.getElementById("res").innerHTML = xmlhttp.responseText;
}
}
xmlhttp.open("GET", "hello.txt", true);
xmlhttp.send();
}
</script>
</body>
</html>
点击按钮可以返回文本文件中的内容
但是Ajax不能访问跨域资源,修改代码如下,请求跨域资源
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="yiyan">none</div>
<button onclick="loadXMLDoc()">click me</button>
<script>
function loadXMLDoc() {
var xmlhttp;
if (window.XMLHttpRequest) {
// IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码
xmlhttp = new XMLHttpRequest();
}
else {
// IE6, IE5 浏览器执行代码
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
document.getElementById("yiyan").innerHTML = xmlhttp.responseText;
}
}
xmlhttp.open("GET", "https://yiyan.api.tsuk1.cn", true);
xmlhttp.send();
}
</script>
</body>
</html>
控制台报错,无法请求跨域资源。但是如果修改响应http头,就能使XHR完成跨域资源请求。这个跨域访问方案受信任的安全基础是“JavaScript无法控制HTTP头”。修改PHP文件的响应头,加上下列代码,即可允许跨域请求该资源。
header("Access-Control-Allow-Origin:*");
header("Access-Control-All-Methods:GET,POST");
header("Access-Control-Allow-Headers:x-requested-with,content-type");
再次点击,请求成功。
IE8 的CSS跨域漏洞
emp1.com/test.html
<body>
{}body{
font-family:
aaaaaaaaaaaaaa
bbbbbbbbbbbbbbbb
</body>
emp2.html/test.html
<style>
@import url("https://emp1.com/test.html");
</style>
<script>
setTimeout(function(){
var t = document.body.currentStyle.currentStyle
alert(t);
}, 2000);
</script>
在emp2.com/test.html中将https://emp1.com/test.html作为CSS文件,渲染进入当前页面的DOM,然后通过document.body.currentStyle.currentStyle
访问该内容,在IE的CSS Parse过程中,IE将fontFamily后面的内容当做了value,可以读取emp1.com/test.html页面的内容。