使用 S3 的预签名 URL 时如何限制不同文件的上传?

问题描述 投票:0回答:1

我使用 @aws-sdk/client-s3 库创建预签名 URL,然后使用此 URL 将文件上传到 S3。在生成预签名 URL 时,我使用 Key 属性,其中包括文件名和内容类型。

但是,问题是当我使用预签名 URL 上传文件时,它允许我上传任何文件。我想要做的是,如果文件名和内容类型与我用于生成预签名 URL 的文件名和内容类型不匹配,则限制文件上传。

以下是代码:

async getUploadPreSignedUrl(key, bucket, expiresInSeconds = 1800)
{
    try {
        const contentType = mime.lookup(key) || undefined;
        if (!contentType) {
            throw new Error('Invalid Content Type')
        }
        const params = { Bucket: bucket, Key: key, ContentType: contentType, }; 
        const putObjectCommand = new PutObjectCommand(params); 
        console.log(params, putObjectCommand)       
        const signedUrl = await getSignedUrl(this.s3, putObjectCommand, 
        { expiresIn: expiresInSeconds, }); 
        return signedUrl;
    } 
catch (error) { 
 console.error("Error generating upload pre-signed URL:", error); throw error; }
}

我想要的是,如果我们使用不同的文件名或不同的内容类型,上传应该返回错误。

amazon-s3 pre-signed-url
1个回答
0
投票

为了确保签名的 URL 仅适用于上传其创建的文件,您必须在

conditions
中设置
getUploadPreSignedUrl
CreatePresignedPostCommand
库中有一个
@aws-sdk/client-s3
方法可以帮助解决此问题。我刚刚使用该方法重写了您的
getUploadPreSignedUrl
并合并了检查
conditions
:

const { S3Client, CreatePresignedPostCommand } = require('@aws-sdk/client-s3');

    async getUploadPreSignedUrl(key, bucket, expiresInSeconds = 1800) {
        try {
            const contentType = mime.lookup(key) || undefined;
            if (!contentType) {
                throw new Error('Invalid Content Type');
            }

            // This is where you set the conditions, eq checks for equality
            const conditions = [
                { bucket: bucket },
                ['eq', '$key', key],
                ['eq', '$Content-Type', contentType]
            ];

            const params = {
                Bucket: bucket,
                Key: key,
                Conditions: conditions,
                Expires: expiresInSeconds,
            };

            // Generate the presigned post URL using CreatePresignedPostCommand
            const command = new CreatePresignedPostCommand(params);
            const { url, fields } = await this.s3.send(command);

            return { url, fields };
        } catch (error) {
            console.error("Error generating upload pre-signed URL:", error);
            throw error;
        }
  }

如果使用此signedUrl上传任何其他文件(不同的

contentType
name
),则会抛出403 Forbidden错误。

为了在前端使用此上传方法,我添加了一个使用浏览器

fetch
API 的示例。

async function uploadFileToBucket(file, presignedUrlData) {
    const formData = new FormData();

    // Append fields from presignedUrlData.fields
    Object.entries(presignedUrlData.fields).forEach(([key, value]) => {
        formData.append(key, value);
    });

    // Append the file content here
    formData.append('file', file);

    // This uploads to the S3 bucket 
    try {
        const response = await fetch(presignedUrlData.url, {
            method: 'POST',
            body: formData,
        });

        if (!response.ok) {
            throw new Error(`Upload failed with status: ${response.status}`);
        }

        console.log("Your file uploaded successfully!");
    } catch (error) {
        console.error("Error uploading file:", error);
    }
}

我想这应该可以解决你的问题

© www.soinside.com 2019 - 2024. All rights reserved.