使用 CloudFront 函数将 X-Frame-Options header 添加到所有 URL

Add X-Frame-Options header to all URLs using CloudFront functions

我有一个单页应用程序,我试图通过向 HTML 响应添加 X-Frame-Options header 来防止点击劫持。我的网站通过 CloudFront 托管在 S3 上。

CloudFront 分发配置为默认发送 index.html

Default root object
index.html

在错误页面部分,我将 404 页面配置为也指向 index.html。这样,所有不在 S3 return 中的 URL 默认为 HTML,即 /login/admin

更新 403状态码也配置:

然后我按照描述创建了一个 CloudFront 函数 here 并将其分配给查看器响应:

function handler(event) {
    var response = event.response;
    var headers = response.headers;

    headers['x-frame-options'] = {value: 'DENY'}; 

    return response;
}

这有效,但仅适用于 /:

curl -v https://<MYSITE.com>
....
< x-frame-options: DENY

对于其他 URL,它不起作用 - x-frame-options header 缺失:

curl -v https://<MYSITE.com>/login
....
< x-cache: Error from cloudfront

我的问题是 - 为什么我的 cloudfront 函数没有在错误响应中附加 header,我该怎么做才能添加它?

我了解到您的问题是:

  • Q1:为什么 CloudFront 函数对 / 有效?
  • 问题 2:为什么 CloudFront 功能对其他 url 路径不起作用?

请参考以下回复:

  • A1:因为您可能会指定一个 Default Root Object [1](例如 index.html),它会在用户请求根 URL 时返回对象。当 CloudFront returns 具有 200 ok 的对象时,将在 viewer response 事件上调用 CloudFront 函数。
  • A2:您可能没有在 S3 存储桶策略中授予 s3:ListBucket 权限(例如 OAI). As the result, you will get Access Denied(403) errors for missing objects instead of 404 Not Found errors. Namely, the Error Pages you have configured isn't applied to this case, and the CloudFront Function won't be invoked because the HTTP status code is higher than 399[2]

[Updated] 建议:

  • 因为当源 returns HTTP 状态代码为 400 或更高时,CloudFront 不会为 viewer response 事件调用边缘函数。但是,针对所有源响应调用 origin response 事件的 Lambda@Edge 函数。在这个场景中,我建议我们应该使用 Lambda@Edge 而不是 CloudFront Functions。
  • 为方便起见,请参考l@e的示例代码:
exports.handler = async (event, context) => {
    const response = event.Records[0].cf.response;
    const headers = response.headers;
   
    headers['x-frame-options'] = [{
        key: 'X-Frame-Options',
        value: 'DENY',
    }];

    return response;
};
  • 仅供参考。这是我的 curl 测试结果:
# PATH: `/`
$ curl -sSL -D - https://dxxxxxxx.cloudfront.net/
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 12
Connection: keep-alive
ETag: "e59ff97941044f85df5297e1c302d260"
___snipped___
Server: AmazonS3
X-Frame-Options: DENY
___snipped___

# PATH: `/login`
$ curl -sSL -D - https://dxxxxxxx.cloudfront.net/login
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 12
Connection: keep-alive
ETag: "e59ff97941044f85df5297e1c302d260"
___snipped___
Server: AmazonS3
X-Frame-Options: DENY
___snipped___