Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Protect Strapi uploads folder via S3 SignedUrl

uploading files from strapi to s3 works fine. I am trying to secure the files by using signed urls:

var params = {Bucket:process.env.AWS_BUCKET, Key: `${path}${file.hash}${file.ext}`, Expires: 3000};
      var secretUrl = ''
      S3.getSignedUrl('getObject', params, function (err, url) {
        console.log('Signed URL: ' + url);
        secretUrl = url
      });

      
      S3.upload(
        {
          Key: `${path}${file.hash}${file.ext}`,
          Body: Buffer.from(file.buffer, 'binary'),
          //ACL: 'public-read',
          ContentType: file.mime,
          ...customParams,
        },
        (err, data) => {
          if (err) {
            return reject(err);
          }

          // set the bucket file url
          //file.url = data.Location;
          file.url = secretUrl;
          console.log('FIle URL: ' + file.url);

          resolve();
        }
      );

file.url (secretUrl) contains the correct URL which i can use in browser to retrieve the file. But whenever reading the file form strapi admin panel no file nor tumbnail is shown. I figured out that strapi adds a parameter to the file e.g ?2304.4005 which corrupts the get of the file to AWS. Where and how do I change that behaviour

Help is appreciated

like image 718
Capsloq Avatar asked Nov 19 '25 04:11

Capsloq


1 Answers

Here is my solution to create a signed URL to secure your assets. The URL will be valid for a certain amount of time.

  1. Create a collection type with a media field, which you want to secure. In my example the collection type is called invoice and the media field is called document.

  2. Create an S3 bucket

  3. Install and configure strapi-provider-upload-aws-s3 and AWS SDK for JavaScript

  4. Customize the Strapi controller for your invoice endpoint (in this exmaple I use the core controller findOne)

const { sanitizeEntity } = require('strapi-utils');
var S3 = require('aws-sdk/clients/s3');

module.exports = {

  async findOne(ctx) {
    const { id } = ctx.params;

    const entity = await strapi.services.invoice.findOne({ id });
    // key is hashed name + file extension of your entity
    const key = entity.document.hash + entity.document.ext;

    // create signed url
    const s3 = new S3({
        endpoint: 's3.eu-central-1.amazonaws.com',   // s3.region.amazonaws.com
        accessKeyId: '...',       // your accessKeyId
        secretAccessKey: '...',   // your secretAccessKey
        Bucket: '...',         // your bucket name
        signatureVersion: 'v4',
        region: 'eu-central-1'           // your region
    });

    var params = {
        Bucket:'',   // your bucket name
        Key: key, 
        Expires: 20 // expires in 20 seconds
    };

    var url = s3.getSignedUrl('getObject', params);

    entity.document.url = url  // overwrite the url with signed url

    return sanitizeEntity(entity, { model: strapi.models.invoice });
  },

};
like image 84
baermathias Avatar answered Nov 21 '25 19:11

baermathias



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!