跨域请求与常见解决方式
在【常见安全测试项目总结-1】这篇文章中,有提到通过CSRF攻击伪造用户请求。在学习的时候有想到既然有浏览器的同源策略,为什么还会有CSRF攻击呢?在我的记忆中,浏览器同源策略会阻止向非同源地址发送AJAX请求,在这种情况下,恶意网站伪造的用户请求是无法发送到目标站点的呀?经过进一步学习后发现:在同源策略下,浏览器发现跨域请求时,请求能发出去,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了。看到这里发现自己对于跨域问题的理解还是有些肤浅,故又看了些文章写下了这篇笔记。
什么是同源策略
同源
同源指目标的协议,域名,子域名,端口 均为一致,即为同源。
限制
同源策略对于非同源、跨域的请求设置了各种限制。这种限制并不能简单的理解为禁止获取非同源的资源(<img>
,<link>
,<script>
标签都可以请求到非同源内容),也不能理解为禁止跨域请求(因为AJAX确实发出去了,只是服务端的响应被屏蔽了,我就是掉进了这个误区中)。准确的说,同源策略的限制如下:
限制获取cookies、LocalStorage等存储
限制DOM节点
限制AJAX的请求结果获取
实例使用时,我遇到的较为常见的触发这三条限制的场景为:
- 通过AJAX调用跨域API
- 在iframe中试图修改外界DOM
跨域可用方案
那么当我们的需求遇到了同源策略的限制,应该如何解决呢?这里转述了下大佬总结的一些跨域解决方案:
JSONP
JSONP的原理是利用<script>
标签没有同源限制的特性,通过<script>
标签获取服务端动态生成的JSON数据。举例如下:
后端将返回的JSON作为参数放入一个与前端约定好的回调方法中。如约定回调方法名为callback,则后端返回以下内容:
1 | "callback("+JSONStr+")" |
前端则通过向页面写入<script>
标签的方式来向后端地址发送get请求:
1 | function jsonp({ url, params, callback }) { |
本质上是向页面中引入了callback(JSONStr)
这句函数调用,调用我们在前端中预先定义好的callback函数,而数据作为参数传入了前端。
以上的调用方式较为麻烦,jQuery则为我们提供了封装好的JSONP调用方法:
1 | $.ajax({ |
CORS
CORS需要浏览器与后端共同支持。浏览器会自动进行CORS通信,而后端则需要配置。
后端需要通过设置Access-Control-Allow-Origin来开启CORS。这个属性用于设置那些域名可以访问该资源。
前端在通过CORS发送跨域请求时,分为简单请求与发杂请求两种情况。简单请求指方法为GET
/ post
/ HEAD
之一,且Content-Type为test/plain
/ multipart/form-data
/ application/x-www-form-urlencoded
之一。其余的请求为复杂请求,复杂请求在通信前会增加一起http请求,来确定服务端是否允许跨域请求。
反向代理
既然我们知道同源策略限制的是非同源的请求,那么只要我们通过Nginx等支持反向代理的服务器将我们需要的地址代理到同一域名端口下,非同源请求自然就变成了同源请求。
我们需要做的是反向代理目标接口,并且修改cookie中的domain信息,以供当前域写入cookie,实现跨域带cookie请求。示例Nginx配置如下:
1 | // proxy服务器 |
以上三种是最主流的解决跨域访问的方案了,其余还有一些方法,个人觉得不是很常用,感兴趣的朋友可以从文末的引用中看下大佬的原文。