关于AWS预签名URL配置CORS限制域名访问及S3文件自动设置Cache-Control元数据的技术咨询
Hey there, let's break down your two AWS S3 issues and walk through practical solutions for each one!
1. Restricting Presigned URL Access to Your Domain Only
First, let's clear up why your CORS rules aren't working for presigned URLs: Presigned URLs bypass S3's standard permission checks—they grant direct, time-limited access to an object regardless of bucket-level CORS settings. That's why your CORS rules work for regular object requests but not for presigned ones.
Here are two reliable ways to lock access to your domain:
Option 1: Add Referer Conditions When Generating Presigned URLs
When creating a presigned URL, you can include a Conditions parameter that restricts usage to requests coming from your specific domain. This tells S3 to only honor the URL if the request's Referer header matches your allowed domain.
Example code for generating the restricted presigned URL (using AWS SDK for JavaScript):
const generatePresignedUrl = () => { const params = { Bucket: 'myvideos', Key: 'public/videos/your-video.mp4', Expires: 3600, // URL expires in 1 hour Conditions: [ // Replace with your domain; use wildcards like "https://*.yourdomain.com/*" for subdomains ["eq", "$Referer", "https://yourdomain.com/"] ] }; return s3.getSignedUrl('getObject', params); };
Any request from a different domain (like an embedded video on another site) will fail because its Referer header won't match the condition.
Option 2: Use CloudFront for Enhanced Control
For more flexibility (e.g., supporting multiple domains or complex access rules), pair S3 with CloudFront:
- Set up a CloudFront distribution pointing to your S3 bucket, and enable Origin Access Control (OAC) to ensure only CloudFront can access your S3 objects.
- In your CloudFront behavior settings, add a Referer whitelist to only allow requests from your domain.
- Use CloudFront signed URLs instead of S3 presigned URLs. This adds an extra layer of security and ensures only valid, domain-restricted requests reach your content.
2. Automatically Setting Cache-Control Metadata for S3 Objects
Let's start with the quick fix for your existing code, then cover automatic rules for all uploads.
Fix Your Current Transfer Code
The issue here is a tiny but critical syntax error: AWS SDK for JavaScript expects the metadata parameter to be CacheControl (capitalized) instead of cacheControl (lowercase). Here's your corrected code:
// transfer videos to S3 export const transferVideoToS3 = (videoUrl, filename, callback) => { request({ url: videoUrl, encoding: null }, function (err, res, body) { if (err) return callback(err, res); s3.upload({ Bucket: 'myvideos', Key: `public/videos/${filename}.mp4`, CacheControl: 'max-age=604800', // Fixed: capitalized parameter name ContentType: res.headers['content-type'], ContentLength: res.headers['content-length'], Body: body // buffer }, callback) }) }
This will now correctly set the Cache-Control metadata when uploading videos.
Automatically Set Cache-Control for All Uploads
If you want every object uploaded to your bucket (whether via code, console, or CLI) to get the Cache-Control metadata automatically, use an S3 event-triggered Lambda function:
- Create a Lambda Function: Use this Node.js code to check and update metadata for new objects:
import { S3Client, HeadObjectCommand, CopyObjectCommand } from "@aws-sdk/client-s3"; const s3Client = new S3Client({ region: 'your-region' }); export const handler = async (event) => { const record = event.Records[0]; const bucketName = record.s3.bucket.name; const objectKey = record.s3.object.key; // Skip if Cache-Control is already set const headParams = { Bucket: bucketName, Key: objectKey }; const headResult = await s3Client.send(new HeadObjectCommand(headParams)); if (headResult.CacheControl) return; // Copy the object to itself to set metadata const copyParams = { Bucket: bucketName, Key: objectKey, CopySource: `${bucketName}/${objectKey}`, CacheControl: 'max-age=604800', MetadataDirective: 'REPLACE' // Overwrite existing metadata }; await s3Client.send(new CopyObjectCommand(copyParams)); }; - Configure the S3 Trigger: In your Lambda function's settings, add an S3 trigger for the
s3:ObjectCreated:*event type, targeting yourmyvideosbucket. - Set Permissions: Make sure your Lambda execution role has permissions to run
s3:HeadObjectands3:CopyObjecton your bucket.
This setup will automatically apply the Cache-Control metadata to every new object, no matter how it's uploaded.
内容的提问来源于stack exchange,提问作者Kien Pham

