同源策略
同源即 同协议,端口,域名
同源策略的限制
- 不能获取不同源的cookie,LocalStorage 和 indexDB。这个东西很好理解,是为了防止恶意网站获取用户其他网站的cookie数据,加入登录过淘宝,cookie信息没有清除,访问恶意网站后就可以直接获取淘宝的cookie了。
- 不能获取非同源的DOM。如果没有这一条,恶意网站可以通过iframe打开银行页面,可以获取dom就相当于可以获取整个银行页面的信息。
-
不能发送非同源的ajax请求。(准确说应该是可以向非同源的服务器发起请求,但是返回的数据会被浏览器拦截)
如果没有同源策略,若非同源下的cookie等隐私数据可以被随意获取,非同源下的DOM可以的随意操作,ajax可以任意请求的话,用户的各种隐私势必泄露。
参考自:https://blog.csdn.net/hcrw01/article/details/84289109
XSS
浏览器颁布了同源策略后,之前获取cookie等方法就不适用了,但是也不代表就安全了。XSS就可以造成系统的不安全。
XSS,站脚本攻击是指恶意攻击者往Web页面里插入恶意Script代码,当用户浏览该页之时,嵌入其中Web里面的Script代码会被执行,从而达到恶意攻击用户的目的。
XSS分类
- 反射型XSS:<非持久化> 攻击者事先制作好攻击链接, 需要欺骗用户自己去点击链接才能触发XSS代码(服务器中没有这样的页面和内容),一般容易出现在搜索页面。
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>XSS</title>
</head>
<body>
<form action="" method="get">
<input type="text" name="input">
<input type="submit">
</form>
<br>
<?php
$XssReflex = $_GET['input'];
echo 'output:<br>'.$XssReflex;
?>
</body>
</html>
比如在输入框中输入
<script>alert(document.cookie)</script>
就会弹出当前系统的cookie,当然弹窗是没有用的,需要将信息发送到攻击者的服务器。
存储型XSS:<持久化> 代码是存储在服务器中的,如在个人信息或发表文章等地方,加入代码,如果没有过滤或过滤不严,那么这些代码将储存到服务器中,每当有用户访问该页面的时候都会触发代码执行,这种XSS非常危险,容易造成蠕虫,大量盗窃cookie(虽然还有种DOM型XSS,但是也还是包括在存储型XSS内)。
DOM型XSS:基于文档对象模型Document Objeet Model,DOM)的一种漏洞。DOM是一个与平台、编程语言无关的接口,它允许程序或脚本动态地访问和更新文档内容、结构和样式,处理后的结果能够成为显示页面的一部分。DOM中有很多对象,其中一些是用户可以操纵的,如uRI ,location,refelTer等。客户端的脚本程序可以通过DOM动态地检查和修改页面内容,它不依赖于提交数据到服务器端,而从客户端获得DOM中的数据在本地执行,如果DOM中的数据没有经过严格确认,就会产生DOM XSS漏洞。
可以在进行数据转义,使脚本失效
<script>alert(document.cookie)</script>
可以使用HttpOnly属性,使js不能获取cookie。
也可以使用CSP对页面进行限制,这样就不需要逐个转义,有关文章参看http://www.ruanyifeng.com/blog/2016/09/csp.html
CSRF
与XSS不同的是,CSRF并不是想办法获取cookie,而是诱导用户点击某个连接,这样访问这个网站的时候就会自动带上cookie,比如在攻击者的网站带一个链接
恭喜你获得了iPhone X一台,快来 <a href="www.icbc.com.cn/transfer?toBankId=黑客账户&money=金额">领取吧!</a>
得事先知道icbc.com.cn的转账操作的url和参数名称。如果这个用户恰好登录了icbc.com, 那他的cookie还在, 当他禁不住诱惑,点了这个链接后,一个转账操作就神不知鬼不觉的发生了。
跨域
浏览器的同源策略在一定程度上保证了安全性,同时也引来了跨域等问题,常见的跨域解决方法为反向代理,cors等,反向代理容易理解,就是代理服务器将请求作为发送方发送,cors则比较复杂一些
cors
使用过cors的人应该发现过一个http请求有时会请求2次的时候,其中一次是以options方式发起的请求,为什么会多出一次请求。
跨域问题中,有一些 request 会收不到 response,因为 response 被浏览器拦截了,内容不告诉你
另外一些请求会根本发不出去,因为浏览器不允许发出那样的 request。
接下来,我们就来讨论,哪些情况会导致收不到 response,哪些情况会导致 request 失败。这两种失败方式是由两种发送方式决定的,也就是简单请求和预检请求。
简单请求
- request method 只能是 GET,HEAD,POST
- 只能有浏览器默认添加的 headers,以及一些 CORS 协议中默许的 headers
- Content-Type这个header的value只能是特定的3个text/plain、multipart/form-data、application/x-www-form-urlencoded
一旦一个 request 是 simple request,那么,尽管这个请求是跨域的,它也会被浏览器直接放行。但是,在 response 返回的时候,浏览器并不会把 response 直接交给你,而是去检查这个 response 的 headers 中有没有 Access-Control-Allow-Origin,以及这个 header 的 value 包含 request 发出的地址。
如果两个条件都满足, response 会被返回给发出请求的程序;如果没有这个 header 或者 value 不对, response 就会被拦截下来,因为在浏览器看来,这个 response 不属于你(因为服务器没有明确允许你这个“域”来请求它)。如果你使用的是 chrome 浏览器,在 response 被拦截下来的时候,console 中会显示一个类似于下面的错误信息:
repeat this in your console
尽管发出request的程序无法得到 response,但是这个请求实际上是被发出了的,而且服务器也会完整的处理这个request。可以想见,如果被请求的服务器支持被跨域请求,那么它一定会想办法在 response 中加上Access-Controll-Allow-Origin这个 header,并且附上合适的值。什么是合适的值呢?在 Request 的headers中会有一个 Origin,只要Access-Controll-Allow-Origin包含这个 Origin 就可以了(如果是*,那么就等于包含所有的 Origin)。
预检请求
- 不是 GET,HEAD,POST 请求;比如是 PUT 请求
- 包含一些非 CORS 协议默许的 headers,比如Authorization,X-Request-With 或者一些自定义的headers。
- Content-Type 不是默许的那 3 种,text/plain、multipart/form-data、application/x-www-form-urlencoded
只要请求不满足其中一条,就属于非简单请求。在一个请求被发出之前,浏览器会先发一个 OPTIONS 请求到目标“域”的服务器上,这个提前发出的请求,被称为 preflight request,也就出现了为什么有的时候,会出现两次访问的情况。
预检请求整个流程如下:
- 浏览器发送 preflight request(那个 OPTIONS 请求[2])
- 浏览器收到 preflight response(也就是刚刚那个 request 的返回)
- 浏览器根据 preflight response 中的 Access-Control-Allow-Origin, Access-Control-Allow-Headers以及其他Access-Control-*类的headers 中的 value 来判断网页程序真正要发出的 request 是否符合要求
- 如果这个 request 符合要求,request 被发出,网页程序可以收到正常的 response(如果不出网络通讯上的意外);如果这个 request 被判定为不符合要求,这个 request 干脆就不会被发出。
"预检"请求用的请求方法是OPTIONS,表示这个请求是用来询问的。头信息里面,关键字段是Origin,表示请求来自哪个源。
除了Origin字段,"预检"请求的头信息包括两个特殊字段。
(1)Access-Control-Request-Method
该字段是必须的,用来列出浏览器的CORS请求会用到哪些HTTP方法,上例是PUT。
(2)Access-Control-Request-Headers
该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段,上例是X-Custom-Header。
预检请求响应头:
(1)Access-Control-Allow-Methods
该字段必需,它的值是逗号分隔的一个字符串,表明服务器支持的所有跨域请求的方法。注意,返回的是所有支持的方法,而不单是浏览器请求的那个方法。这是为了避免多次"预检"请求。
(2)Access-Control-Allow-Headers
如果浏览器请求包括Access-Control-Request-Headers字段,则Access-Control-Allow-Headers字段是必需的。它也是一个逗号分隔的字符串,表明服务器支持的所有头信息字段,不限于浏览器在"预检"中请求的字段。
(3)Access-Control-Allow-Credentials
该字段与简单请求时的含义相同。
(4)Access-Control-Max-Age
该字段可选,用来指定本次预检请求的有效期,单位为秒。上面结果中,有效期是20天(1728000秒),即允许缓存该条回应1728000秒(即20天),在此期间,不用发出另一条预检请求。