向后端发起GET请求成功了,POST请求却发生了403,然而再尝试Postman发送POST请求却能成功,为什么?记录一下整体过程
问题与结论
今天和后端联调,发现了一个问题,发起的get请求没有问题,post请求都被拦截了,403forbidden,后端觉得是前端配置问题,于是用 postman发送了请求,并且成功了,这是为什么呢?
先说结论确定了前端的配置没有问题后,查看了后端代码与历史修改记录(曾经是没问题的),发现后端修改了一行代码导致的,config.addAllowedOrigin("*")
,据后端所说,他们是重写了cors的拦截策略,因为安全性,所以删除了这行代码。
问题结论:没有允许非同origin下的请求
但是该行代码,同时引起了我的思考,为什么postman可以?为什么同样的GET请求可以,但是POST请求不可以?
解决过程
首先,判断并非是前端跨域问题。
在Webpack中设置反向代理通常是为了解决开发环境中的跨域请求问题。可以使用webpack-dev-server的反向代理功能来实现。且前端若配置失败,浏览器返回的错误是这样的。
于是应该是后端做了什么相关的策略。后端当时使用postman,发现并无问题。
因为之前项目是没问题的,所以去查了修改记录,所以发现是为了安全考虑,少了那一行代码。
贴上修改后的代码
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; @Configuration public class CorsConfig { @Bean public CorsFilter corsFilter(){ //1.添加CORS配置信息 CorsConfiguration config = new CorsConfiguration(); //1) 允许的域,不要写*,否则cookie就无法使用了 // config.addAllowedOrigin("*"); //这里填写请求的前端服务器 config.addAllowedOriginPattern("*"); //2) 是否发送Cookie信息 config.setAllowCredentials(true); //3) 允许的请求方式 config.addAllowedMethod("OPTIONS"); config.addAllowedMethod("HEAD"); config.addAllowedMethod("GET"); config.addAllowedMethod("PUT"); config.addAllowedMethod("POST"); config.addAllowedMethod("DELETE"); config.addAllowedMethod("PATCH"); //4) 允许的头信息 config.addAllowedHeader("*"); //2.添加映射路径,我们拦截一切请求 UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource(); configSource.registerCorsConfiguration("/**", config); //3.返回新的CorsFilter. return new CorsFilter(configSource); } }
为什么GET请求可以?
首先理解,请求头中的origin是什么?
HTTP 协议中的 Origin Header 存在于请求中,用于指明当前请求来自于哪个站点。
经查询资料, Origin是Referer头的升级版, 常用于CORS或者非GET
、HEAD
请求(MDN 的说法有误,不是只有 POST
)相关的服务端身份检验
浏览器端
Origin
无法手动设置
Origin
头是浏览器保护字段,类似的有Referer
、Host
、Content-Length
、Keep-alive
等,但是可以通过 nginx 代理修改。浏览器根据约定自动附加
浏览器附加
Origin
头的规则
- 根据fetch说明, 只有当请求为跨域请求或者非
get
,head
请求时都会自动附加。不可被编程,不可被编辑。get
,head
请求由于兼容性,故无法实现
非 CORS 情况下,
Origin
字段框架使用情况
- 据我了解, 绝大部分框架都没有使用 Origin 字段, 我所待的几个公司也从未根据此值来判断
所有符合规则的资源都会包含 Origin 头?
- 不是。例如跨域图片不会包含 Origin 头, 更多资源请查看
比如有的浏览器(IE)能够请求成功,而有的浏览器却请求失败(Chrome)。这不是因为前一个浏览器行为正确,而是因为前一个浏览器发出请求时没有带上 Origin
而后一个浏览器带上了正确的 Origin
。
而在服务器端,因为没有 Origin
Header,所以认为这不是一次 CORS
请求,所以没有进行 CORS
校验。这也反过来要求服务端强制请求带上 Origin
Header,才能进一步保证服务器的安全性。
可能当前项目后端请求中,并未校验GET(简单请求)的origin吧?因为本人只是一名前端,个人思考结果。如果有人知道具体原因,还请告知。
为什么Postman请求可以?
首先理解下同源策略
同源策略是浏览器的一个安全机制,限制了一个源(域名、协议、端口)的文档或脚本如何与来自另一个源的资源进行交互。这种限制是为了防止潜在的安全漏洞,比如跨站脚本(XSS)攻击。
但是,Postman 并不是一个浏览器,它是一个独立的工具,不受同源策略的限制。当你在 Postman 中发送请求时,它实际上是在模拟一个 HTTP 请求,并不像浏览器一样执行 JavaScript 代码。因此,Postman 可以轻松地发送请求到不同域名的服务器,并获得响应,而不会受到同源策略的约束。
而且Postman的默认请求头中,并没有Origin
的参数。
理论上来说,如果我手动添加,非同源,是否也会失败,事实证明,的确如此。