strapi-provider-upload-azure-storage icon indicating copy to clipboard operation
strapi-provider-upload-azure-storage copied to clipboard

[Question] Why SaSToken is presented in every image url?

Open daniiltkach-ms opened this issue 1 year ago • 4 comments

Hello guys! First of all thank you for amazing work, the plugin is so useful.

Overview

Once image (media) is loaded into the strapi, it can be returned by requesting some data which is using that image. In the result I can see the SaS token which was passed initially into the plugin setup.

image

Question

Was it done intentionally or I did something wrong in the setup ?

Why I am asking? If I get correctly, It is pretty easy to steal this token in this implementioan and get an CRUD access to the blob storage.

daniiltkach-ms avatar Jun 27 '24 11:06 daniiltkach-ms

This is intentional. Following the Azure blob storage docs. We use an anon client when the sas token is present in the service url

example here: https://github.com/Azure/azure-sdk-for-js/blob/7e0cdab9146df801c3111e1d93b35aafd471084b/sdk/storage/storage-blob/samples/javascript/anonymousCred.js#L18C1-L26

jakeFeldman avatar Jun 28 '24 17:06 jakeFeldman

ah i see @jakeFeldman actually it can create a security issue for people who use it then

const { BlobServiceClient } = require("@azure/storage-blob");

async function main() {
  try {
    const sas = ""; // SAS TOKEN which can be token from url
    const account = ""; // account name
    const containerName = ""; // name

    const blobServiceClient = new BlobServiceClient(
      `https://${account}.blob.core.windows.net?${sas}`
    );

    const containerClient = blobServiceClient.getContainerClient(containerName);

    const blobName = "assets/image.png";

    const blockBlobClient = containerClient.getBlockBlobClient(blobName);
    const content = "Hello world!";

    // Upload new content to the blob (this will overwrite existing content)
    const uploadBlobResponse = await blockBlobClient.upload(
      content,
      Buffer.byteLength(content)
    );
    console.log(
      `Upload block blob ${blobName} successfully`,
      uploadBlobResponse.requestId
    );
  } catch (e) {
    console.log(e);
  }
}

main()
  .then(() => console.log("Done"))
  .catch((ex) => console.log(ex.message));

ghost avatar Jul 03 '24 08:07 ghost

it seems to me that plugin should work at least with two keys:

  • Internal token for crud;
  • Public token for reading;

Some possible solution:

      async isPrivate() {
        return true;
      },
      async getSignedUrl(file) {
        return {
          url: file.url.replace(
            process.env.STORAGE_ACCOUNT_SAS_TOKEN,
            process.env.STORAGE_ACCOUNT_SAS_READ_TOKEN
          ),
        };
      },

ghost avatar Jul 03 '24 09:07 ghost

@daniiltkach-ms Thanks for flagging. At this time, I'm unable to work on this. I'm open to a PR if this is something you want to take on

jakeFeldman avatar Jul 09 '24 05:07 jakeFeldman

I think this is a big security risk. We are using SAS Token approach to get plugin authenticated. And we are seeing same token appended in url of the uploaded file which has risk of being exposed. Luckily I catched this on my end early as this lead to SQL error as the url including SAS token exceeds the default url field max size of 255 chars.

kemaldaggen avatar Feb 23 '25 14:02 kemaldaggen