浏览器同源策略及其关联头部详解
- Origin和Referer请求头
Origin 是一个请求头,由浏览器在发起跨站请求时自动添加,它标识请求的来源。包含协议、主机名、端口号。在 JavaScript 中,一个跨站请求可能如下:
fetch("https://some-site.com/api", { method: “GET”, headers: { “Content-Type”: “application/json”, },}); 在这个请求中,浏览器会自动添加 Origin 头。
Referer 头则标识当前请求的来源 URL。它主要用于让网站了解访问者来源、防止图片盗链,以及提供个性化内容服务。由浏览器在用户点击链接跳转时,将当前页面的完整URL带上。
- Access-Control-Allow-Origin和Access-Control-Allow-Credentials头
在服务器端,我们可以通过设置 Access-Control-Allow-Origin 和 Access-Control-Allow-Credentials 头,来控制哪些站点可以跨域访问我们的资源。
response.setHeader("Access-Control-Allow-Origin", "<https://allowed-site.com>");response.setHeader("Access-Control-Allow-Credentials", "true");
Access-Control-Allow-Origin 头指定了可以访问该资源的外域 URI。Access-Control-Allow-Credentials 头则指定了是否允许浏览器在跨站请求中携带用户的凭证(如 cookies 和 HTTP 认证信息)。
- Preflight请求
“预检”请求是一种由浏览器自动发出的请求,用于确认实际的跨站请求是否可以被服务器接受。它是一种 OPTIONS 请求,会附带 Access-Control-Request-Method 和 Access-Control-Request-Headers 等头,来询问服务器实际请求的允许情况。
- 多个Allow-Origin域名的处理
如果你希望允许多个特定的源进行访问,可以在服务器端编程以动态生成 Access-Control-Allow-Origin 头。
String origin = request.getHeader("Origin");if (allowedOriginsList.contains(origin)) { response.setHeader("Access-Control-Allow-Origin", origin);}
- Spring MVC在处理CORS的策略
在 Spring MVC 5.x 中,如果 allow-origin 被设置为 “",而请求头中存在 Origin,那么 Spring MVC 会将响应的 Access-Control-Allow-Origin 设置为请求中的 Origin 值。这个返回值有时会让人困惑,因为allowed origin一般是特定值,或者“”, 容易引起误解,值得注意。在老项目mgcc-kol就存在这个问题。
好消息是,在 Spring MVC 6中,如果Access-Control-Allow-Origin 设置为””,实际的响应头也会固定为”“,不会随着请求的Origin而变化。
- 跨源策略的最佳实践和可能的安全问题
虽然允许所有的源并允许发送 cookie 会带来方便,但这也可能导致 CSRF 攻击。假设有一个恶意网站evil-site.com尝试访问用户在某网站上的数据:
fetch("<https://legitimate-site.com/api/data>", { method: "GET", credentials: "include",});
如果服务器允许所有的源并允许发送 cookie,那么恶意网站就能取得用户的数据。
在这个例子中,evil-site.com实际上并没有直接获取到legitimate-site.com的cookie。当一个请求被发送到legitimate-site.com时,如果该请求的credentials属性被设置为"include”,那么浏览器会自动附带在用户浏览器上存储的legitimate-site.com的cookie。这意味着,尽管恶意网站无法直接访问cookie,但它可以通过构造一个特定的请求,诱使浏览器将cookie发送到legitimate-site.com。
这就是为什么将Access-Control-Allow-Credentials设为true的同时,将Access-Control-Allow-Origin设为"*“是危险的。这种配置允许任何网站发送带有cookie的请求,即使那些网站无法直接访问cookie,也能通过这种方式进行潜在的恶意操作。
因此,我们应:
避免在 Access-Control-Allow-Credentials 为 true 时,将 Access-Control-Allow-Origin 设置为 *。`` 在服务器端设定一个明确的允许源列表,而不是简单地接受所有的源。 在前端,合理使用 CORS 和其他技术来发送跨站请求,同时处理可能的错误和异常。 在老项目mgcc-kol中,我们配置存在vulnerability,应在后期项目中避免。
@Configuration
public class WebMvcAutoConfiguration implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowCredentials(true)
.allowedOrigins("*")
.allowedMethods("*")
.maxAge(3600);