我的踩坑之旅 跨域问题引发Bug

场景:

由于业务原因需要在请求中添加一个信息表明请求的source,经过一轮方案的评审,大家共同决定把这source信息存放在消息header中。前端小伙伴听完之后心里暗自偷笑:就一行的代码的事,请求的时候在消息头中添加source:xxxx,这么轻松。然后也没有测试就直接发布了。刚发布没多久,用户纷纷过来投诉各种页面打不开。

cause:

用户刚投诉,小伙伴们纷纷跑到后台抓取日志查看,但是啥也没有。只能亲测了页面了,一打开页面立马在console上看到各种红点,全显示各种跨域问题。当时就纳闷了,项目中有考虑跨域问题呀,后台配置了CORSFilter,以前一直也没有什么问题呀。经过各种确认之后才发现是由于前端加了自定义消息头的原因。

跨域流程具体分析:

说到跨域,首先有已个关键词:同源性。同源性指的是当前页面的协议号,域名,端口号与所请求的资源的协议号,域名,端口号保持一致。浏览器为什么要这么做呢?这是从安全方面考虑,防止XSS攻击。但是现实场景中,很多情况又不得不跨域请求。这该怎么办呢?W3C增加了CORS标准,这个标准允许浏览器向跨源服务器发出XMLHttpRequest请求。CORS需要浏览器和服务器同时支持。在跨域请求中可以分为简单请求和非简单请求,简单请求指的是——请求方法为GET,POST,HEAD,请求响应头只能为:Accept,Accept-Language,Last-Event-ID,Content-type,且Content-type的值只能为application/x-www-form-urlencoded、multipart/form-data、text/plain。其它的请求都属于非简单请求。

简单请求:简单请求相对于非跨域请求在请求header中添加了一个origin头,表明本次请求的来源,服务器收到请求,根据origin头判断是否支持本次请求,如果支持返回响应结果,并在响应中添加了一个Access-Control-Allow-Origin头,如果服务器不支持本次请求,会返回一个正常的http响应,正常的响应指的是http status code正常,但是没有响应内容。

非简单请求:非简单请求相对于非跨域请求增加了一次请求,这次请求俗称“预检”请求,这个请求的request method 是OPTIONS方法,header头中有origin和Access-Control-Request-Header,origin头的意义跟上文的一致,Access-Control-Request-Header头包含的信息是本次请求(真实请求,不是指嗅探请求)的所有请求头。这个请求顾名思义就是嗅探下服务器是否支持本次请求。嗅探的内容包括:服务器是否支持真实请求的request method,是否支持真实请求的消息头(具体是从Access-Control-Request-Header取出值,然后跟服务器配置的可接受消息头进行比对),查看当前网页所在的域名是否在服务器的许可名单中(查看origin头中的值是不是在服务器的允许域名列表中),若服务器不支持本次真实请求的话,嗅探请求会返回403,真实请求也不会发生了。

服务器端的配置:以上讨论的是浏览器端做的操作,当然那些操作用户无法感知,程序猿也不需要特别开发,一切都是浏览器自主完成,目前大部分浏览器都支持CORS。CORS需要浏览器和服务器共同配合完成,那服务器端需要配置什么呢?总结起来就那么几点:哪些域名是服务器认可得,哪些请求方法是服务器认可的,哪些请求头是服务认可的,是否允许设置cookie。下面利用spingMVC的CORSFilter来配置服务器(不止这一种方案,还有其他诸如在Nginx配置响应头)作个示例,具体如下:

CORS

cors.allowOrigin

*

//配置支持的方法

cors.supportedMethods

GET,POST, HEAD, PUT, DELETE

//配置支持的消息头

cors.supportedHeaders

Accept,Origin, Authorization, X-Requested-With, Content-Type, Last-Modified

//配置响应结果的暴露的消息头

cors.exposedHeaders

Set-Cookie

//是否允许cookie

cors.supportsCredentials

true

CORS

/*

服务器端配置之后,就可以进行“预检”请求了,“预检“”请求之后,你会发现响应消息头中相对于非跨域请求会增加几个消息头:Access-Contol-Allow-Origin(表明服务器允许的消息来源域),Access-Control-Allow-Method(表明服务器允许的请求方法),Access-Control-Allow-Header(表明服务器允许的请求头),Access-Control-Allow-Credentials(是否允许Cookie,若不允许,前端就拿不到cookie了),浏览器收到这几个头之后,觉得真实请求满足这些条件,接下来就会发起真实的请求了。

总结:回到最开始的bug问题,这个问题是因为前端开发人员在请求中自定义了一个消息头source,不在简单请求的范围内,属于非简单请求,在发起“预检”请求时,由于后台CORSFilter中没有配置允许该请求头,倒致“预检”请求403。

更多精彩内容:

项目管理应该怎么做?

Web安全测试基础 下

Web安全测试基础 上

黑客携手AI的时代, 你HOLD住吗?

项目管理上的失误和3大应对措施

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180309A0NWP700?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励