AWS API Gateway - CORS“access-control-allow-origin” - 多个条目

时间:2016-09-22 00:56:09

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

我有一个AWS Lambda实例,它连接到已定义的AWS API网关。如果我启用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>

5 个答案:

答案 0 :(得分:14)

如果您想启用多个Origins,这一直是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网关中进行设置,请添加OPTIONS方法,并为Integration Request选择Lambda Function,并勾选Use Lambda Proxy integration

当然,这样做的缺点是你要支付lambda函数,调用lambda函数可能比模拟集成延迟50ms。

答案 1 :(得分:7)

为什么不使用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

答案 2 :(得分:5)

不幸的是,今天不可能。 CORS规范不允许部分通配符,并且当前API网关仅允许标头的单个静态值。

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

答案 3 :(得分:2)

我做了这样的事情:

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('https://exampleLambda.com/v1/example', { 
   method: 'get',
   mode: 'cors'
   headers: new Headers({
     'Authorization': 'Bearer 12345, 
   }), 
 })
 .then(result => result.json())
 .then(console.log)

答案 4 :(得分:0)

您可以使API Gateway返回以逗号分隔的域列表,但浏览器只需要一个。其他答案中都暗示了这一点,只是明确说明了这一点。

以下是浏览器上的参考,仅接受CORS标头中的一个域: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors/CORSMultipleAllowOriginNotAllowed

仅用于踢球,这是您返回多个的方式(尽管不确定为什么要这样做)。将单引号括在逗号分隔列表中。我只是用我的一种API做到了这一点,并且可以正常工作(因为它返回了多个域并且API中断了。)

首先单击此处:

enter image description here

按照以下说明填写(使用您的值):

enter image description here

请注意仅在开头和结尾使用单引号。您将返回多个域,但浏览器不会进行下一个调用,因为它不会解析它们进行匹配。

这是POSTman的屏幕截图,显示了标头中返回的两个值: enter image description here