浏览器的同源策略
一、同源的三个条件
1、域名(二级域名与一级域名之间也算是不同源)
2、端口
3、协议
二、同源策略的意义
浏览器基于用户的隐私安全目的,防止恶意网站窃取数据(只是浏览器有这个同源策略设置,但是用命令行curl请求某个跨域地址时能得到相应结果),不允许不同域名的网站之间互相调用ajax XHR对象, 只是不允许XHR对象,对其他的图片、js 脚本、css 脚本还是可以通过标签跨域调用。
所以 css/js/img 可以跨域请求(即引用),AJAX 不能请求跨域的资源。
同源策略会限制以下三种行为:
- cookie、localStorage 和 indexDB 无法读取
- DOM无法获得
- AJAX 请求无效(可以发送,但浏览器会拒绝接受响应)。
三、跨域访问的四种方式
1、JSONP 实现跨域
JSONP(json with padding)方式, 通过 script标签请求资源,允许用户在 src 地址中传递一个 callback 参数(callback=abc)即将预先定义好的回调函数名以查询字符串的形式传递给服务端,服务端收到请求后会将要返回的数据用这个callback参数(abc)包裹住再返回,即将请求传入的参数 abc 作为函数名来包裹住要返回的 JSON 数据,比如 abc(JSON),这样客户端在收到服务端返回的abc(JSON)文件后默认用JS解析执行。通过JSONP就可以随意定制自己的函数来自动处理返回数据了。
jsonp 的原理
虽然浏览器默认禁止了跨域访问,但并不禁止在页面中 script 标签引用其他域下的 JS 文件,比如线上 jquery 库,并可以自由执行引入的 JS 文件中的 function(包括操作 cookie、Dom 等等)。
根据这一点,可以方便地通过动态创建script节点的方法来实现完全跨域的通信。
jsonp 的缺点
1、安全问题,src 引用是开放的,所以 jsonp 的资源都被所有人访问到。解决方法是用 jsonp 中的 token 参数,通过A域和B域共用同一套 cookie 来验证A的身份。
2、只能用GET方式不能用POST方式获取数据因为是基于 src 引用的,引用是 get 请求。 3、可被注入恶意代码如 ?callback=alert(1)
,这问题只能用正则过滤字符串的方法解决,过滤 callback 后的内容不能有括号之类的条件
jsonp 代码实现
1.定义数据处理函数
appendHtml(){
xxxxx
}
2、创建 script
标签,src
的地址执行后端接口,最后加个参数 callback=appendHtml
。如:
var script=document.createElement('script')
script.src="http://127.0.0.1/getNews?callback=appendHtml"
3、服务端在收到请求后,解析参数,计算返还数据,输出 appendHtml(data)
字符串。 4.前台页面收到服务端返回的 appendHtml(data)
字符串所构建的 script
标签,页面加载这个 script
标签时做为 js 执行。 此时会调用 appendHtml()
函数,将 data
做为参数。
注意:JSONP 实现的前提是后端必须有 JSONP 的 API 接口,即后端有将前端传入的参数作为函数名包裹数据返回 js 文件的逻辑。
2、CORS 跨域资源共享 Cross-Origin Resource Sharing
CORS允许浏览器向跨域服务器发出 XMLHttpRequest 请求,突破了 AJAX 只能同源使用的限制。CORS 需要浏览器和服务器同时支持,目前,所有浏览器都支持该功能,IE 浏览器不能低于 IE10。CORS原理:浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。只要服务器实现了 CORS 接口,就可以跨源通信。
header("Accept-Control-Allow-Origin","*")//允许所有源发起的请求
如果 Origin 指定的源,不在服务端许可范围内,服务器会返回一个正常的 HTTP 回应。
但这个响应头信息没有包含 Access-Control-Allow-Origin
字段。
浏览器接收后就知道出错了,从而抛出一个错误,被 XMLHttpRequest 的 onerror
回调函数捕获。
这种错误无法通过状态码识别,因为 HTTP 回应的状态码有可能是 200。
如果Origin指定的域名在许可范围内,服务器返回的响应,响应头会包含以下信息字段
Access-Control-Allow-Origin: http://api.bob.com
// 允许来自源 http://api.bob.com 的访问,如果是*则代表允许来自所有源的访问
3、HTML5 跨文档通信 API window.postMessage
HTML5 中最酷的新功能之一就是 跨文档消息传输 Cross Document Messaging。
下一代浏览器都将支持这个功能。Facebook 已经使用了这个功能,用 postMessage 支持基于 web 的实时消息传递。
举例,父窗口 aaa.com
向子窗口 bbb.com
发消息,调用 postMessage
方法如下:
var popup = window.open('http://bbb.com', 'title');
popup.postMessage('Hello World!', 'http://bbb.com');
// 第一个参数是具体的信息内容(支持任意类型),
// 第二个参数是接收消息目标窗口的源origin(协议 + 域名 + 端口)也可以设为*,表示不限制域名,向所有窗口发送。
子窗口向父窗口发送消息的写法如下:
window.opener.postMessage('Nice to see you', 'http://aaa.com');
父窗口和子窗口都可以通过message事件,监听对方的消息:
window.addEventListener('message', function(event) {
console.log(e.data);
},false);
4、降域 实现 iframe 窗口跨域访问 实现不同子域页面 cookies 共享
当两个网页一级域名相同,只是二级域名不同,浏览器允许通过设置 document.domain
来实现 iframe 窗口相互访问或设置 cookie。降域方式只适用于同一站点下不同子域名共享 cookie 或者 iframe 页面中嵌套的子域名页面之间的访问。降域不适用访问 LocalStorage 和 IndexedDB,postMessage() 方法可访问 LocalStorage。
举例来说,A网页是 http://w1.example.com/a.html ,B网页是 http://w2.example.com/b.html ,子域名不同默认情况下会被同源策略阻止访问。只要将两个页面都设置相同的 document.domain
,两个网页就可以共享 Cookie 或在 iframe 窗口下相互访问。
document.domain = 'example.com';
服务器也可以在设置 Cookie 的时候,指定 Cookie 的所属域名为一级域名以后二级域名和三级域名不用做任何设置,都可以读取这个 Cookie。比如 .example.com
。
Set-Cookie: key=value; domain=.example.com; path=/
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
上一篇: 路由器命令行操作
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论