Security implications of displaying files from user-provided paths - c#

Assume some intranet WebAPI endpoint like:
public class AttachmentDto
{
public String Path { get; set; }
}
public class AttachmentsApiController : ApiController
{
public void Post(AttachmentDto attachment)
{
var attachmentsStorage = new AttachmentsStorage();
attachmentsStorage.Add(attachment.Path);
}
}
where AttachmentsStorage in one or another way reads the file at attachment.Path (one or another network share) and saves the contents at some more or less publicly available and known place.
That is basically equivalent to simply
public String Post(AttachmentDto attachment)
{
return File.ReadAllText(attachment.Path);
}
That in my opinion evaluates to security vulnerability, even though the system is intranet, because any file on the server that is accessible to the used service account can be technically read.
Am I correct?
If it is so, then what can be done to mitigate this issue?
I've considered:
Pass the file contents - possible, though not desired for this particular system because of the assumed design and possible size of the files.
Prohibit any addresses that are not network shares. Something like:
private Boolean IsNetworkShareFile(String path)
{
var uri = new Uri(path);
return
uri.IsFile &&
uri.IsUnc &&
uri.IsAbsoluteUri;
}
It seems to work, but it at best prevents only local file access(though some file share can actually point to local) and doesn't restrict access to private shares.
Try impersonation/delegation - probably the best solution with authentication mode="Windows", though it will require changing account settings in Active Directory

This is an A4
What you are describing is known as an Insecure Direct Object Reference and is in the OWASP top 10.
You can guess the mitigations from the title. You can either
Secure the references, or
Use indirect object references instead
(or both)
Secure the reference
The server should validate Path, ideally against a white list.
Paths can be a little tricky to validate because they can contain escape characters. Be sure to use Path.Combine and MapPath instead of performing any path computation yourself.
Also, since this is a string that is being input into your system, always check for injection.
Use an indirect object reference
Modify the API's interface so the client submits a PathID instead of a Path, and make PathID discoverable via some other service call which lists only those specific files that the client has the right to access. If the system has per-user permissions (i.e. ACL), then bind the PathID namespace to the user session, so that one user cannot guess another user's PathIDs.

Related

How do I make this object exist within sessions?

Here's the deal: I have a site where multiple people will be sharing the same account and should each be able to be on a page that uploads files and keeps a list of the files they've uploaded that session. The controller for the file uploading page looks like
public class FileUploadController : Controller
{
// ...
private List<ThreePartKey> uploadedFiles = new List<ThreePartKey> ();
public ActionResult Index ( )
{
// ...
}
[HttpPost]
public ActionResult Index (HttpPostedFileBase file)
{
// ...
if (!errorOccured)
{
uploadedFiles.Add(new ThreePartKey { orgname = selectedOrgName, catname = selectedCatName, filename = fileNameNoExtension, fullfilepath = newFileUrlPathAndName });
}
// ...
}
and the problem is that uploadedFiles keeps getting re-initialized whenever [HttpPost] public ActionResult Index (HttpPostedFileBase file) is called, meaning the user's list of uploaded files only shows the last uploaded one. So I instead tried
private static List<ThreePartKey> uploadedFiles = new List<ThreePartKey> ();
and that screwed up everything because all the signed-in users are sharing the same list.
Is there any easy way to do what I'm trying to do?
Controllers are instantiated and destroyed on every request. If you want to persist information in a webserver it is strongly advised to use a permanent backing store such as a database.
You can use static state in ASP.NET applications (WebForms, MVC, OWIN, etc) however this is only recommended for caching for performance. It cannot be relied upon because static state is only local to the current AppDomain in the current Application Pool (w3wp.exe instance) - if your website is run in multiple pools or appdomains, or if your application is restarted (or killed due to inactivity) then the stored state is lost.
On option is to provide a 'session' code/id with each request. When user first connects to your site, they are given a session-code (I use 'code' to indicate it has nothing to do with what we would normally call 'session').
Every link has that session-code as part of the url and every post includes the session-code. Then your upload cache can be:
private static ILookup<int, ThreePartKey> uploadedFiles;
(or dictionary if you prefer)
private static IDictionary<int, IList<ThreePartKey>> uploadedFiles;
Depends on the size of the rest of your site if this is workable or not - in most cases probably not as described... but could be managed, eg use the IP address as the 'code' or if you're using AnglurJS or single page application.
As pointed out, any static/singleton cache will still be lost if the app pool is reset, eg via the inactivity timeout setting in IIS.
Another option is to persist the files in subfolders based on the user's IP address.
You've only stipulated that they all use the same login, not how the files are stored etc, so maybe this would work for you.

ASP.NET MVC singleton or static class to pass around data?

I'm creating a controller that will serve the combined/minified versions of my JavaScript and CSS. I need to somewhere along the line define which scripts/styles to be loaded.
When a request is made, for example for style.css?VersionNumberHere, it will check if the combined/minified data is already in the HttpContext.Cache, if so spit it out. Otherwise, I need to look up the definition that makes up style.css.
I created a Script/StyleBuilder (that inherits from ContentBuilder) that will store all the paths that need to be combined and then squished (so this would be the definition of style.css).
Where should I be storing these references to the "builders"? Should they be in a static class or a singleton that implements an interface so that it can be tested?
Here's the interface that the abstract class ContentBuilder implements (you can easily imagine the implementation):
public interface IContentBuilder : IEnumerable<string>
{
string Name { get; }
int Count { get; }
string[] ValidExtensions { get; }
void Add(string path);
bool ValidatePath(string path);
string GetHtmlReference(); // Spits out <script>, or <link> depending on implementation.
string Build(); // Minifies, combines etc.
}
And here is ideally what I'd like to be able to do with these:
ContentBuilderContainer.Current.Add("main.js", c => new ScriptBuilder()
{
"/path/to/test.js",
"/path/to/test2.js",
"/path/to/test3.js"
});
ContentBuilderContainer.Current.Add("style.css", c => new StyleBuilder()
{
"/path/to/style.css",
"/path/to/test.less"
});
Then to output all the HTML for all registered IContentBuilder:
ContentBuilder.Container.Current.BuildHtml();
Maybe you should check out SquishIt. Some more info on it in this blog post. We use it in production.
Attach caching attributes to your controller actions and cache by parameter like this:
[OutputCache(Duration = 7200, Location = OutputCacheLocation.Client, VaryByParam = "jsPath;ServerHost")]
[CompressFilter]
// Minifies, compresses JavaScript files and replaces tildas "~" with input serverHost address
// (for correct rewrite of paths inside JS files) and stores the response in client (browser) cache for a day
[ActionName("tildajs")]
public virtual JavaScriptResult ResolveTildasJavaScript(string jsPath, string serverHost)
...
I made the following interface:
public interface IContentBuilderContainer
{
int Count { get; }
bool Add(string name, Func<IContentBuilder> contentBuilder);
string RenderHtml();
}
And then in the implmentation of ContentBuilderContainer:
public class ContentBuilderContainer : IContentBuilderContainer
{
// Other members removed for simplicity.
#region Static Properties
/// <summary>
/// Gets or sets the current content builder container.
/// </summary>
public static IContentBuilderContainer Current
{
get;
set;
}
#endregion
#region Static Constructors
static ContentBuilderContainer()
{
ContentBuilderContainer.Current = new ContentBuilderContainer();
}
#endregion
}
This way there's a single ContentBuilderContainer living at one time.
I helped write some code that did this recently. Here's a high level overview of the solution that was implemented. Hopefully it will give you some good ideas.
Configuration: We created custom configuration elements that define a key and their a corresponding list of directories. So the key JS is linked to our /Content/Scripts folder, and CSS is linked to our /Content/Styles folder. I have seen other solutions where the configuration allowed for individual files to be listed.
Controller: The controller was set up to receive requests something along the lines of /Content/Get/JS and /Content/Get/CSS. The controller uses the configuration key and client request headers to come up with a cache key that identifies the content we want to serve: JS-MSIE-ZIP, CSS-FFX, etc. The controller then checks our cache service. If the content is not there, it gets concatenated, minified, compressed, cached and then served. Handy fallout is that the content is compressed before going into the cache instead of every time it's served.
View: In the View, the links are set up like this:
<link href="<%: Url.Action("Get", "Content", new { key = "CSS" }) %>" rel="stylesheet" type="text/css" />
Cache Service: We're using an existing cache service we have that just wraps the application cache. At some point we'll probably move that to Velocity or something similar. If the amount of CSS and JS we cache keeps growing, we'll probably change the format of the key to a proper filename and move the content to the file system. But, memory's pretty cheap, we'll see what happens.
Reasoning: (if it matters)
We did this in order to keep the JavaScript for different features in separate files in source control without having to link to all of the files individually in the HTML. Because we configure our content by directory and not individual files, we can also run a full minification during production builds to speed up the whole run time process somewhat. Yet we still get the benefit of determining which content to serve based on the client browser, and cached compressed versions.
In development, the system can be set up with a quick configuration change so that every request rebuilds the JS. The files are concatenated with file names injected in comments for easy searching, but the content is not minified and nothing is cached anywhere. This allows us to change, test and debug the JS without recompiling the application.
Couldn't quite find all these features in a package out there so we spent a couple of days and built it. Admittedly some features were just for fun, but that's why we like doing what we do. =)

CDN for Images in ASP.NET

I am in the process of moving all of the images in my web application over to a CDN but I want to easily be able to switch the CDN on or off without having to hard code the path to the images.
My first thought was to add an HttpHandler for image extensions that depending whether a variable in the web.config (something like ) will serve the image from the server or from the CDN. But after giving this a little though I think I've essentially ruled this out as it will cause ASP.NET to handle the request for every single image, thus adding overhead, and it might actually completely mitigate the benefits of using a CDN.
An alternative approach is, since all of my pages inherit from a base page class, I could create a function in the base class that determines what path to serve the files from based off the web.config variable. I would then do something like this in the markup:
<img src='<%= GetImagePath()/image.png' />
I think this is probably what I'll have to end up doing, but it seems a little clunky to me. I also envision problems with the old .NET error of not being able to modify the control collection because of the "<%=" though the "<%#" solution will probably work.
Any thoughts or ideas on how to implement this?
You've dismissed writing an HttpHandler based on an assumption of pre-optimization. I would revisit this and definitely write a simple HttpHandler and test it out. You might find that your Page method solution might even be slower, especially if you get the ASP preprocessor involved.
HttpHandlers are pretty close to the metal - it's a miniscule amount of overhead for IIS to hand the request to ASP.Net. It would be a more elegant solution than what you're proposing, and probably more scalable and I'm willing to bet - faster.
Have you considered a slightly simpler approach?
If your pages all inherit from a base class, you could expose a property on that which contains the prepend URL to your CDN (or, to your local server if you want to switch the CDN off). It is then a trivial matter of storing the prepend URL in the web.config:
public string PrependURLPath() {
get { return ConfigurationManager.AppSettings["ImagePrependURL"].ToString(); }
}
In your <appSettings/> element, you can simply choose what the prepend URL would be, eg:
http://my.cdn.com/user/
or:
http://my.own.server.com/images/
Pretty simple!
You would then be able to code your image refernces as per your example, but calling your base page property to expose the desired path:
<img src='<%= this.BasePage.PrependURLPath() + [YourImagePath.png] %>'/>
I agree that setting the image source through the inline call is messy, but you could probably do as someone else has suggested and then iterate through the image controls on your page, changing the prepend URL as you go.
Even if your pages currently only inherit from System.Web.UI.Page, it's a simple matter to create your own base class which inherits System.Web.Page, then do a find/replace in your solution on all remaining pages.
Hope this helps.
weighing in pretty late here, but i've been looking for a similar solution myself. searched google to sanity check what i had done. didn't consider the HttpHandler approach, what i did was simply extend the ASP.net Image control:
public class Img : Image
{
public Img()
{
RelativePath = false;
}
public bool RelativePath { get; set; }
public override string ImageUrl
{
get
{
if (RelativePath)
return base.ImageUrl;
return "http://some.configurable-value.com" + base.ImageUrl;
}
set { base.ImageUrl = value; }
}
}
it's rough and ready, but it works :) obviously it should rely on some configurable value rather than a string literal, but that's not a big change
If you display your images using tags you could create a control adapter, these allow you to alter the way .net controls render or universally alter them something like this should do the trick:
using System.Web.UI.WebControls.Adapters;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace ExampleCode
{
public class ImageAdapter : WebControlAdapter
{
private bool UseCdn
{
get { return true; } // Get value from config or anywhere else
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
Image image = (Image)Control;
if (UseCdn)
{
// If using relative urls for images may need to handle ~
image.ImageUrl = String.Format("{0}/{1}", "CDN URL", image.ImageUrl);
}
}
}
}
Then add a browser file to the App_Browsers folder in your web project like below:
<browsers>
<browser refID="Default">
<controlAdapters>
<adapter
controlType="System.Web.UI.WebControls.Image"
adapterType="ExampleCode.ImageAdapter"
/>
</controlAdapters>
</browser>
</browsers>
you could loop all controls and change the images url in the prerender event on your base class...
The good thing about the HTTP Handler approach is that it's quite re-usable and configurable: you can identify img paths to handle based on location - assuming the structure they're in helps this.
The possible drawback is that image file extensions (.jpg, .png, etc) aren't automatically passed on to the asp.net pipe-line; you can easily config IIS to do so - but you need to have a certain level of contriol over IIS - so it might not be an option if you're on a shared hosting environment.
I will go for #Rhys approach for image control.
Most of the time, I try to use background image css than using image control.
After that I upload both css and images together to the cloud and working fine for relative path.
Doesn't look like there has been an accepted answer yet so here is my suggestion. I had similar problems dealing with modifying URL's transparently (to a different end, but I thought about using it for CDN support as well).
This is an old filter / module but it worked well for my needs with a little tuning: http://www.paraesthesia.com/archive/2007/12/14/urlabsolutifiermodule---convert-urls-in-asp.net-output-to-absolute.aspx
What you can do is make a response filter and hook it with an httpmodule (as this absolutifier does). If you use this module + response filter you could probably achieve what you need by modifying the source for it to replace the hostname / prefix all urls to use the CDN.
I had to solve your problem and another one, that is I do not want to take resources from the CDN during development but only when the website is deployed on the production server.
To solve this I developed an ExpressionBuilder that prepends the CDN URL only in production.
<asp:Image ImageUrl="<%$ CdnUrl:/images/myimage.png %>" runat="server" />
In previous code the CDN URL will be prepended only in production.
namespace IdeaR.Web.Compilation
{
[ExpressionPrefix("CdnUrl")]
public class CdnUrlExpressionBuilder : ExpressionBuilder
{
public static object GetCdnUrl(string expression, Type target, string entry)
{
var retvalue = expression;
var productionUri = new Uri("http://www.myproductionurl.com",
UriKind.Absolute);
var currentUri = HttpContext.Current.Request.Url;
var cdnUrl = "http://cdn.mycdn.com";
// If this is a production website URL
if (currentUri.Scheme == productionUri.Scheme &&
currentUri.Host == productionUri.Host)
retvalue = cdnUrl + expression;
return retvalue;
}
public override CodeExpression GetCodeExpression(BoundPropertyEntry entry,
object parsedData, ExpressionBuilderContext context)
{
var componentType = entry.DeclaringType;
var expressionArray = new CodeExpression[3]
{
new CodePrimitiveExpression(entry.Expression.Trim()),
new CodeTypeOfExpression(componentType),
new CodePrimitiveExpression(entry.Name)
};
var descriptor = TypeDescriptor.GetProperties(componentType)
[entry.PropertyInfo.Name];
return new CodeCastExpression(descriptor.PropertyType,
new CodeMethodInvokeExpression(
new CodeTypeReferenceExpression(GetType()),
"GetCdnUrl", expressionArray));
}
}
}
For more information I wrote an article on this
How to use a CDN in production but not during development

Creating a protected link

Is there a way to create a protected download link which is random, expiry, requires a password and pointing to a specific file in C# that is associated with IIS 7.0?
Several random links can link to the same file.
Built-in codes or perhaps 3rd party libraries?
For example, http://www.example.com/<some random gibberish>/<md5 of file>/file.jpg
One way to do this would be to use GUIDs. GUIDs are designed not to collide, and that design also leads to a difficulty in guessing valid GUIDs. I'm sure someone out there will tell me that this is not very secure! Well, you are also protecting with a password. It is pretty easy to generate a GUID in C#.
I guess what you need is firstly a way of ingesting the files that you want to protect in this way, and secondly a handler that will respond to requests in a given path and inspect the GUID in the path to determine if it's valid.
You'd then need a database back end to maintain lists of GUIDs corresponding to URLs, the password (preferably crypted) and the expiry date. The handler would inspect the entry for the requested URL/GUID to see if the link has expired, then prompt the user (could do this via a web form easily enough) for the password and check this against the crypted password stored in the database.
To generate a GUID, you want:
System.Guid.NewGuid().ToString()
To create a module that is called before every request (for IIS7) you can add an entry to your web.config like so:
<modules>
<add name="MyDownloadModule" type="Example.MyDownloadModule, Example"/>
</modules>
where MyDownloadModule is the class containing your handler, in the namespace Example.
Inside that class you then need to implement the IHttpModule interface, in particular overriding the methods:
public string ModuleName {
get { return "MyDownloadModule"; }
}
public void Init(HttpApplication app) {
// Add an event handle which is called at the beginning of each request
app.BeginRequest += new EventHandler(this.AppBeginRequest);
}
//
// Our event handler for the BeginRequest event
//
private void AppBeginRequest(Object source, EventArgs e)
{
HttpRequest request = app.Context.Request;
//
// Is this a file download?
//
if (request.AppRelativeCurrentExecutionFilePath == "~/downloads") // or whatever
{
// this is where you work your GUID inspecting magic
}
}
Going about it this way means this will be called for every request to the server, which may not be what you want.
You could always create your own HttpHandler, and then implement your own proprietary expiration/validation code.
Something like:
http://www.example.com/download?token={your_token}
It would then be a trivial matter to have the handler intercept the request and grab the file from disk, and deliver it to the client if the ?token querystring value is correct.
For more information on the IHttpHandler interface, see MSDN http://msdn.microsoft.com/en-us/library/system.web.ihttphandler.aspx

Easiest way to implement this dynamic login scheme for asp.net

I currently have a site where different users can login, and depending on their sub domain, are presented with different data from different databases. I am overriding the SqlMembershipProvider to use a "temp" connection string, that I dynamically set during the Initialize Method, per this post's instructions:
http://forums.asp.net/p/997608/2209437.aspx
public override void Initialize(string name, NameValueCollection config)
{
// intercept the setting of the connection string so that we can set it ourselves...
string specifiedConnectionString = config["connectionStringName"];
ConnectionStringSettings connectionString = ConfigurationManager.ConnectionStrings[specifiedConnectionString];
var fi = typeof(ConfigurationElement).GetField("_bReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);
fi.SetValue(connectionString, false);
connectionString.ConnectionString = WakeflyClientHelper.GetClientConnectionStringByCurrentSubdomain();
config["connectionStringName"] = connectionString.Name;
// Pass doctored config to base classes
base.Initialize(name, config);
}
The problem is that the SqlMembershipProvider class seems "static" in that when multiple users connect from different sub domains, they end up seeing the User Accounts from ONE of the databases, not each of their own. It looks like the Initialize is called by the application, and not on a per request basis.
So my question to you is... What would be the easiest way to implement a solution to this?
I have not written a custom provider before, so I'm not sure how that works, or what the limitations are. And if I write it myself, there is always the possibility of security holes if I overlook something (not to mention the time it will take). Any ideas?
Update 1:
I could have a single database, however, the user's within a given sub domain need the ability to add/edit/delete user's within their own sub domain, without seeing other sub domains' users. Would that be possible under this scheme?
The code for the SQLMembershipProvider is provided here. You could extend/change what you think is necessary by adding the project to your solution and changing the namespace references in web.config.
I have done exactly this using a single membership database to handle all the logins, and then hook them up to the appropriate database depending on the domain in which they logged in.

Categories