jakeFeldman / strapi-provider-upload-azure-storage

Strapi Provider Upload Azure Storage
MIT License
75 stars 42 forks source link

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

Open daniiltkach-ms opened 4 months ago

daniiltkach-ms commented 4 months ago

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.

jakeFeldman commented 3 months ago

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

daniiltkach-ms commented 3 months ago

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));
daniiltkach-ms commented 3 months ago

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

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
          ),
        };
      },
jakeFeldman commented 3 months ago

@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