Skip to content
Go back

Storing user uploads in Windows Azure blob storage

Edit page

On one of the mailing lists I follow, an interesting question came up: “We want to write a VSTO plugin for Outlook which copies attachments to blob storage. What’s the best way to do this? What about security?”. Shortly thereafter, an answer came around: “That can be done directly from the client. And storage credentials can be encrypted for use in your VSTO plugin.”

While that’s certainly a solution to the problem, it’s not the best. Let’s try and answer…

What’s the best way to uploads data to blob storage directly from the client?

The first solution that comes to mind is implementing the following flow: the client authenticates and uploads data to your service which then stores the upload on blob storage.

Upload data to blob storage

While that is in fact a valid solution, think about the following: you are creating an expensive layer in your application that just sits there copying data from one network connection to another. If you have to scale this solution, you will have to scale out the service layer in between. If you want redundancy, you need at least two machines for doing this simple copy operation… A better approach would be one where the client authenticates with your service and then uploads the data directly to blob storage.

Upload data to blob storage using shared access signature

This approach allows you to have a “cheap” service layer: it can even run on the free version of Windows Azure Web Sites if you have a low traffic volume. You don’t have to scale out the service layer once your number of clients grows (at least, not for the uploading scenario).But how would you handle uploading to blob storage from a security point of view…

What about security? Shared access signatures!

The first suggested answer on the mailing list was this: “(…) storage credentials can be encrypted for use in your VSTO plugin.” That’s true, but you only have 2 access keys to storage. It’s like giving the master key of your house to someone you don’t know. It’s encrypted, sure, but still, the master key is at the client and that’s a potential risk. The solution? Using a shared access signature!

Shared access signatures (SAS) allow us to separate the code that signs a request from the code that executes it. It basically is a set of query string parameters attached to a blob (or container!) URL that serves as the authentication ticket to blob storage. Of course, these parameters are signed using the real storage access key, so that no-one can change this signature without knowing the master key. And that’s the scenario we want to support…

On the service side, the place where you’ll be authenticating your user, you can create a Web API method (or ASMX or WCF or whatever you feel like) similar to this one:

Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/

—>public class UploadController : ApiController { [Authorize] public string Put(string fileName) { var account = CloudStorageAccount.DevelopmentStorageAccount; var blobClient = account.CreateCloudBlobClient(); var blobContainer = blobClient.GetContainerReference(uploads); blobContainer.CreateIfNotExists();

    var blob </span><span style="color: #000000;">=</span><span style="color: #000000;"> blobContainer.GetBlockBlobReference(</span><span style="color: #800000;">"</span><span style="color: #800000;">customer1-</span><span style="color: #800000;">"</span><span style="color: #000000;"> </span><span style="color: #000000;">+</span><span style="color: #000000;"> fileName);

    var uriBuilder </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> UriBuilder(blob.Uri);
    uriBuilder.Query </span><span style="color: #000000;">=</span><span style="color: #000000;"> blob.GetSharedAccessSignature(</span><span style="color: #0000ff;">new</span><span style="color: #000000;"> SharedAccessBlobPolicy
        {
            Permissions </span><span style="color: #000000;">=</span><span style="color: #000000;"> SharedAccessBlobPermissions.Write,
            SharedAccessStartTime </span><span style="color: #000000;">=</span><span style="color: #000000;"> DateTime.UtcNow,
            SharedAccessExpiryTime </span><span style="color: #000000;">=</span><span style="color: #000000;"> DateTime.UtcNow.AddMinutes(</span><span style="color: #800080;">5</span><span style="color: #000000;">)
        }).Substring(</span><span style="color: #800080;">1</span><span style="color: #000000;">);

    </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> uriBuilder.ToString();
}

}

This method does a couple of things:

On the client side, in our VSTO plugin, the only thing to do now is call this method with a filename. The web service will create a shared access signature to a non-existing blob and returns that to the client. The VSTO plugin can then use this signed blob URL to perform the upload:

Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/

—>Uri url = new Uri(http://…/uploads/customer1-test.txt?sv=2012-02-12&st=2012-12-18T08%3A11%3A57Z&se=2012-12-18T08%3A16%3A57Z&sr=b&sp=w&sig=Rb5sHlwRAJp7mELGBiog%2F1t0qYcdA9glaJGryFocj88%3D); var blob = new CloudBlockBlob(url); blob.Properties.ContentType = test/plain;

using (var data = new MemoryStream( Encoding.UTF8.GetBytes(Hello, world!))) { blob.UploadFromStream(data); }

Easy, secure and scalable. Enjoy!


Edit page
Share this post on:

Previous Post
Windows Azure Websites and PhpStorm
Next Post
Protecting your ASP.NET Web API using OAuth2 and the Windows Azure Access Control Service