我应该在 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 标头发送到不允许的来源吗?的主要内容,如果未能解决你的问题,请参考以下文章
带有飞行前请求的 Angularjs $q.all 在 OPTIONS 请求后解析