毁人不倦-令人困惑的浏览器安全策略:同源策略
同源策略(The same-origin policy)
这是浏览器的一个基本却又非常重要的安全策略,浏览器会限制对异源(异域)
(我们常称之为别人家的站点)的资源操作。打个比方,你不会让老王来你家,也不允许他在你家墙上打个洞,装个监控啥的。通过这个比喻你就知道同源策略
的重要性了。
同源策略
主要针对脚本(script)
的行为进行限制,而<script>
,<link>
,<img>
,<iframe>
,<object>
等带有src
属性的dom元素
一般不受影响,这也很好理解,你可以禁止老王进你家,但是无法限制他在自己家装个雷达对你家进行监控。因此,在没有得到授权的情况下,用javascript
脚本操作异域
的资源,那是不允许的。科学的说法应该是:浏览器允许发起请求,但如果响应中没有包含对方的许可的话,浏览器就会屏蔽响应结果,不给你用。经常会抛出这样的异常: XMLHttpRequest cannot load http://www.othersite.com/. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://www.mysite.com' is therefore not allowed access.
源(Origin)
唠叨了半天异源(异域)
,科学的解释一下什么是源(Origin)
。
公式:Origin = [protocol]://[domain]:[port]
Origin
是你的页面所在的位置。例如我有个站点www.mysite.com
,那么它的源
就是http://www.mysite.com:80
,其中[protocol]
的缺省值是http
,[port]
的缺省值是80
。
不管我的站点在哪个页面www.mysite.com/p/1.html
,只要[protocol]
,[domain]
,[port]
三者相同则视为同源
,或者叫同域
,通常称之为同域
,因为我们通常都是叫别人的小名二狗子
,而不会称呼其大名犬次郎
。
更多示例:
URL | Origin |
---|---|
http://www.mysite.com/p/1.html
|
http://www.mysite.com
|
https://wwww.mysite.com/p/1.html
|
https://www.mysite.com
|
http://app.mysite.com/p/1.thml
|
http://app.mysite.com
|
http://www.mysite.net/p/1.html
|
http://www.mysite.net
|
http://www.mysite.com:9000/p/1.html
|
http:www.mysite.com:9000
|
http://www.mysite.com/news/fresh.html
|
http://www.mysite.com
|
解决访问跨域资源的问题
虽然是安全了,但是如果想从我的www.mysite.com
去我的分站son.mysite.com
获取点东西也会被同源策略
禁止,这就不是我们想要的了,那怎么办呢?可以利用<script>
等不受同源策略
限制的dom元素
绕过去,这种方式称之为jsonp
,这是很多年前就提出来的方法,很巧妙不过很繁琐,渐渐地不怎么再使用了,有兴趣的自行google
。
还有现代化的解决方案:CORS(Cross-Origin Resource Sharing)
。还记得同源策略
的规定吗?通过屏蔽响应结果的方式保证信息安全,也就是说浏览器并没有阻止发起跨域请求。浏览器如果在跨域请求的响应(Http Response Headers
)中发现了对方的许可就会认为是安全的。这套标准称之为CORS。
这套标准规定一系列的Http Headers
,让服务器申明哪些资源是可以被谁访问,浏览器通过解析响应头部就能知道是否得到了许可。
举两个简单的?栗子说明这一系列的Http Headers
:
- 在
www.mysite.com
中有如下脚本,要去访问www.othersite.com
的资源。
<script>
var request = new XMLHttpRequest();
var url = 'www.othersite.com/post/001/';function callOtherDomain() {if(request) { request.open('GET', url, true);request.onreadystatechange = handler;request.send(); }
}
</script>
通过浏览器的控制台,查看到该请求,请求和响应报文的重要内容如下:
请求报文
GET /post/001 HTTP/1.1
Host: www.othersite.com
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Referer: www.mysite.com
Origin: http://www.mysite.com
响应报文
HTTP/1.1 200 OK
Date: Sat, 04 Mar 2017 14:23:53 GMT
Access-Control-Allow-Origin: *
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
这是一个简单的Get
请求,在请求报文中有一个值得注意的Origin
,这个属性就表示了当前所处的源
,Origin
是由浏览器自动控制的,不允许用户干预。如果同源策略
判定请求是跨域请求,那么就会自动把Origin
加入请求头部中。
在响应报文中,注意Access-Control-Allow-Origin
属性,如果对方允许你跨域访问,那么它会在响应中加入你的请求头部中的Origin
,此处的响应报文中的*
表示允许任何请求的跨域访问。
https://www.mysite.com
要去修改https://posts.mysite.com
中的一篇文章。
var request = new XMLHttpRequest();
var url = 'posts.mysite.com/?pid=1024';
var body = 'new post';function callOtherDomain(){if(request){request.open('PUT', url, true);request.setRequestHeader('userid', 'keke');request.onreadystatechange = handler;request.send(body); }
}
这次是发送了PUT
类型的请求,要去修改pid=1024
的文章,同时还携带了我的身份信息userid=keke
在请求头部中。继续在浏览器的控制台中观察请求信息,发现有两次请求,第一个如下:
OPTIONS /?pid=1024
Host: https://posts.mysite.com
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Origin: https://www.mysite.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: useridHTTP/1.1 200 OK
Date: Sat, 04 Mar 2017 14:35:39 GMT
Access-Control-Allow-Origin: https://www.mysite.com
Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT
Access-Control-Allow-Headers: userid
Access-Control-Max-Age: 1728000
Vary: Accept-Encoding, Origin
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain
这是因为这次发送的不是简单请求,CORS规范要求先发个预检请求(Preflight)
,一般会采用OPTIONS
类型,该请求不包含请求体,会携带一些用于探测的信息,除了Origin
,还有
* `Access-Control-Request-Method`
* `Access-Control-Request-Headers`
前者用来携带真正的请求的类型,后者携带真实请求自定义的头。
在响应报文中还有Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT
表示对方许可的请求类型。
对方会根据预检请求
中的信息判断是否可以接受真正的请求,如果预检请求
通过了,浏览器才会发起真正的请求。
PUT /?pid=1024/ HTTP/1.1
Host: https://posts.mysite.com
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
userid: keke
Content-Type: text/xml; charset=UTF-8
Referer: https://www.mysite.com
Content-Length: 8
Origin: https://www.mysite.com
Pragma: no-cache
Cache-Control: no-cache
……HTTP/1.1 200 OK
Date: Sat, 04 Mar 2017 14:35:39 GMT
Access-Control-Allow-Origin: https://www.mysite.com
Vary: Accept-Encoding, Origin
Content-Encoding: gzip
Content-Length: 235
Keep-Alive: timeout=2, max=99
Connection: Keep-Alive
……
响应报文报文头部中带有Access-Control-Allow-Origin: https://www.mysite.com
,表示对方同意
https://www.mysite.com
的请求,浏览器就不会屏蔽响应结果。
上述栗子中,提到了CORS
规定了对于不简单的请求类型,要先发一个预检请求(Preflight)
,那么简单与否的判定条件是什么呢?在如下范围内的请求都是被视为简单请求
- 请求类型的范围限制:
GET
,HEAD
,POST
- 自定义的请求头部限制范围:
Accept
,Accept-Language
,Content-Language
- 媒体类型(Content-Type)的限制范围的:
application/x-www-form-urlencoded
,multipart/form-data
,text/plain
除来上述栗子中提到的几个头部,还有哪些呢?如下明细:
HTTP请求头部
Origin
: 表示发送请求者的源(域),浏览器控制的。Access-Control-Request-Method
: 这是预检请求(Preflight)
中表示真实请求的请求方式。Access-Control-Request-Headers
: 这是预检请求(Preflight)
中表示真实请求的自定义的头部,可以有多个(Access-Control-Request-Headers: userid, pwd, location
:表示真实请求会携带3个自定义头部(userid
,pwd
,location
))。
HTTP响应头部
Access-Control-Allow-Origin: <origin> | *
: origin参数表示对方允许访问的URI.对于一个不带有credentials的请求,可以指定为'*',表示允许来自所有域的请求。Access-Control-Expose-Headers: X-My-Custom-Header, X-Another-Custom-Header
: 设置允许的请求头部。Access-Control-Max-Age: <delta-seconds>
: 这个头告诉我们这次预检请求
的结果的有效期是多久,delta-seconds 参数表示,允许这个预检请求
的参数缓存的秒数,在此期间,不用发出另一条预检请求
。Access-Control-Allow-Credentials: true | false
: 告知客户端,当请求的credientials属性是true的时候,响应是否可以被得到.当它作为预检请求
的响应的一部分时,它用来告知实际的请求是否使用了credentials.注意,简单的GET请求不会预检,所以如果一个请求是为了得到一个带有credentials的资源,而响应里又没有Access-Control-Allow-Credentials头信息,那么说明这个响应被忽略了。Access-Control-Allow-Methods: <method>[, <method>]*
: 这个响应头信息在客户端发出预检请求
的时候会被返回,表示被允许的请求方式。Access-Control-Allow-Headers:<field-name>[, <field-name>]*
: 也是在响应预检请求
的时候使用。用来指明在实际的请求中,可以使用哪些自定义HTTP请求头。
对于Access-Control-Allow-Credentials
这个头部只会出现在请求头部中包含了凭证(HttpCookie)
信息。一般而言,对于跨站请求,浏览器是不会发送凭证
信息的。但如果将XMLHttpRequest的一个特殊标志位设置为true,浏览器就将允许该请求的发送。
var invocation = new XMLHttpRequest();
var url = 'http://www.othersite.com';function callOtherDomain(){if(invocation) {invocation.open('GET', url, true);invocation.withCredentials = true;invocation.onreadystatechange = handler;invocation.send(); }
再例如使用jQuery
发起ajax
请求时:
$.ajax({//...xhrFields: {withCredentials: true},//...
});
针对脚本(script)
的跨域操作是安全了,可是如果通过<iframe>
这种dom元素
来嵌入资源的话,同源策略
就无法保护我们了。
针对<iframe>
的安全策略
我们肯定不希望自己的页面被不法分子用<iframe src="www.mysite.com"></frame>
等方式嵌入,然后被利用。浏览器们早已考虑到这个漏洞,并提出了解决方案。类似于CORS标准,解析响应头部中的X-Frame-Options
,用这个头部信息来表达是否可以被对方嵌入。
X-Frame-Options
有三种值:
X-Frame-Options: DENY
X-Frame-Options: SAMEORIGIN
X-Frame-Options: ALLOW-FROM https://www.othersite.com/
DENY
: 无论请求者是谁,都不允许嵌入。SAMEORIGIN
: 只有同源(origin)
的页面才可以嵌入。ALLO-From https://www.othersite.com/
: 只有https://www.othersite.com/
才可以嵌入咱们的页面。
例如,www.othersite.com
要用如下代码嵌入我的页面www.mysite.com
。
...
<iframe src="www.mysite.com"></iframe>
...
我给www.mysite.com
的响应头部中加入X-Frame-Options: SAMEORIGIN
,浏览器会屏蔽响应结果,并报错Refused to display 'http://www.mysite.com/' in a frame because it set 'X-Frame-Options' to 'SAMEORIGIN'.
这些都是基本的网络安全规范,但是其重要性却不可忽略。面对红果果的互联网,时刻不能放松。
转载于:https://www.cnblogs.com/kexxxfeng/p/6505380.html
毁人不倦-令人困惑的浏览器安全策略:同源策略相关推荐
- 【每天学习一点新知识】浏览器的同源策略
目录 同源的定义 同源策略的限制 规避同源策略 document.domain属性 跨域资源共享(CORS) 跨文档通信 JSONP WebSocket Nginx反向代理 浏览器默认 ...
- 美多商城后台管理之登录、浏览器的同源策略
登录 后台管理中我们首先需要完成登录功能,我们可以通过改写美多表单登录来完成相应的功能. 在后台登录中,由于我们前端服务和后端服务的域名不一样,所以我们首先解决跨域问题. 登后的状态保持我们采用jwt ...
- 浏览器的同源策略与跨域问题的解决方案
浏览器的同源策略与跨域问题的解决方案 参考文章: (1)浏览器的同源策略与跨域问题的解决方案 (2)https://www.cnblogs.com/yanggb/p/10735763.html 备忘一 ...
- 什么是浏览器的同源策略?
有时在开发中我们会遇到跨域的问题,众所周知,跨域是由浏览器的同源策略引起的,那么什么是浏览器的同源策略呢? 同源策略,是浏览器对javascript施加的安全限制.所谓同源是指,域名,协议,端口均相同 ...
- 浏览器的同源策略是什么,没有同源策略会怎么样?
同源策略 同源策略由Netscape提出的一个著名的安全策略. 现在所有可以支持JavaScript的浏览器都会使用这一策略. 同源 同源即 同协议,端口,域名 同源策略的限制 不能获取不同源的coo ...
- 浏览器的同源策略与跨域
本文所有案例在本地址都可找到:https://github.com/dancingZhou/sameOrigin/tree/dev 什么是同源策略 两个页面地址中的协议.域名和端口号一致,则表示同源. ...
- 浏览器的同源策略及跨域解决方案
同源策略 一个源的定义 如果两个页面的协议,端口(如果有指定)和域名都相同,则两个页面具有相同的源. 举个例子: 下表给出了相对http://a.xyz.com/dir/page.html同源检测的示 ...
- 浏览器的同源策略和跨域请求_学习版
目录 同源策略 : 跨域请求 : 跨域请求的常见解决方案 : 1. jsonp 2. cors(跨域资源共享) 3. proxy(代理) 同源策略 : 什么是同源策略 ? + 同源策略是 浏览器 ...
- 同源策略——浏览器安全卫士
对于软件开发人员来说,理解同源策略.能够非常好地攻克了一个痛点. 不同域名下的资源读写 ! 古代的楚河汉界明白地规定了两方的活动界限.假设没有这些界限,天下必将大乱.相同,在我们的浏览器,也有着一些界 ...
- gorilla websocket无法跨域_聊聊浏览器同源策略与跨域方案详解
开发出高性能的 Web 应用固然重要,但安全问题也不容小觑.本文我们继续以 HTTP 为线索,展开来讲一讲浏览器安全相关的同源策略. 浏览器的同源策略(Same Origin Policy) 源(Or ...
最新文章
- FEAST:快速准确的微生物来源追溯工具
- 2018-2019-1 20189204《Linux内核原理与分析》第三周作业
- 《研磨设计模式》chap22 装饰模式Decorator(4)AOP+总结
- 运行 YunYang1994/tensorflow-yolov3 所遇到的一些问题记录
- 【STM32】FreeRTOS移植
- leetcode654. 最大二叉树
- lz0-007 读书笔记03
- original_keras_version = f.attrs[‘keras_version‘].decode(‘utf8‘)AttributeError: ‘str‘ object has no
- 瀑布流布局的实现方式
- cocos2d-x CCArray用法 遍历和删除元素
- android simpliadapter的两种用法
- chapter10--进程和计划任务管理
- linux抓肉鸡入侵详细教程,Linux XOR.DDoS入侵排查步骤 | 聂扬帆博客
- 24种不同的ITF条形码字体版本的条形码控件Interleaved 2 of 5 Barcode Font Advantage Package...
- OneNote PC端同步时遇到0×80004005
- C#调用Outlook发送邮件
- dds:publish
- NRF24L01使用
- 2022年黑五软件促销
- SWR:最具潜力的 React Hooks 数据请求库
热门文章
- csdn博客更换皮肤
- 2021计算机一级等级考试考前冲刺模拟试题及答案(WPS Office)
- 2021年起重机司机(限桥式起重机)考试题库及起重机司机(限桥式起重机)考试试卷
- Unity TimeLine实用功能讲解
- 第四章 SQL语法分类
- 《C语言程序设计》第4版 何钦铭、颜晖主编 课后习题答案 第4章 课后习题
- The chain rule(链式法则)
- openwrt 添加usb网卡_树莓派安装OpenWrt教程
- 微端服务器添加文件,微端服务器配置
- “Google Play In-app Billing API version is less than 3”的解决方法