同源策略:
- 同源策略
在web应用的安全模型中是一个重要概念。在这个策略下,web浏览器允许第一个页面的脚本访问第二个页面里的数据,但是也只有在两个页面有相同的源时。源是由URI,主机名,端口号组合而成的。这个策略可以阻止一个页面上的恶意脚本通过页面的DOM对象获得访问另一个页面上敏感信息的权限。
对于普遍依赖于cookie维护授权用户session的现代浏览器来说,这种机制有特殊意义。客户端必须在不同站点提供的内容之间维持一个严格限制,以防丢失数据机密或者完整性。
- 源决定规则
RFC6454中有定义URI源的算法定义。对于绝对的URIs,源就是{协议,主机,端口}定义的。只有这些值完全一样才认为两个资源是同源的。
为了举例,下面的表格给出了与URL" http://www.example.com/dir/page.html "
的对比。
对比URL | 结果 | 结果 |
http://www.example.com/dir/page2.html | 同源 | 相同的协议,主机,端口 |
http://www.example.com/dir2/other.html | 同源 | 相同的协议,主机,端口 |
http://username:password@www.example.com/dir2/other.html | 同源 | 相同的协议,主机,端口 |
http://www.example.com:81/dir/other.html | 不同源 | 相同的协议,主机,端口不同 |
https://www.example.com/dir/other.html | 不同源 | 协议不同 |
http://en.example.com/dir/other.html | 不同源 | 不同主机 |
http://example.com/dir/other.html | 不同源 | 不同主机(需要精确匹配) |
http://v2.www.example.com/dir/other.html | 不同源 | 不同主机(需要精确匹配) |
http://www.example.com:80/dir/other.html | 看情况 | 端口明确,依赖浏览器实现 |
不像其他浏览器,IE在计算源的时候没有包括端口。
- 安全考量
- 规避同源策略
document.domain属性
如果两个window或者frames包含的脚本可以把domain设置成一样的值,那么就可以规避同源策略,每个window之间可以互相沟通。例如,orders.example.com
下页面的脚本和 catalog.example.com
下页面的脚本可以设置他们的 document.domain
属性为 example.com
,从而让这两个站点下面的文档看起来像在同源下,然后就可以让每个文档读取另一个文档的属性。这种方式也不是一直都有用,因为端口号是在内部保存的,有可能被保存成null。换句话说,example.com
的端口号80,在我们更新 document.domain
属性的时候可能会变成null。为null的端口可能不被认为是80,这主要依赖浏览器实现。
跨域资源共享
这种方式使用了一个新的Origin
请求头和一个新的Access-Control-Allow-Origin
响应头扩展了HTTP。允许服务端设置Access-Control-Allow-Origin
头标识哪些站点可以请求文件,或者设置Access-Control-Allow-Origin
头为"*",允许任意站点访问文件。浏览器,例如Firefox3.5,Safari4,IE10使用这个头允许跨域HTTP请求。
跨文档通信
这种方式允许一个页面的脚本发送文本信息到另一个页面的脚本中,不管脚本是否跨域。在一个window对象上调用 postMessage()
会异步的触发window上的onmessage
事件,然后触发定义好的事件处理方法。一个页面上的脚本仍然不能直接访问另外一个页面上的方法或者变量,但是他们可以安全的通过消息传递技术交流。
JSONP
JOSNP允许页面接受另一个域的JSON数据,通过在页面增加一个可以从其它域加载带有回调的JSON响应的<script>
标签。
WebSocket
现代浏览器允许脚本直连一个WebSocket地址而不管同源策略。然而,使用WebSocket URI的时候,在请求中插入Origin
头就可以标识脚本请求的源。为了确保跨站安全,WebSocket服务器必须根据允许接受请求的白名单中的源列表比较头数据。
- 不受同源策略限制的:
1、页面中的链接,重定向以及表单提交是不会受到同源策略限制的。
2、跨域资源的引入是可以的。但是js不能读写加载的内容。如嵌入到页面中的<script src="..."></script>,<img>,<link>,<iframe>等。
跨域:
- 什么是跨域:
浏览器从一个域名的网页去请求另一个域名的资源时,域名、端口、协议任一不同,都是跨域
- 域名:
主域名不同 http://www.baidu.com/index.html –> http://www.sina.com/test.js
子域名不同 http://www.666.baidu.com/index.html –> http://www.555.baidu.com/test.js
域名和域名ip http://www.baidu.com/index.html –> http://180.149.132.47/test.js
- 端口:
http://www.baidu.com:8080/index.html –> http://www.baidu.com:8081/test.js
- 协议:
http://www.baidu.com:8080/index.html –> https://www.baidu.com:8080/test.js
- 备注:
1、端口和协议的不同,只能通过后台来解决
2、localhost和127.0.0.1虽然都指向本机,但也属于跨域
- 如何解决跨域问题:
- 通过jsonp跨域
JSONP(JSON with Padding:填充式JSON),应用JSON的一种新方法,
JSON、JSONP的区别:
1、JSON返回的是一串数据、JSONP返回的是脚本代码(包含一个函数调用)
2、JSONP 只支持get请求、不支持post请求
(类似往页面添加一个script标签,通过src属性去触发对指定地址的请求,故只能是Get请求)
- 代理:
www.baidu.com/index.html需要调用www.sina.com/server.php,可以写一个接口www.baidu.com/server.php,由这个接口在后端去调用www.sina.com/server.php并拿到返回值,然后再返回给index.html
- PHP端修改header
header(‘Access-Control-Allow-Origin:*’);//允许所有来源访问
header(‘Access-Control-Allow-Method:POST,GET’);//允许访问的方式
- document.domain
跨域分为两种,一种xhr不能访问不同源的文档,另一种是不同window之间不能进行交互操作;
document.domain主要是解决第二种情况,且只能适用于主域相同子域不同的情况;
document.domain的设置是有限制的,我们只能把document.domain设置成自身或更高一级的父域,且主域必须相同。例如:a.b.example.com中某个文档的document.domain可以设成a.b.example.com、b.example.com