Skip to content

Instantly share code, notes, and snippets.

@devlead
Created July 20, 2013 22:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save devlead/6046575 to your computer and use it in GitHub Desktop.
Save devlead/6046575 to your computer and use it in GitHub Desktop.
Had some twitter discussions with Filip Ekberg ( @fekberg ) about a blog post he wrote (http://blog.filipekberg.se/2013/07/12/are-you-serving-files-insecurely-in-asp-net/) I didn't agrree 100% with his post and some times 140 chars isn't enough to make you point, so toke 10 minutes before bed to write an quick code example and comment more detai…
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.Caching;
using System.Web.Mvc;
using Microsoft.AspNet.Identity;
using FileDownloadSecurityIdeas.Models;
namespace FileDownloadSecurityIdeas.Controllers
{
[Authorize]
public class InvoiceController : Controller
{
//Generate some simple fake data
private static readonly string AppDataPath = System.Web.HttpContext.Current.Server.MapPath("~/App_Data");
private static readonly IDictionary<long,Invoice> Invoices = Enumerable.Range(
1,
10
).ToDictionary(
key => (long)key,
value =>
{
var publicId = Guid.NewGuid()
.ToByteArray()
.Aggregate(
DateTime.Now.Ticks,
(prev, cur) => prev - cur
)
.ToString(CultureInfo.InvariantCulture);
return new Invoice
{
Id = value,
PublicId = publicId,
FileName = string.Concat(
publicId,
".pdf"
),
PhysicalPath = Path.Combine(
AppDataPath,
"TOP_SECRET_PDF.pdf"
)
};
}
);
//Inproc memory cache for demo purposes, could be azure cache, redis, session, sql etc.
private static readonly MemoryCache UserFileCache = new MemoryCache("InvoiceUserFileCache");
public ActionResult Index()
{
var model = LoadUserInvoices(
User.Identity.GetUserId(),
Request.UserAgent,
Request.UserHostAddress
);
return View(model);
}
public ActionResult Download(string id)
{
Invoice invoice;
if (!TryGetInvoice(
id,
User.Identity.GetUserId(),
Request.UserAgent,
Request.UserHostAddress,
out invoice
)
)
return HttpNotFound();
return File(
invoice.PhysicalPath,
"application/pdf",
invoice.FileName
);
}
private static bool TryGetInvoice(
string id,
string userId,
string userAgent,
string userHostAddress,
out Invoice invoice
)
{
var cacheKey = GetCacheKey(
userId,
userAgent,
userHostAddress,
id
);
var invoiceId = (UserFileCache.Contains(cacheKey))
? UserFileCache.Get(cacheKey) as long?
: null;
return TryLoadInvoiceById(invoiceId, out invoice);
}
private static bool TryLoadInvoiceById(long? invoiceId, out Invoice invoice)
{
invoice = null;
return (
invoiceId.HasValue &&
Invoices.TryGetValue(invoiceId.Value, out invoice) &&
invoice != null &&
!string.IsNullOrWhiteSpace(invoice.PhysicalPath) &&
!string.IsNullOrWhiteSpace(invoice.FileName) &&
System.IO.File.Exists(invoice.PhysicalPath)
);
}
private static KeyValuePair<string, Invoice>[] LoadUserInvoices(
string userId,
string ip,
string agent
)
{
var model = Invoices.ToDictionary(
key =>
{
var tempId = Guid.NewGuid().ToString();
var cacheKey = GetCacheKey(userId, ip, agent, tempId);
UserFileCache.AddOrGetExisting(
cacheKey,
key.Key,
DateTimeOffset.Now.AddHours(0.5)
);
return tempId;
},
value=>value.Value
).ToArray();
return model;
}
private static string GetCacheKey(
string userId,
string ip,
string agent,
string tempId
)
{
var cacheKey = string.Concat(
userId,
"%%",
tempId,
"%%",
ip,
"%%",
agent
);
return cacheKey;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment