浏览器安全之同源策略

同源策略

同源策略(same origin policy),是一种约定,它是浏览器最核心也是最基本的安全功能。同源策略会阻止一个域的javascrip脚本和另一个域的内容进行交互,是用于隔离潜在恶意文件的关键安全机制;关于这一点我们后面会举例说明。如果缺少了同源策略浏览器的安全使用会受到很大的影响。可以说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中的,因此会被认定为同源。

代码语言:javascript
复制
<script src="https://tsuk1.com/main.js"></script>

在浏览器中,<script>、<iframe>、<img>、<link>等标签都可以跨域加载资源,因为这些资源在加载的时候,就相当于浏览器发起了一次GET请求。

不同于XMLHttpRequest的是,通过src加载的资源,浏览器限制了JavaScript的权限,使其不能读、写返回的内容

XHR可以访问同源对象的内容

代码语言:javascript
复制
<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>

点击按钮可以返回文本文件中的内容

图片[1]-浏览器安全之同源策略-能不能吃完饭再说

但是Ajax不能访问跨域资源,修改代码如下,请求跨域资源

代码语言:javascript
复制
<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>
图片[2]-浏览器安全之同源策略-能不能吃完饭再说

控制台报错,无法请求跨域资源。但是如果修改响应http头,就能使XHR完成跨域资源请求。这个跨域访问方案受信任的安全基础是“JavaScript无法控制HTTP头”。修改PHP文件的响应头,加上下列代码,即可允许跨域请求该资源。

代码语言:javascript
复制
header("Access-Control-Allow-Origin:*");
header("Access-Control-All-Methods:GET,POST");
header("Access-Control-Allow-Headers:x-requested-with,content-type");

再次点击,请求成功。

图片[3]-浏览器安全之同源策略-能不能吃完饭再说

IE8 的CSS跨域漏洞

emp1.com/test.html

代码语言:javascript
复制
<body>
    {}body{
        font-family:
        aaaaaaaaaaaaaa
        bbbbbbbbbbbbbbbb
</body>

emp2.html/test.html

代码语言:javascript
复制
<style>
        @import url("https://emp1.com/test.html");
    </style>
    <script>
        setTimeout(function(){
            var t = document.body.currentStyle.currentStyle
            alert(t);
        }, 2000);
    </script>
图片[4]-浏览器安全之同源策略-能不能吃完饭再说

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页面的内容。