牛叉的AJAX,这种酷请求还真的有安全问题?
作者 | 撒网要见鱼
链接 | cnblogs.com/dailc/p/8191150.html
# AJAX三问
- AJAX请求真的不安全么?
- AJAX请求哪里不安全?
- 怎么样让AJAX请求更安全?
# 前言
本文包含的内容较多,包括AJAX,CORS,XSSb I J j d d _,CSRF等内容,要完整的看完并理解需要付出一定的时间。z + 8 9
另外,见解有限,如有描述不当之处,请帮忙及时指出。
# 正文开始
从入坑前端开始,一直到现在,& h * C e j dAv 3 ^ y & ]JAX请求都是以极高的频率重复0 y % d _ .出现,也% X Q解决过不少AJAX中遇到的问题,如跨域调试,错误调试等等。
从这种,发现了一个共通现象:那就是每次和后台人员对接时,他们都会提到AJAX请求不安全,请用普通http请求!
虽然很多时候,都是经过多翻口舌之争后,最终后台那R , Y w e @ f边妥协,允许部分符合条件+ q : s I I 5 A 7的p Q r A 1AJAX请求。但是,我却很纠结一个问题:AJAX请求真的不安全么?为什么我自己写后台时并没有发现这个问题?
于是,开始k j l m . 3 ) 7 4 Mb应用中,客户端输入不可信是一个基本原则。
# AJAX不安全的说法从何而来?
在AJAXW b a出现时,那j ; $ t { R时的服务端还是很古老的那一批,因此m 7 / 6 ? R @ M完@ S 0 { B 6 8全没有考虑到AJAX出现后,前端请求方式会变得异常复杂,造成以前的安全策略已经无法满足要求了,导致大批的后台安全漏洞曝光。。。
很显然,都是因为AJAX出现后曝光了更多的安全漏洞,9 & p 8 B 7 6 Y 5导致它看起来很危险(因为AJAX出现后,请求方式变多了,以前的架构在新的请求中就可能出现更多漏洞)
So,AJQ E G kAX不安全的说法自然扩散到了各个角落。
# 常见的几种Web前端安全问题
要知道AJAX请求是否安全,那么就得先知道Web前端中到底有那几种安全问题
1.XSS(跨站脚本攻击)(cross-sitO ] R T 2 Z z Qe scripting)
-> 伪造会话(基于1 A n B Y = # 3XSS实现CSRF)
-> 劫持cookie
-> 恶意代码执行
2.CSRF(跨站* N S ]请求伪造)(cross-site request forgery)
-> 伪造用户身份操作
3. SQL注入...(其它暂且不提)如上,Web前端中的安全问题主要就是这% z Y Z几大类(仅列举部分做分析),所以我们首先要分A N t U | d i N析Ap e pJAX与这几r s Q @ z ? c (大类之间的关系。(XSS和CSRF,在下文也会做简单介绍)
# CSRF简介
CSRF,特征很简单:冒用用户身份,进行恶意操作
时至今日,这项安全漏洞已经被人们剖析的很透彻了,随便Google,百度之,都会找到很多的解释。这里也用一张图来先做简单描述:
注:下面介+ a O x * L J _绍参考了来源文Y A ( b V R i H章中的描述,譬如图就是参考了来源中的博文后重绘的。
所以,我们看到关键条件是:
- 采用cookie来进行用户校验
- 登 . - U 6 3录受信任网站A,并在本地生成Cookie
- 在不登出A的情况下,访问危险网站B
一般在(4)处恶意网站(BM Y 2 {)的攻击手段如下(必须是指向A的地址,否则无法带上cookie):
// 1.譬如在5 e | 6网站内的图U p ` E\' action=\'http://www.bank.examplR 6 C M D + t he/transfer\'
target=\"csrf-frame\" id=\"csrf-form\">
<input type=\'hidden\' name=\h h E i'toBankId\' value=\'heZ 8 2 u Gllo\'>
<inpuS j Q t type=\_ T K 8 f M ['hidden\' name=\'amouc 6 g o : ent\' value=\'1000000\'>
<input type=\'submit\' vZ v | !alue=\'su1 L 0 4 `bmit\'>
</form>
<script>document.getElementById(\"csrf-form\").submit()</script>而且,从头到尾,攻击网站0 j ~ $ V 9都没有获取到过 cookie,都是通过浏览器间接实现(利用Web的cookie隐式身份验证机制),所以HttpOnlyN R ^ l | k并不会影响这个攻击
最后说下,几种常见的CSRF防御手段:
1. 验证HTTP Referez H * (r字段(非常简单,但是鉴于客户+ ! Q M端并不可信任,所以并不是很安全)
防止CSRF,检查Referer字段简单直接,但是其[ { B m A完全依赖浏览器发送正确的Referer字段。
虽然http协议对此字 { R _ y段的内容有明确的规定,但并无法保证来访的浏览器的具体实现,亦无法保证浏览器没有安全漏洞影响到此字L z s P u f !段! X c [ g l 2 p。并且也存在攻击者攻击某些浏览器,篡改其Referer字段的可能。
2. 在请求地址中添加token并验证
譬如post中,以参数的形式加入一个随机产生的token。
#2 m E x CSRF与AJAX的关系
上文中,我们看到CSRF的前提是cookie验证用户身份,那么它与AJAX{ n U的关系大么?
我们先7 7 C h分析AJAX中带cookie验证的情况:
1. AJAX受到N @ )浏览器的同源策略限制
2. AJAX默认无法请求跨域的接口
当然后台可以配置Access-ContX I & I ) ,rol-Allow-Origin: *之类的允许所有的跨域请求
3. AJAX请求无法携带跨域cooki/ | ! e Te
如果强行开启with@ { L 1 :Credentials,必须服务端配合认证,无法H R Z ^ _用作, 3 } E z M height=\'0\'>
然后,接下来发生的故事就和CSRF中提到的一致。这种情况就是基于X) x k t L ( s @ +SS5 = W _而开展的CSRF,也有人喜欢称之为XSRF
需要注意,这里并没有自己拿到cookie,而是CSRF中提到的利用浏览器的隐式验证机制来冒G c z充用= e y K M m w 1 B户。
3.其它恶意代码执行
其实上面的cookie劫持以及会话伪造都算是恶意代码执行,为了区别,这里就专指前端的流氓JS。
譬如前面的评论中的输入可以是:
- 譬如市面上盛; o a # E行的网页游戏弹窗等。
- 譬如干脆直接让这+ H ~ M c $ * v个页面卡死都可以。
- 譬如无限循环。
这里再提一点,上述都是从前端输入作为入口的,但r h W p u实际上有一类的输入也不可忽视,那1 ( h T t q就是:富文本攻击
它的特点就是:富文本中注入了脚本,并且前后端未进行过滤,导致直接输出到了页面中。
因为存在很$ { r多页面,都是将富文本内容展K n ~ N w M x示到网页上的,没有进行过滤(哪怕时至今日( 9 R { Y,仍然有不少页面),这样只要富文本中有注入脚本,基本就中招了…..
结论:
只要最终能向页面输出可执行的脚本语句,那么就是有漏洞,XSS攻击都有可能发生。
而且,基本上xss漏洞是很广泛的,虽然攻击类型很被Y ? @ e Y动,也需要大量时间分析,但胜在大量的网站上都存在(特别j p Q h是那种长期不更新的)
再提一点。上述的介绍G L : I I更多k ; 9 1 U # O的是从造成的5 2 K + V H h 6后果来看,但其实如果从攻击手动来看的话可以分为几大类型:
- 反射型XSS攻击(直接通过URL注入,而且很多浏览器都自带防御)
- 存储型XSS攻击(存储到DB后读取时注入)
- 还有一个DOM-Based型。
上述示例中都X ! = + ( @ P 3是存储型,具体更多内容网上已经有很详细的资料,这里不再继续深入,放一张图巩固下。
如何预防XSS:
1、输入过滤,不信任用户的任何输入,过滤其中的<、>、/等可能导致脚本注入的特殊字符,或者过滤script、javascript等脚5 1 b = / } ; / H本关键字,或者对V F | j A B $ @输入数据的长度进行限制等等,还得考虑攻击者使用十六进制编码来输入脚本的方式。
2、输出进行编码,和输入过滤类似,不过是从输出上着手,数据输出到页面时,经过HtmlEQ b O 1 7 R kncoder等工具编码,这样就不会存在直接输出可执行的脚本了
3、cookie设置http-only,这样用脚本就无法获取cookie了(这样只有浏览器向Web服务器发起请求的时才会带上cookie字段,7 / o 5 p S d避免了X1 # n d h | h E BSS攻击利用Ja u H ?vaScript的document.cookie获取cookie)
4k g )、Cookie防盗,尽可能地避免在Cookie中泄露隐私,如用z Y ] P户名、密码等;或者,为了防止重放攻击,可以将Cookie和IP进行绑定,H A i a m这样也可以阻止攻击者冒充正常用户的身份。
注意:特别c L } f A E K是后台,一定不能信任前端的输入,需要过滤与校验。
# XSS与AJAX的关系
以上分析了XSS造成一些影响与问题,仍然发现:与AJAX关系不大,因为这些问题不管用不用Am j ^ IJAX都会发生。
看看这种情况,譬如上述的富文本注入中:
- 某个接口采用AJAX交互
- AJAX请求u = A = , b C b完后将对应富文本字段显示到了页面上-譬如innerHTML
但是,这真的与AJAX无关,这是前后端没有进行输入输出过滤而造成的后果。
所以,还是那句话:如果某个Web应用具备良好的安全性{ G 4 l,那么再怎么用“不安全的AJAX”也削弱不了它的安全性,反之如果应用本身存在漏洞,不管用何种技术请求,它都是不安全的
# SQL注Y N e o m入简介
sql注入展开将也是一门很大的学问,很早以前更是大行其道(当然,现在…),这里仅仅举几个最极端的示例。
前提是后台没有过滤前端的输入数据,否则根本无法生u I 5 ^ ^ O效。
假设页面A中有一个登陆查询存在拙劣的sql注入漏洞,这样子的:(最极端,最傻的情况)
<%P D j - % t o S@ page language=\"java\" contentType=\"text/html; chae s v p = vrset=UTF-8\" pageEncoding=\"UTF-8\"%> <formH 4 K action=\"login.jsp\" method=\"post\"> 请输入用户名与密码:<BR> <input name=\"name\" type=\"text\"> <input name=\"password\" typ. | @ ]e=\"teV k 3 / g 6 ; i +xt\"> <input t^ Z bype=\"suV M F } # Q ^ 8 lbmit\" value=\"登陆\"> &l^ @ 4t;2 2 ~ B $ i /form>
在接收到登陆请求后,服务端的实际执行代码时是:
String sql = \"SELECT * Fs _ # @ 1ROM us; H 0 a Hers WH 8 6HERE name = \'\" + name
+ \"\' AND password = \'u E Z\" + password + \"\'\";然而有攻击者分析出后台可能存在漏洞,尝试sql注, 8 ] ?入攻击,输入
name = \' or 1=1password = anything那么这样,后台接收到数据后,实际上, J O * 2 ? z J查询的结果是
SELECT * FROM users WHERE name = \' \' or 1=1 AND password = \'anything\^ s r'故而,攻击u A x W T者成功的绕过的用户名,利用后台漏洞登陆了。
当然了,像这! { J =类这么低级的漏洞,现象几乎已经不存在了,往往这类型漏洞需要仔细分析,耗时。(又或者是有内奸…..)
# SQL注入与AJAX的关系
额,从上述的示例中看不出和AJAX有什么关系。但是我们可以这样假设:
- 有一个接口,接收AJAX post的数据
- 数据中有一个字段 name,后台接收到后没有进行过滤,直接如上面的演示一样,执行sql语句了
- 所以AJAX中如果给那个字段传入非法的注入信息,就会触发这个漏洞q L i ] # 0 a,导致攻击生效
对,就是这样极端的情况下才会发生,而且与AJAX并没有关系,因为换成任何一种其它请求都会有类似的情况….
所以说,结论是:SQL注入与AJAX无关。
# AJAXH _ /和HTTP请求的区别
从本质上将:AJAX就是浏览器发出的HTTP请求,只不6 W U J过是浏览器加上了一个同源策略限制而已。AJAX请求的XMLHk v y vTTPRequest对象就是浏览器开放给JS调用HTTP请求用的。
那么AJAX和HTTP的区别呢?列出以下几点:
- AJAX请J A R I求受到浏览器的同源策略限制,存在跨域问题
- AJAX在进行复杂请求时,浏览器会预先发出OPTIONS预检(HTTP自己是不会预检的)
- 从使用角度上说,AJAX使用简单一点,少了些底层细节,多了些浏览器特性(如自动带上同域cookie等)
- 所以说,和认证上的HTTP请求的区别就是-多了一次浏览器的封装而已(浏览器会有自己的预处理,加上特定限制)
但是,从最终发出的报文来看,内容都是一样H V t w Z的(HTTP协议规范的内容),AJAX是发送HTTP请求的一种方式
所以从这一点可以得出一个结论:AJAX本质上安全性和HTTP请求一样
# CORS4 6 8 a E W 5 m与AJAX安全性之间的关联
按照前文中提到的内容,基本无法得出AJAX与请求不安全的关联。那么f * - | H $ 2接下来,再e P o /继续分析,如果使用了跨域资源共享(CORS)后的安全性。(因为往往ajax都会伴i o y k y r头部检查),就抛出对应错误。否则就是正常的响应,接下来发出真正的请求(如POST)
请求和响应的头部信息大概如下:
Request Headers// 在CORS中专门作为Origi3 j 4 y F o qn信5 j z息供后端比对,表示来源域。
Origin: http://xxx
Access-Control-Request-Headers:K 7 v 9 X-Requested # f逗号隔开的形式包含在这个头中,一般POST请求中就会带上
Access~ j # I t o g-Control-ReqL h * u ] ?uest-Method: OPTIONSResponse Headers
Access-Contr] L N V $ @ hol-Allow-HeB } 9aders: Origin, X-Requested-With, Content-Type,
AcceptAccess-Control-Allow-Methods: GET, POST, OPTIONS
Access-Controlf s L ; y . L 0-Allow-Origin: h_ e V 8 q 5ttp://xxx最终,客户端发出的请求,必须符合服务端的校验规则才能正确,服务端才会返回正确头部,n q ! | - _ n 2否则只会请求失败。报跨域错误。
以上仅是简介,更多信息可以参考来源中的ajax跨域,这应该是最全的解决方案了
# 为什么要配置CORS?
因为同源策略限制,AJAX无法请求跨域资源,CORSV } ] 2 G : J l可以解决AJAX跨域请求问题。
因此:在本文中,配置CORS只是为了AJAX能跨域请求。
# CORS会配置些什么信息?
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type,
AcceptAccess-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Origin: http://xxxX X t a r : C } T如上,加上这个配置后,必须符合要求的才算是正常的请求,否则就会拒绝掉,一般AJAX跨域的话都会有OPTIONS,所以在预检中就做了这一步。
可以看到,关/ $ x H 9 8键的可变信息是:Access-Control-Allow-Origin: http://xxx
这个配置就是域名白名单,规定在什么样q O H ( | H的域名下才能进行AJAX跨域请求。
CORS Origi} R k E Qn: *的安全性
关键问题来了,在上面的CORS配置是这样的:
Access-Control-Allow-Origin: http:$ A Z ^ ! a//xxx但是这个配置只允许p I ~ X 5特定域名访问,鉴于前端的复杂性,有时候调试起来不是很方便,因此有时候,会偷懒的设置为:
Access-Control-AllX } e Jow-Originw o , ~ , z 8: *这个代表所有来源的跨域AJ{ % # ^ W @ 5 i 5AX请求都能正常响应。
接下来我们o | L Z * 5 6再来分析设置Origin: *可能带来哪m # v % $ E x d些问题。(都是基于AJAX的情况)
问题1:会对cookie认证造成影响么?
不会。虽然*代表了所有来源都能正常请求,但是同源策略下,是无法带上跨域cookie的。因此根本无法用身k ; . M x V份验证。
而且,就算用withCredentials强行带上跨域cookie,因为后台没有支持,所以会报错。(U s ; m m 4 C 2这可以看成是CORSs模型的最后一道防线)
再者,后台就算配置AccO K Y S j 5 s !ess-Cont# m A + v Hrol-Allow-Credentials允许跨域cookie,但是这时候的安全策略是Origin不允许T M h - H T为,必须是一个明确的地址。(否则你就可以看到浏览器的报错信息-跨域cookie时,Origin不允许为)
问题2:如果伪造OO _ P ; O H d [ }rigin头部呢?
首先,标准的浏览器中是不允许你伪造的(除非有严重漏洞),所以一般需要通过模拟~ , p (客户端请求伪造。
但是。在非浏览器情况下,本来就没有同源策略@ W o 0。这又是何必…..
所以说,伪造Origin与CORS并没有关系。
问题3:如果后台本来就存在漏洞呢?
做这样一y ; H / J 6 b个假设,假设用户所在网络的内网中有一台内网服务器,并且配k k & V % Z Y置了允许x 6 W A 9 $ l }所有的跨域请求:(当然,外网是请求不到内网的)
// 允许任何来自任意域的跨域请求
Access-Control-Allow-Origin: *再假设内网服务器上恰巧存在敏感M 7 9 p h 7 s资源,并且没有额外设防,只要内网就能访问。譬如:
192.168.111.23/users.md然后用户访问了恶意网页,而像HTML之类的网页都是下f % D p载到本地执行的,正好网页内有恶意代码,去向192.168.111.23/users.md请求资源,再将接收到的服务端返回发送到攻击者服务器。(因为加了Origin为*,而且AJAX是由本地浏览器发) 6 z出的,所以用户下载到本地的恶意网站是可以访问到用户内网中的后台的)
然后这些敏感数据就这样被盗取了。
But,这是因为服务端漏洞而存在的问题,设置Origin为的后台上为何要放置敏感资源?正常设置为Origin为的最大作用是- p W 4 [ T G _ (用作公共API。
而且更重要的是,为何敏感资源就这样轻1 q g w U } 9 5易的被获取了?m A (为什么没有二次验证?
SO,后台本身有漏洞,w v o Z q T所以才导致被攻击,AJAX恰好是攻击的手段之一(除了AJAX外还会有其它的方式),所以很多锅都甩到了AJAX头上。
这样,可以得出一个保守点的结论:
Origin如果不是,AJj L V z R r AX请求并不会有安. ? : j一种攻击手S @ [ Y b 8 { 6 !段而已,没有AJAX,该不安全的仍然不安全。
譬如还有的说法是:因为在AJAX出现以前,如果出现安全漏洞,容易被察觉,但AJAX是异步的,更容易隐式的出现安全问题…..这也与安全性的本x w f R ~ L Q ?质无关。
最重要一点,从Web应用安- P ; ~全角度来谈,Web应用必须从不信任客户端。所以不要再把锅甩给AJAX。
# AJAX请求哪里不安全?
同上,AJAX本身并不存: Q R (在这种安全v k 9 } c 方案。
- Alloy S = w N ? ew-Origin可以设置特定的值,过滤特定的白名单
- 对于一些公共的Ac ] A B ePI,可以直接将Allow-Origin设置为*
- 当然,如果确认后台没有这p ~ & ? M +些隐藏漏洞,可以直接使用*,毕竟也只是针对浏览器的同源策略而已,影响没有那么大。
# 怎么样让AJAX请求更安全?& v ? K a
仍然是文中反复提到的结论:
让Web后台更安全,则AJAX请求也更安全,反N V y L s p Z之后台有漏洞,不管怎么样都是不安全的
# 写在最后的话
这样的话,应该可以把AJAX不安全的锅甩掉了吧?
# 参考资料
- https://dwz.cn/4L494n0l
- blog.csdn.net/gh% ; 4 b , isau/article/details/17027893
- cnblogs.com/lovesong/p/5199623.html
- b7 m u ^ J ^log.ca h / M ; x = Wsdn.ne& e *t/wei00d6ra/article/details/39137849
- https://segmentfault.com/q/1010000002500378/^ s x L g [ T
- blog.csdn.net/fengyinchao/article/details/50775121
- https://segmentfault.com/a/1) 4 h q190000012469713