0

Related:

Amazon S3 direct file upload from client browser - private key disclosure

https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/s3-example-creating-buckets.html

In a rest endpoint:

import aws from 'aws-sdk'

export default async function handler(req, res) {
    try {
        // 1.
        const s3 = new aws.S3({
            accessKeyId: process.env.APP_AWS_ACCESS_KEY,
            secretAccessKey: process.env.APP_AWS_SECRET_KEY,
            region: process.env.APP_AWS_REGION,
        })

        // 2.
        aws.config.update({
            accessKeyId: process.env.APP_AWS_ACCESS_KEY,
            secretAccessKey: process.env.APP_AWS_SECRET_KEY,
            region: process.env.APP_AWS_REGION,
            signatureVersion: 'v4',
        })

        console.log('bucket: ' + process.env.AWS_S3_BUCKET_NAME)
        // 3.
        const post = await s3.createPresignedPost({
            Bucket: process.env.AWS_S3_BUCKET_NAME,
            Fields: {
                key: req.query.file,
            },
            Expires: 60, // seconds
            Conditions: [
                ['content-length-range', 0, 5048576], // up to 1 MB
            ],
        })

        console.log('post req: ' + JSON.stringify(post))
        // 4.
        return res.status(200).json(post)
    } catch (error) {
        console.log(error)
    }
}

The constructed url is invalid:

bucket: 'arn:aws:s3:::my-app-bucket'  # Will be used in an API route.
post req: {"url":"https://s3.eu/'arn:aws:s3:::my-app-bucket'  %23 Will be used in an API route."

Is this the right way of authenticating to aws?

Code:

 const uploadPhoto = async (e) => {
    const file = e.target.files[0];
    const filename = encodeURIComponent(file.name);
    const res = await fetch(`/api/upload-image?file=${filename}`);
    const data = await res.json();
    const formData = new FormData();

    console.log("uploadPhoto()");
    console.log("file " + JSON.stringify(file));
    console.log("filename " + filename);
    console.log("data " + JSON.stringify(data));

    // @ts-ignore
    Object.entries({ ...data.fields, file }).forEach(([key, value]) => {
      formData.append(key as string, value as string);
    });

    toast.promise(
      fetch(data.url, {
        method: "POST",
        body: formData,
      }),
      {
        loading: "Uploading...",
        success: "Upload successful",
        error: `Upload failed ${error}`,
      }
    );
  };

Logs:

uploadPhoto()
admin.tsx?6c2c:49 file {}
admin.tsx?6c2c:50 filename user.png
admin.tsx?6c2c:51 data {"url":"https://s3.eu/'arn:aws:s3:::my-app'  %23 Will be used in an API route.","fields":{"key":"user.png","bucket":"'arn:aws:s3:::my-app'  # Will be used in an API route.","X-Amz-Algorithm":"AWS4-HMAC-SHA256","X-Amz-Credential":"AKIAZMB5ZBK2LSTW23DT/20221025/EU (Frankfurt) eu-central-1/s3/aws4_request","X-Amz-Date":"20221025T133228Z",
Sebi
  • 4,262
  • 13
  • 60
  • 116
  • 1
    I wouldn't say that injecting credentials like that is the right way of authenticating it. Try always to cope with temporary security credentials when obtaining credentials. https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_use-resources.html – Victor Hugo Montes Oct 25 '22 at 11:22
  • 1
    In regards to this code you sent, which error are you getting? Can you edit your question by adding it? – Victor Hugo Montes Oct 25 '22 at 11:24

0 Answers0