ASP.Net Core static file security (images specifically) - asp.net

I have an issue that seems like a very common requirement, but I'm unable to find any help. Let's say I have an authenticated user uploading private photos to non browsable folder on my server. Each user has their own folder in a large file store, like...
/FileStore/{UserId}/Photos/my_cute_cat.jpg
The file is uploaded and I save a thumbnail of the photo like...
/FileStore/{UserId}/Photos/Thumbs/my_cute_cat_thumb.jpg
That user wants to download their photo. No problem...
User sends a request to download
I authorize the user and make sure they own that particular photo
I serve the file
I need display the thumbnail in a plain old img tag on the user's dashboard. The /Thumbs/ folder is not set up to serve static images. I don't want the /thumbs/ folder to be able to serve static images because they should only be visible to authorized users. What am I supposed to do?

If its just a small thumb nail, consider using embedded base64 image with more details here:
How to display Base64 images in HTML?
You can pass base64 down to the View by encoding the file into a base 64 format as a string explained here:
http://www.devcurry.com/2009/01/convert-string-to-base64-and-base64-to.html
Using this approach or even using a FileActionResult to serve the file through a controller has the big disadvantage of not being able to use a CDN to deliver the cached content. What you can do to help with this is still serve the images statically but give them obscenely long random names which is unguessable. When someone requests the image from you, then you simply provide them with the unguessable url.

First and foremost, if a static file should not be available to the whole world, then your web server should not serve the directory it is in at all. Nothing else will do on that front. If the directory is served, then the image can leak.
That then presents the problem of how to allow the user to access it. The simple answer there is that you need an authorized action that returns the image(s). Basically, that's going to look something like:
[Authorize]
public async IActionResult Image(string image)
{
var file = $"/FileStore/{User.Identity.GetUserId()}/Photos/{image}";
if (!File.Exists(file))
return NotFound();
return File(file);
}
Now, obviously, I don't know about your "FileStore", so the exact code here may need to change. The general idea is that you simply see if this file exists under the user's directory. If it does, they can have it. If not, they don't own it. You also should probably add in a bit more security, such as restricting the image param to only image types, so someone can't try to pull just any arbitrary file. They'd still have to somehow manage to get some aberrant file there, in the first place, but just in case it's better to not take chances.
The return methodology may need to change as well. Right now, I'm assuming a file on the filesystem of the server, so I just return a FileResult with the path. If you're pulling it from some sort of storage account in Azure, AWS, etc. then you'd use HttpClient to make the request, and then you should stream the response from that directly to a FileStreamResult.

I've not tested on linux, but if you make a folder where you have you pictures, you can actually just create a controller method that returns a file. Now, even if you are using a view served from another method, you can still call this file method from this razor view and display the image.
in controller called App I serve the image from a folder called Documents:
public IActionResult File(string id)
{
if (String.IsNullOrEmpty(id))
{
return PhysicalFile(Path.Combine(_env.ContentRootPath, "Documents", "Wrong.png"), "image/jpg");
}
return PhysicalFile(Path.Combine(_env.ContentRootPath, "Documents", id), "image/jpg");
}
in razor (using a bit bootstrap):
<img src="~/App/File/#profilePicture" class="img-fluid" />
use the location of your method that serves the file.

Related

Generate Static HTML Pages to replace dynamic pages

For one project, we've to generate static .html pages, which are gonna to be published on the same server to serve to millions of visitors.
We've to automate the creation of those files from a c# code, which takes data from a SQL Server database.
The project is already developed using C# asp.net MVC3, and we need to store the dynamically generated pages in .html on the same url to be served to visitors.
I was wondering how to use asp.net MVC3/Razor to generate those .html pages?
I don't want/need to use web caching, for a lot of reasons(load(millions of pages loaded every day), these static pages will be cached on CDN network to further serve super fast without original server going into picture, number of pages are really too many (caching will only help me if I've the same pages a lot of time, but I will have more than million pages visited very frequently, so I will have to generate them often.)
So I really search something to generate HTML pages.
Any idea how to do this...
To start with, make sure your routes all produce urls that can be duplicated as static html files. So that your calls to Html.ActionLink will produce urls you can use.
Generate your whole site as if you are using it directly, and then let it be cached externally.
You could use something like wget on Linux to grab the whole html tree of the site, and put those up along with the content files; css, images, javascript, etc.
Then redownload the site when there are changes.
In my company we've done something similar. We have a separate program that goes trhough a list of urls, sends a http-request against them. Saves the result and copies it out to the web servers. This way we only have one web server with asp-code on it internally on the network and the servers on the internet has static copies of the dynamic pages. And we get some great performance out of it.
In order for you to get the list of urls you would probably have to create a special view/controller that queries the database for the keys that can be used to query the info you want. So if you have for example a site that shows hamburgers, your list view that creates the urls might query your burger-table and create a bunch of /myburger?name=Wopper type urls. Then your batch-program reads those urls and as described before, does a http-request and saves the result etc.
If you want to generate html based on the mvc views and models, you could use the Razor.
I have used it to generate email templates, where we have used the Razor to inject the model into a view. You could generate the html from the views and write them into static html files if that fits your purpose.
Refer Razor Engine from NuGet, And you could use it like
var html = Razor.Parse(templateView, model);
If you want more customization on it, May be this tutorial could help you.
http://www.west-wind.com/weblog/posts/2012/May/30/Rendering-ASPNET-MVC-Views-to-String
I always use my own email generating method instead of MvcMailer.
First, you should generate a string from your view or partial, then add/remove some html tags, such as <html> etc, if you need... Next write this string into a file, save it as a .html file to your path.
public static string HTMLToString(ControllerContext context, string viewName, object model)
{
if (string.IsNullOrEmpty(viewName))
viewName = context.RouteData.GetRequiredString("action");
var viewData = new ViewDataDictionary(model);
using (var sw = new StringWriter())
{
var viewResult = ViewEngines.Engines.FindPartialView(context, viewName);
var viewContext = new ViewContext(context, viewResult.View, viewData, new TempDataDictionary(), sw);
viewResult.View.Render(viewContext, sw);
return sw.GetStringBuilder().ToString();
}
}

aspx, response.write, image and link referencing

I've spent a while trying to find out whether what I want is possible.
I have 3 websites on different domains. Two are in English, one in French. We have one page in english, one in french which are identical apart from the text. These pages and relevant images (we'll call common content) are stored on a separate domain (reasons beyond my control) and use response-writefile to insert the content into the two english pages.
Got all that working fine. However, the images in these common pages have a path relative to domain on which they are stored, which means when the pages are written into the main pages, the images dont show. I understand why and can get around it by putting in the full path of the image.
I would prefer not to go through every single page changing the image path, is there any way of the server knowing or being told that the image is relative to the common content and not the rendered page?
I wouldn't have thought so, but it would save my day if there was!
Further explanation:
Relative path of image:
abc.png
Path of common content file:
http://domain1.com/CommonContent/123.html
Code in final pages (domain2.com/english.html):
<% Response.WriteFile("/CommonContent/123.html"); %>
Rendered path of image (what I don't want):
http://domain2.com/abd.png
Ideal path of image in rendered page: ie, what I want to happen:
http://domain1.com/CommonContent/abd.png
what you can do is use WebClient class to get the page content
String URI = "http://domain1.com/CommonContent/123.html";
WebClient webClient = new WebClient();
Stream stream = webClient.OpenRead(URI);
String request = reader.ReadToEnd();
then you perform a string replace, here I'm not sure what can match, maybe something like this can match:
request.Replace("<src=", "<src=http://domain1.com/CommonContent/")
then you render this string to the browser.
You can make Application Settings having the path for each domain on each application, and then maybe add a function that will be in charge of writing the full path of the pictures. Also you can make an HTTP Module to address this issue as well as a Generic Handler that will receive all requests for images and load them from different domains/applications.
Good luck!

Generating etags for images in asp.net?

On my site, users can upload images that are displayed publicly. When the user uploads a new image, it overwrites one of their old images.
Because the images can be large, I want them to be cached. However, when the user uploads a new image, the old cached images should not be used.
The source of the dynamic images looks like this:
userImage.ashx?id=f488b864-0a0b-46d9-af4a-a43cd0dcf751&type=micrositePhoto
So I can inject headers into the response in the .ashx file if I need to.
I've been told to use etags for this purpose, but I don't know how to do this in asp.net. The .js and .css files on my site already have etags, but I don't know what is generating them. Also, any in-built systems to generate etags will probably not understand how my .ashx file works.
How do I generate etags for my site, and make it so that they work as they are supposed to?
Looks to me that you should be able to do, for example:
Response.AddHeader("ETag","\"" + Guid.NewGuid().ToString() + "\"");
ETags must be enclosed inside "
NOTE Obviously, once an ETag is returned with an image it needs to be the same on subsequent requests. My code above was just a proof of concept. :)
Edit: Yep, just tested and confirmed using Firebug that the Response headers do contain the Guid that I created.

How do i prevent direct linking to a few pdf files?

I'm working on a website where I need to prevent the direct linking to a few pdf files. I'm using ASP.net 2.0. Is there an easy way in code to do this? or some simple IIS setting?
Right now i'm just using a standard anchor tag to link to the files. i can validate the user on the page containing the anchor tag but that still doesn't stop the user from nabbing the url and passing it on to someone else.
Create an HttpHandler to process all requests for .pdf. Since ASP.Net doesn't process PDF files out of the box, the HttpHandler will intervene and the web.config tell IIS to do so.
The Code
namespace YourNameSpace
{
public class HttpHandlerClassName: IHttpHandler
{
public bool IsReusable
{
//We dont want this class to be reused simply       
//because we dont want other requests to wait and lie pending       
//suggests that an instance of this class cannot
//be reused to serve more than one request.
get { return false; }
}
public void ProcessRequest(HttpContext context)
{       
string MyReferrer = context.Request.UrlReferrer.ToString();
//do some regex to determine if the request is originating from
//your site.
//Put logic for the behavior your want for the outcome of your
//RegEx match here
}
}
}
web.config
<system.web>
<httpHandlers>
<add verb="*" path="*.pdf" type="YourNameSpace.HttpHandlerClassName,YourAssemblyName"/>
</httpHandlers>
</system.web>
I've solved this in the past by using a file-fetcher asp page and streaming the bytes of the desired file, using the correct content-type in the header. Roughly:
Create page fetchfile.aspx
Sample URL: yoursite/fetchfile.aspx?n=pdfname.pdf
In fetchfile:
- Verify user is permitted to access file.
- Check chosen directory for presence of file from query string.
- Set content-type appropriately for file type.
- Open the file and stream all bytes of it to the client.
- Close the file and end the response.
Do not send anything in the response except the bytes of the file. If an error occurs, either redirect or return error html with the content-type set correctly.
The last time I did this I was serving up images, so I found a suitable free library and wrote my error message into a new custom image that could then display. For fun, you can use this technique to serve up content that is unexpected when anyone steals your bandwidth by hot-linking like this:
Create a blacklist with unwanted referrer names, in a database table or text file.
When a request for a file comes in, if the user is not allowed, check if the referrer is in the blacklist, and if not, let the file be read.
On a regular basis, check the referring pages and decide a suitable pdf to return to punish that site.
Add the content you want to return to your blacklist for each referrer, and when the referrer IS in the blacklist, then return the alternate diddled content.
This is a great way to make people REALLY unlikely to steal your stuff. Their experience looks like this:
They find some nice content they want to "borrow."
They post it on their site and it works just fine.
The next day you see their action and add them to the blacklist table but make it so anyone trying to obtain the content instead gets a nice little message of some sort: "example.com is STEALING this content from the owners at somecoolsite.com. Please let them know that you are displeased with their actions."
You have a good laugh.
This can be especially wonderful if the content being stolen is an image. Embarrassments galore are in store for bandwidth thieves!
Some extra clever IP-address and time comparison could possibly make you show the correct content to the actual perpetrator but the wrong content to any of his site visitors... evil and delicious.
Place the files in your App_Data folder and serve them using an HttpHandler. Inside the handler you can check the Session.IsNewSession property to see if the request is coming from outside your website. But you'd probably want to include some kind of authentication and validation inside the handler as well.
Put the PDF files in a directory. Use .htaccess and or robots.text.

Is it possible to call a servlet from css?

I'm trying to move all the images stored in web application folder to a database. And calling them with a servlet. Is it possible to call a servlet from my css ?? or is there any way to call a remotely stored image file from css??
I tried to call a servlet method from CSS.But couldn't succeed. Is it possible to call a method like this?
background-image: url(servlet/com.abc.servlet.GetImage?name=home&GetImage('abc','123'));
Yes. As long as the images have urls, you can use it in your css.
For example:
background-image:url('/getimage.ashx?id=3');
You can even go a step further an reroute their urls - you can even use the same urls you have today, but having your server handle the request and loading files from the database.
Another tip: make sure you set the right headers. You want to use the correct content type, and probably want the images cached properly on the client side.
Yes. A CSS rule that specifies an image can contain any kind of URL that the browser can parse and fetch:
body {
background-image:
url(http://www.domain.com/servlets/my_servlet.jsp?argument=value)
}
It is possible. Just create an imageservlet like this example here. To the point just obtain the image as InputStream from DB by ResultSet#getBinaryStream() and write it to the OutputStream of the response as obtained by HttpServletResponse#getOutputStream() the usual Java IO way. Don't forget to add the HTTP content type and content length headers. If you omit the content type, the browser don't know what to do with the information. If you omit the content length, it will be sent with chunked transfer encoding, which is a tad less efficient.
As to referencing the servlet in the CSS file, just specify the URL relative to the CSS file. This way you don't need to worry about the context path. Determining the relative URL isn't that hard, it works the same way as with accessing local disk filesystem paths in the command console. cd ../../foo/bar/file.ext and so on. You've ever learnt that at schools, yes?
OK, assume that the imageservlet is located at http://example.com/context/image?id=x and that the CSS file is located at http://example.com/context/css/globalstyle.css (thus, the current folder is css), then the right relative URL to the imageservlet from inside the CSS file would be:
background-image: url('../image?id=123');
The ../ goes a step backwards in the directory structure so that you go from the folder http://example.com/context/css to http://example.com/context. If you still have a hard time in figuring the right relative path, then let us know the absolute URL of both the servlet and the CSS file, then we'll extract the correct relative path for you.

Resources