AJAX跨域的问题
在AJAX
未出现之前,浏览器想从服务器获得资源,会经过如下一个过程:
浏览器发起请求 ---> 服务器接到请求响应给你HTML文档--->浏览器收到资源,刷新页面,加载获得的的HTML
之后ajax出现了,Asynchronous JavaScript + XML
(异步的JS和XML)可以阻止页面整体刷新,只是动态响应用户的操作,快速显示到局部。
但是我们浏览器有同源政策,不是同协议 同域名 同端口 的网页是无法相互访问的,ajax恰好是同源政策的拥趸,如果AJAX
向非同源的地址发起请求,会报错(form表单无视同源政策,可以发起跨域请求)。
这是为甚么呢,原页面用 form 提交到另一个域名之后,原页面的脚本无法获取新页面中的内容,所以浏览器认为这是安全的。而 AJAX 是可以读取响应内容的,因此浏览器不能允许你这样做。
所以浏览器这个策略的本质是,一个域名的 JS ,在未经允许的情况下,不得读取另一个域名的内容。但浏览器并不阻止你向另一个域名发送请求。
解决的办法:CORS 它允许浏览器跨域发起XMLHttpRequest
请求,而且可以发起多种请求,不像JSONP
只能发起GET
请求,全称是"跨域/源资源共享"(Cross-origin resource sharing)。
那ajax安全吗?
要知道AJAX请求是否安全,那么就得先知道Web前端中到底有那几种安全问题
1.XSS(跨站脚本攻击)(cross-site scripting)
2.CSRF(跨站请求伪造)(cross-site request forgery)
CSRF特征很简单:冒用用户身份,进行恶意操作,这项安全漏洞已经被人们剖析的很透彻了
所以,我们看到关键条件是:
1. 采用cookie来进行用户校验
2. 登录受信任网站A,并在本地生成Cookie
3. 在不登出A的情况下,访问危险网站B
4. 危险网站B要求访问网站A,发出request
5. 根据B在(4)处的请求,浏览器带着(2)处的cookie访问A站
一般在(4)处恶意网站(B)的攻击手段如下(必须是指向A的地址,否则无法带上cookie):
1.譬如在网站内的图片资源中潜入恶意的转账操作
2.构建恶意的隐藏表单,并通过脚本提交恶意请求
而且,从头到尾,攻击网站都没有获取到过 cookie,都是通过浏览器间接实现(利用Web的cookie隐式身份验证机制),所以HttpOnly并不会影响这个攻击
最后说下,几种常见的CSRF防御手段:
1. 验证HTTP Referer字段(非常简单,但是鉴于客户端并不可信任,所以并不是很安全)
2. 在请求地址中添加token并验证
CSRF与AJAX的关系
我们先分析AJAX中带cookie验证的情况:
1. AJAX受到浏览器的同源策略限制
2. AJAX默认无法请求跨域的接口
3.AJAX请求无法携带跨域cookie
譬如假设上图中第4部分的请求由AJAX发起,假设网站A已经允许了Access-Control-Allow-Origin: *,由于网站B与网站A是不同域名,所以存在跨域,根据同源策略,请求时根本就无法携带cookie,故而无法通过身份认证,攻击失败。。。就算Access-Control-Allow-Origin: *允许所有来源的AJAX请求,跨域的cookie默认情况下仍然是无法携带的,无法CSRF
cookie验证机制
Cookie是客户端的解决方案。用户用浏览器访问一个支持Cookie的网站的时候,用户会提供包含用户名的用户个人信息到服务器。
之后服务器向客户端回传相应的超文本也会发回这些个人信息,这些信息通过HTTP响应头(Response Header)传回来,客户端浏览器收到来自服务器的响应后,浏览器将这些信息存放在一个统一的位置。
当服务器返回客户端一个Http响应信息时,如果包含Cookie-Set这个头部时,意思就是指示客户端建立一个Cookie,并且在之后的请求中自动发送这个Cookie到服务端,知道这个Cookie过期。
如果Cookie的生命周期设置为整个会话期间,浏览器会将Cookie保存到内存中,浏览器关闭就会自动清除这个Cookie。
另一种情况就是设置了Cookie的生命周期,在生命周期内关闭浏览器,Cookie会保存在硬盘中,浏览器关闭也不会清除。下次打开浏览器访问对应网站,这个Cookie会自动发送到服务器端。
cookie特性:Cookie具有不可跨域名性。根据Cookie规范,浏览器访问Google只会携带Google的Cookie,而不会携带Baidu的Cookie。Google也只能操作Google的Cookie。W3C标准的浏览器会阻止JavaScript读写任何不属于自己网站的Cookie。换句话说,A网站的JavaScript程序读写B网站的Cookie不会有任何结果。