我应该在 OPTIONS 请求之后的实际请求中将任何 Access-Control-Allow-Origin 标头发送到不允许的来源吗?

Posted

技术标签:

【中文标题】我应该在 OPTIONS 请求之后的实际请求中将任何 Access-Control-Allow-Origin 标头发送到不允许的来源吗?【英文标题】:Should I send any Access-Control-Allow-Origin header to non-allowed origins in the actual request following the OPTIONS request? 【发布时间】:2018-02-15 15:21:33 【问题描述】:

我对它的工作原理有一个大致的了解。如果请求的“origin”标头有效(允许),我返回相同的“ORIGIN”值

但我不知道:

    对于 OPTIONS 请求之后的实际请求,我是否需要包含与我为预检请求返回给客户端的完全相同的 Access-Control-Allow-Origin 标头?服务器代码是否只需要在实际请求中存在“ORIGIN”标头时才需要这样做? (在下面的代码中,我没有检查请求是 OPTIONS/preflight 请求还是实际请求,我假设相同的代码可以适用于两者而不会造成伤害)。

(更多细节,因为“当请求的凭据模式为'include'时,响应中'Access-Control-Allow-Origin'标头的值不能是通配符'*'”,所以我需要ORIGIN将请求中的值放回响应中。

    如果 ORIGIN 不允许,我应该返回什么?

    根本不包括 Access-Control-Allow-Origin 标头? 或 setHeader("Access-Control-Allow-Origin", ""), 还是 setHeader("Access-Control-Allow-Origin", "null")?

public class CORSResponseFilter implements ContainerResponseFilter 

@Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException 
    MultivaluedMap<String, Object> headers = responseContext.getHeaders();

    String origin = requestContext.getHeaderString("Origin"); 


String origin = requestContext.getHeaderString("Origin");

    URL originUrl = null;
    try 
        if (StringUtils.hasText(origin)) 
            originUrl = new URL(origin);
            
            Pattern hostAllowedPattern = Pattern.compile("(.+\\.)*mydomain\\.com", Pattern.CASE_INSENSITIVE);

            if (hostAllowedPattern.matcher(originUrl.getHost()).matches()) 
                headers.add("Access-Control-Allow-Origin", origin);
             else 
                headers.add("Access-Control-Allow-Origin", "");
            
            headers.add("Vary", "Origin");
        

        headers.add("Access-Control-Allow-Credentials", "true");
        headers.add("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
        headers.add("Access-Control-Allow-Headers",

【问题讨论】:

【参考方案1】:

对于 OPTIONS 请求之后的实际请求,我是否需要包含与我为预检请求返回给客户端的完全相同的 Access-Control-Allow-Origin 标头?

是的,也就是说,如果您要发回一个实际的原始值而不是“*”通配符,那么该原始值就是导致OPTIONS 请求成功的原因。因为如果您发回的非通配符原始值与 OPTIONS 成功返回的值不同,这将导致浏览器阻止客户端代码访问响应(因为实际的原始值不匹配)。

服务器代码是否应该只在实际请求中存在“ORIGIN”标头时才需要这样做?

是的,因为当浏览器中运行的前端 javascript 代码使用 XHR 或 Fetch API 或某个 JavaScript 库中的 Ajax 方法来发出跨域请求时,浏览器总是会在请求中添加 Origin 标头。而Access-Control-Allow-Origin 只供浏览器使用。

因此,将Access-Control-Allow-Origin 发回给未在请求中发送Origin 的非浏览器工具是没有意义的——在这种情况下,您发送的只是浪费的字节。

当然有人可以使用curl 或任何非浏览器工具向服务器发送请求,并手动将Origin 标头添加到请求中。但这没关系——在这种情况下,他们将得到的响应与您发送到浏览器的响应相同。所以这实际上对测试很有帮助。

如果 ORIGIN 不允许,我应该返回什么? 根本不包括 Access-Control-Allow-Origin 标头?

是的。在这些情况下,根本不要发回 Access-Control-Allow-Origin 响应标头。这就是缺少标头的语义:如果服务器未发送 Access-Control-Allow-Origin 响应标头,则意味着服务器未选择允许来自运行浏览器的前端代码的跨域请求,因此适用默认的同源策略。

也就是说,通过不发送Access-Control-Allow-Origin响应头,服务器告诉浏览器:“请像往常一样使用默认的同源策略,并禁止所有前端JavaScript代码访问该响应发送了这个请求。”

或 setHeader("Access-Control-Allow-Origin", ""),

不,永远不需要像这样发回一个空值。这并不意味着什么特别。

还是 setHeader("Access-Control-Allow-Origin", "null")?

绝对不要那样做。在很多情况下,浏览器会发送带有 null 值的 Origin 标头,除非您有意允许所有带有 Origin: null 的请求访问来自服务器的响应,否则不要这样做。

有关详细信息,请参阅@987654321 的答案的当浏览器必须在内部将原点设置为将被序列化为null 部分的值@

【讨论】:

所以不需要检查它是否是预检电话?不用担心以前的电话? 我不是 100% 清楚你在问什么,但如果你问的是 - 就你的代码而言 - 对于预检,你检查 Origin 标题与 @ 987654339@,那么是的,你应该。就这一点而言,您的代码不应将预检 OPTIONS 请求与正常的 GET 或 POST 请求区别对待——所有这些都应以相同的方式检查 hostAllowedPattern。当然,在其他方面,您的代码需要对预检 OPTIONS 做出与其他请求不同的响应,但这是另一回事(例如,OPTIONS 响应应该没有响应正文)。

以上是关于我应该在 OPTIONS 请求之后的实际请求中将任何 Access-Control-Allow-Origin 标头发送到不允许的来源吗?的主要内容,如果未能解决你的问题,请参考以下文章

为啥会有OPTIONS请求

在 SOAP 请求中将 XML 数据作为参数传递

带有飞行前请求的 Angularjs $q.all 在 OPTIONS 请求后解析

JQuery POST 请求转换为 OPTIONS。为啥?

HTTP OPTIONS 请求可以返回 204 还是应该始终返回 200?

options预请求