Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Azure blob storage security options in MVC

I am working on a solution where a small number of authenticated users should have full access to a set of Azure Blob Storage containers. I have currently implemented a system with public access, and wonder if I need to complicate the system further, or if this system would be sufficiently secure. I have looked briefly into how Shared Access Signatures (SAS) works, but I am not sure if this really is necessary, and therefore ask for your insight. The goal is to allow only authenticated users to have full access to the blob containers and their content.

The current system sets permissions in the following manner (C#, MVC):

// Retrieve a reference to my image container 
myContainer = blobClient.GetContainerReference("myimagescontainer");

// Create the container if it doesn't already exist
if (myContainer.CreateIfNotExists())
{
    // Configure container for public access
    var permissions = myContainer.GetPermissions();
    permissions.PublicAccess = BlobContainerPublicAccessType.Container;
    myContainer.SetPermissions(permissions);
}

As a result, all blobs are fully accessible as long as you have the complete URL, but it does not seem to be possible to list the blobs in the container directly through the URL:

// This URL allows you to view one single image directly:
'https://mystorageaccount.blob.core.windows.net/mycontainer/mycontainer/image_ea644f08-3263-4a7f-9be7-bc42efbf8939.jpg'

// These URLs appear to return to nothing but an error page:
'https://mystorageaccount.blob.core.windows.net/mycontainer/mycontainer/'
'https://mystorageaccount.blob.core.windows.net/mycontainer/'
'https://mystorageaccount.blob.core.windows.net/'

I do not find it an issue that authenticated users share complete URLs, allowing public access to a single image; however, no one but the authenticated users should be able to list, browse or access the containers directly to retrieve other images.

My question then becomes whether I should secure the system further, for instance using SAS, when it right now appears to work as intended, or leave the system as-is. You might understand that I would like to not complicate the system if not strictly needed. Thanks!

The solution I ended up using has been given below :)

like image 440
Tormod Haugene Avatar asked Jul 15 '14 10:07

Tormod Haugene


People also ask

What are good recommendations for securing files in BLOB storage?

Microsoft recommends using Azure AD to authorize requests to Azure Storage. However, if you must use Shared Key authorization, then secure your account keys with Azure Key Vault. You can retrieve the keys from the key vault at runtime, instead of saving them with your application.


2 Answers

I use Ognyan Dimitrov's "Approach 2" to serve small PDFs stored in a private blob container ("No public read access") inside a browser window like this:

public ActionResult ShowPdf()
{
    string fileName = "fileName.pdf";

    var storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString"));
    var blobClient = storageAccount.CreateCloudBlobClient();
    var container = blobClient.GetContainerReference("containerName");
    var blockBlob = container.GetBlockBlobReference(fileName);

    Response.AppendHeader("Content-Disposition", "inline; filename=" + fileName);
    return File(blockBlob.DownloadByteArray(), "application/pdf");
}

with config file

<configuration>
    <appSettings>
        <add key="StorageConnectionString" value="DefaultEndpointsProtocol=https;AccountName=account-name;AccountKey=account-key" />
    </appSettings>
</configuration>

...which works perfect for me!

like image 76
Géza Avatar answered Sep 22 '22 05:09

Géza


So, here is what I ended up doing. Thanks to Neil and Ognyan for getting me there.

It works as following:

  • All images are private, and cannot be viewed at all without having a valid SAS
  • Adding, deletion and modification of blobs are made within the controller itself, all privately. No SAS or additional procedures are needed for these tasks.
  • When an image is to be displayed to the user (either anonymously or authenticated), a function generates an SAS with a fast expiry is that merely allows the browser to download the image (or blob), upon page generation and refresh, but not copy/paste a useful URL to the outside.

I first explicitly set the container permissions to Private (this is also the default setting, according to Ognyan):

// Connect to storage account
...

// Retrieve reference to a container. 
myContainer= blobClient.GetContainerReference("mycontainer");

// Create the container if it doesn't already exist.
if (myContainer.CreateIfNotExists())
{
    // Explicitly configure container for private access
    var permissions = myContainer.GetPermissions();
    permissions.PublicAccess = BlobContainerPublicAccessType.Off;
    myContainer.SetPermissions(permissions);   
}

Then later, when wanting to display the image, I added an SAS string to the original storage path of the blob:

public string GetBlobPathWithSas(string myBlobName)
{
    // Get container reference
    ...

    // Get the blob, in my case an image
    CloudBlockBlob blob = myContainer.GetBlockBlobReference(myBlobName);        

    // Generate a Shared Access Signature that expires after 1 minute, with Read and List access 
    // (A shorter expiry might be feasible for small files, while larger files might need a 
    // longer access period)
    string sas = myContainer.GetSharedAccessSignature(new SharedAccessBlobPolicy()
    {
        SharedAccessExpiryTime = DateTime.UtcNow.AddMinutes(1),
        Permissions = SharedAccessBlobPermissions.Read | SharedAccessBlobPermissions.List
    });
    return (blob.Uri.ToString() + sas).ToString();
}

I then called the GetBlobPathWithSas()-function from within the razor view, so that each page refresh would give a valid path+sas for displaying the image:

<img src="@GetPathWithSas("myImage")" />

In general, I found this reference useful:

http://msdn.microsoft.com/en-us/library/ee758387.aspx

Hope that helps someone!

like image 21
Tormod Haugene Avatar answered Sep 22 '22 05:09

Tormod Haugene