You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

JavaScript获取用户指定AWS S3存储桶数据遇跨域403错误

解决浏览器中调用AWS S3 listObjects时的CORS 403错误及安全问题

你的问题主要涉及两个核心点:S3存储桶的CORS策略未正确配置,以及前端代码暴露AWS密钥的严重安全风险,下面一步步帮你解决:

1. 修复CORS策略问题

你遇到的No 'Access-Control-Allow-Origin' header is present错误,说明你的S3存储桶没有配置允许当前前端环境(这里是null,应该是你直接用本地文件file://协议打开HTML)跨域访问的规则。

配置S3桶的CORS规则

  1. 登录AWS控制台,找到目标S3存储桶
  2. 切换到权限标签页,找到**跨域资源共享(CORS)**模块
  3. 编辑CORS配置,替换为以下规则(可根据实际需求调整):
[
    {
        "AllowedHeaders": ["*"],
        "AllowedMethods": ["GET", "OPTIONS"],
        "AllowedOrigins": ["*"],
        "ExposeHeaders": []
    }
]
  • AllowedOrigins:开发阶段可暂时用*允许所有来源,生产环境务必替换为你的前端实际域名(比如https://your-app.com
  • AllowedMethods:因为你调用的listObjects对应GET请求,必须包含GET和预飞行请求所需的OPTIONS
  • 保存配置后,等待1-2分钟让配置生效,再重新测试代码

2. 解决前端暴露AWS密钥的安全问题

绝对不能在前端代码里直接硬编码accessKeyIdsecretAccessKey!任何用户都能通过浏览器开发者工具看到这些密钥,一旦泄露,攻击者可以用你的密钥操作S3桶、访问其他AWS服务,造成不可估量的损失。

推荐两种安全方案:

方案一:使用Amazon Cognito生成临时凭证

通过Cognito身份池为用户生成临时AWS凭证,前端用临时凭证调用S3:

// 初始化Cognito身份池
AWS.config.region = '你的AWS区域';
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
    IdentityPoolId: '你的Cognito身份池ID',
});

// 凭证刷新后执行S3请求
AWS.config.credentials.get(function() {
    const s3 = new AWS.S3();
    var bucket = document.getElementById('bucketName').value;
    var params = { Bucket: bucket, MaxKeys: 5 };
    s3.listObjects(params, function(err, data) {
        if (err) console.log("error is : " + err);
        else {
            console.log(data.Contents);
            // 转换成你期望的JSON格式
            const formattedData = data.Contents.map(item => ({
                name: item.Key,
                size: item.Size,
                lastModified: item.LastModified
            }));
            console.log(formattedData);
        }
    });
});

同时需要在Cognito身份池的权限策略中,允许用户执行目标S3桶的listObjects操作。

方案二:通过后端代理请求

在后端(如Node.js、Python)编写接口,前端调用后端接口,由后端负责与S3交互:

  • 后端代码(Node.js示例):
const AWS = require('aws-sdk');
const express = require('express');
const app = express();

// 后端通过环境变量配置AWS密钥,禁止硬编码
AWS.config.update({
    region: '你的AWS区域',
    accessKeyId: process.env.AWS_ACCESS_KEY_ID,
    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY
});

const s3 = new AWS.S3();

app.get('/api/s3/list-bucket', async (req, res) => {
    const bucketName = req.query.bucket;
    try {
        const params = { Bucket: bucketName, MaxKeys: 5 };
        const data = await s3.listObjects(params).promise();
        res.json(data.Contents);
    } catch (err) {
        res.status(500).json({ error: err.message });
    }
});

app.listen(3000, () => console.log('后端服务运行在3000端口'));
  • 前端代码:
async function loadBucket() {
    var bucket = document.getElementById('bucketName').value;
    try {
        const response = await fetch(`http://localhost:3000/api/s3/list-bucket?bucket=${bucket}`);
        const data = await response.json();
        console.log(data);
        // 格式化数据
        const formattedData = data.map(item => ({
            name: item.Key,
            size: item.Size,
            lastModified: item.LastModified
        }));
        console.log(formattedData);
    } catch (err) {
        console.log("error is : " + err);
    }
}

这种方式将AWS密钥完全隔离在后端,避免了前端暴露的风险。

3. 调试小贴士

  • 配置CORS后仍报错时,查看浏览器网络请求面板,检查OPTIONS请求的响应头是否包含Access-Control-Allow-Origin
  • 确保S3桶的桶策略允许对应的用户/角色执行listObjects操作
  • 本地开发时,尽量用本地服务器(如http-server)打开HTML,避免file://协议的严格跨域限制

内容的提问来源于stack exchange,提问作者VARUN GARG

火山引擎 最新活动