【问题标题】:AWS API Gateway - CORS "access-control-allow-origin" - multiple entriesAWS API Gateway - CORS“访问控制允许来源” - 多个条目
【发布时间】:2017-01-30 10:01:12
【问题描述】:

我有一个连接到定义的 AWS API 网关的 AWS Lambda 实例。如果我启用 CORS 并将access-control-allow-origin 定义为http://example.com,那么我可以从http://example.com 访问 Lambda 实例。但是,如果我使用https://example.com,它就不起作用了。

那么在 AWS 中,如何在不使用通配符的情况下使用多个 access-control-allow-origin 值来定义?我尝试使用 *.example.com 之类的东西,但这不起作用。

编辑:如果我在 API 网关上使用 '*' 作为我的值,但在我的 S3 存储桶上设置 CORS 规则,那会安全吗?存储桶规则示例:

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>http://example.com</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <AllowedMethod>POST</AllowedMethod>
        <AllowedMethod>PUT</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <AllowedHeader>*</AllowedHeader>
    </CORSRule>
    <CORSRule>
        <AllowedOrigin>https://example.com</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <AllowedMethod>POST</AllowedMethod>
        <AllowedMethod>PUT</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <AllowedHeader>*</AllowedHeader>
    </CORSRule>
    <CORSRule>
        <AllowedOrigin>https://www.example.com</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <AllowedMethod>POST</AllowedMethod>
        <AllowedMethod>PUT</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <AllowedHeader>*</AllowedHeader>
    </CORSRule>
</CORSConfiguration>

【问题讨论】:

  • 这里有同样的问题。我的情况是我必须使用 withCredentials() 选项,因此不允许使用通配符。我可能需要自己处理 cors 标头,而不是让 apigw 处理它。很奇怪,他们为 s3 提供了 CORS 规则,但没有为 apigatway 提供。

标签: amazon-web-services amazon-s3 lambda cors aws-api-gateway


【解决方案1】:

我做了这样的事情:

const handler: APIGatewayProxyHandler = async (event) => {
  const origin = event?.headers?.Origin || event?.headers?.origin;
  const allowedOrigins = ['https://example.com'];
  const headers = {
    'Access-Control-Allow-Origin': allowedOrigins.includes(origin)
      ? origin
      : allowedOrigins[0],
  };

  return {
    headers,
    body: JSON.stringify({
      myResponse: 'data',
    }),
    statusCode: 200,
  };
};

然后可以通过 chrome 开发工具进行测试,方法是转到您的客户端域并在控制台中运行 fetch:

fetch('https://exampleLambda.com/v1/example', { 
   method: 'get',
   mode: 'cors'
   headers: new Headers({
     'Authorization': 'Bearer 12345, 
   }), 
 })
 .then(result => result.json())
 .then(console.log)

【讨论】:

    【解决方案2】:

    为什么不使用 Velocity Template 语言映射模板从允许的域列表中检查并设置源头

    $input.json("$")
    #set($domains = ["https://www.example.com", "https://www.abcd.com"])
    #set($origin = $input.params("origin"))
    #if($domains.contains($origin))
    #set($context.responseOverride.header.Access-Control-Allow-Origin="$origin")
    #end
    

    【讨论】:

    • 这个应该放在哪里,然后在was提供的默认核心配置中应该有什么?
    • 这么旧的线程,但仍然可以使用,可能更适用于最新的 HTST 问题,在这些问题中,仅使用本地主机文件来“模拟”实时或测试域不再那么容易了。此外,这个答案值得比 Lambda 更多的选票。 Lambda 在这方面很浪费,你必须为每个 OPTIONS 请求付费,完全没有必要。我刚刚遇到了一个问题,希望我的 API 测试阶段可以从本地开发服务器访问,但也可以通过 Netlify 的测试服务器访问。使用了类似的东西,将其放在每个 OPTIONS 方法中的响应映射模板上,类似于使用 CORS 的所有其他方法。
    • 我对 dev 使用了类似的东西:我使用了这个 apporach:#if( $input.params('origin') == 'https://localhost:8080' &amp;&amp; $context.stage == 'test') #set($context.responseOverride.header.Access-Control-Allow-Origin = #end 这种方式默认被覆盖。
    • @RajanSharma 在 AWS Api Gateway 控制台中,options 和 post 方法的 Response Integration -> Content-Type: application/json -> Mapping Template
    • 感谢这个!完美运行!
    【解决方案3】:

    如果您想启用多个 Origin,这一直是 CORS 的烦恼。

    在其他系统(例如 express/nginx 等)中常见的解决方法是:

    • 检查浏览器发送的Origin标头
    • 对照来源白名单检查它
    • 如果匹配,则将传入的Origin 作为Access-Control-Allow-Origin 标头返回,否则返回占位符(默认来源)

    使用 AWS-Gateway 的自动连接 CORS 支持是不可能的,因为它使用模拟集成,但是如果您编写自己的代码来处理 OPTIONS 请求,则可以。

    以下是使用 lambda 代理集成编写的示例代码:

    const allowedOrigins = [
        "http://example.com",
        "http://example.com:8080",
        "https://example.com",
        "https?://[a-z]*.?myapp.com",
        "http://localhost:[0-9]*"
    ];
    
    exports.handler = (event, context) => {
        const origin = event.headers.Origin || event.headers.origin;
        var goodOrigin = false;
    
        if (origin) {
            allowedOrigins.forEach( allowedOrigin => {
                if (!goodOrigin && origin.match(allowedOrigin)) {
                    goodOrigin = true;
                }
            });
        }
    
        context.succeed({
            headers: {
                "Access-Control-Allow-Headers": "Accept,Accept-Language,Content-Language,Content-Type,Authorization,x-correlation-id",
                "Access-Control-Expose-Headers": "x-my-header-out",
                "Access-Control-Allow-Methods": "DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT",
                "Access-Control-Allow-Origin": goodOrigin ? origin : allowedOrigins[0]
            },
            statusCode: 204
        });
    };
    

    将其保存为 lambda 函数。要在 API-Gateway 中进行设置,请添加 OPTIONS 方法并为 Integration Request 选择 Lambda Function 并勾选 Use Lambda Proxy integration

    当然,这样做的缺点是您要为 lambda 函数付费,并且调用 lambda 函数可能会比模拟集成多出 50 毫秒的延迟。

    【讨论】:

    • 我正在使用基于 cookie 的身份验证,那么我们如何在不使用 lambda 代理集成的情况下为 GET 请求配置这些核心标头?
    【解决方案4】:

    不幸的是,这在今天是不可能的。 CORS 规范不允许部分通配符,目前 API Gateway 仅允许标头使用单个静态值。

    您可以重载 OPTIONS 方法以根据传入的主机标头动态返回此值。

    【讨论】:

    • 谢谢鲍勃。我知道不建议使用 * 作为值(因为任何事情都有效),但是对于低调的网站,您认为这会导致任何问题吗?
    • @Wes 这取决于您愿意接受的风险水平。如果这只是 http 与 https 的问题,您可以通过始终将客户端重定向到 https 来解决这个问题。随着FirefoxChrome 走向弃用http,这是有道理的,应该不会太难。
    猜你喜欢
    • 2023-03-17
    • 2017-03-06
    • 2019-02-09
    • 2016-06-02
    • 2021-09-07
    • 2016-06-27
    • 2016-12-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多