ASP.NET MVC5 file download security best practices? - c#

We are building an ASP.NET MVC5 web app which includes serving file downloads.
Users are required to login using ASP.NET Identity framework.
The files are stored in the database (we are interfacing with a legacy application) and each file is identified by a standard integer primary key.
We plan to serve the files as follows:
The user requests a file using its ID eg. http://www.example.com/getFile?fileId=5
The controller then checks to see if the requesting user is allowed to access that file (using some complex business rules) and if successful streams the file to the user.
I have been researching best practices but am struggling to find specifics as most of what I've read deals with the scenario where the files are being read from physical paths and therefore the recommendation is to obfuscate the filename in the request.
We could obfuscate the file's ID but I don't see much point to that if the controller will validate the user's access to the file on each request.
Is our approach sufficient or should we be doing it another way, if so, what is the recommended way please?

Your approach is perfectly sufficient. If your authorisation rules in your controller adequately protect the files, then this should be all that you require.
The only information leak that is occurring is the use of what is presumably the primary key of the file in the database in the URL that is being used to request the file. This could potentially create a vulnerability if for example another part of your application is vulnerable to SQL injection attacks and an attacker makes use of the IDs in your URL to construct a SQL injection attack to fetch a file with a specific ID. Whether this is a risk in practice however depends on whether your application is also vulnerable to SQL injection attacks and most attackers would probably guess or brute force the IDs any way, so there may be little practical benefit to masking these even if you were vulnerable to SQL injection attacks - a better focus in that case would be to simply make sure that you're not.

I've once created something similar.
The user asked for a file, we validated if the user could access the file and then streamed it to their browser.
One thing we did though, is store the files outside of the web app folder. This made sure that the files couldn't get into Google by accident, and is also more secure, because malevolent users can't use the full path to the file to download the file directly.
You can obfuscate the file name quite easily. Take a look at this code for example:
public FileResult Download()
{
byte[] fileBytes = System.IO.File.ReadAllBytes(#"c:\folder\myfile.ext");
string fileName = "myfile.ext";
return File(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, fileName);
}
in the variable "filename", you put the file that the user will get to see. This can be anything.
Hope this helps.

Related

What should I be saving locally when I use Azure blob storage?

I'm using Azure Blob Storage to allow users to upload files from a web app.
I've got them uploading into a container, but I'm not sure what would be best to save on the web app's database since there are multiple options.
There is a GUID for the file, but also a URL.
The URL can be used to get to the file directly, but is there a risk that it could change?
If I store the file GUID I can use that to get the other details of the file using an API, but of course that's and extra step compared to the URL.
I'm wondering what best practices are. Do you just store the URL and be done with it? Do you store the GUID and always make an extra call whenever a page loads to get the current URL? Do you store both? Is the URL something constant that can act just as good as a GUID?
Any suggestions are appreciated!
If you upload any file on azure blob it will give you Url to access it which contains three part
{blob base url}/{Container Name}/{File Name}
e.g
https://storagesamples.blob.core.windows.net/sample-container/logfile.txt
SO you can save Blob base url and container name in config file and only the file name part in data base.
and at run time you can create whole url and return it back to user.
So in case if you are changing blob or container you just need to change it in config file.

ASP.NET: Handling server cached file for short-term

I have this specific scenario:
The user is sending me request which contains a URL to a file in my private repository.
The server side catch this request and Download the file.
The server making some calculation on the downloaded file.
The server sending the results back to client.
I implemented this in the "Naive" way. Which mean, I downloading the file (step 2) for each request. In most cases, the user will send the same file. So, I thought about better approach: keep the downloaded file in short term "cache".
This mean, I will download the item once, and use this for every user request.
Now the question is, how to manage those files?
In "perfect world", I will use the downloaded file for up to 30 minutes. After this time, I won't use it any more. So, optional solutions are:
Making a file system mechanism to handling files for short terms. Negative: Complex solution.
Using temporary directory to do this job (e.g. Path.GetTempFileName()). Negative: What if the system will start to delete those files, in the middle of reading it?
So, it's seems that each solution has bad sides. What do you recommend?

Make a PHP file accesable only via my C# application?

I got a little questions for you all! Currently I have a login form on my C# application and you need to enter the right user and pass to open another form that is the real program. To do this I got this line of codes:
string response = SendRequest("http://mysite/login.php?name=" + userName);
string[] back = response.Split('_');
back[0] = back[0].Replace(" ", "");
back[0] = back[0].ToUpper();
and I got this method:
private string SendRequest(string url)
{
try
{
using (WebClient client = new WebClient())
{
return client.DownloadString(new Uri(url));
}
}
catch
{
MessageBox.Show("Error while receiving data from the server.","Something broke.. :(", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
return null;
}
}
I also have a method that checks if the entered password = the stored passwod in the database
$dbConnection = new mysqli("SERVER", "LOGIN", "PASS", "DBNAME");
$email = $_GET['name'];
$stmt = $dbConnection->prepare('SELECT password, salt FROM TABLE WHERE email = ?');
$stmt->bind_param('s', $email);
$stmt->execute();
$stmt->bind_result($pass, $salt);
$stmt->fetch();
echo "$pass" . "_" . "$salt";
This works fine and I can login when I enter the right password and I can't when I enter the wrong password.
My problem though is if I enter : http://mysite/login.php?name=[username]
where [username] is any username it returns the hashed and salted password. Since it's hashed and salted this is not a big issue but later when I will do inserts this will become a bigger problem since then someone could enter information into the tables with this method. So my question is: Is there anyway to make the PHP file only allow to return the values if the connections come from my C# application?
If you are really interested in managing this in a manner such as that, you should do one of the following:
Implement an OAUTH Configuration
You should implement a form of OAUTH in your PHP app, and generate the right proper tokens for your C# app. You would then use a full OAUTH dialogue to send/retrieve the data from the PHP server. This would eliminate the possibility for random queries to the page to return proper results. You should also implement HTTPS with this. PHP OAUTH implementation basics: http://www.sitepoint.com/creating-a-php-oauth-server/
Advantages: Security. This method provides a greater deal of security than the others, without sacrificing the robustness of the project in general. You would also be able to remove the entire GET/POST request by using tokens for each client, instead of a GET against username. Extensibility. This method can be easily extended to provide features for further apps/programmes.
Disadvantages: Complexity. This method is much more complex and has much more overhead than the others.
Modify the Request to be a POST with Secret
Another option is to change the C# programme to send a POST request to the PHP page, and send some secret value with it as well. This is not recommended, as anyone who knows the secret value could send it from a malicious page. This is equivalent to implementing basic XSS attack prevention. You should also use HTTPS for this as well.
Advantages: Simplicity. This method is the quickest/easiest to implement without removing any current features.
Disadvantages: Insecurity. This method does not provide any security benefits, apart from security through obscurity.
Alter Database Visibility
Since you are using MySQL on the PHP page to return the value, you should modify the C# programme to connect directly to the MySQL database and collect the value. This has the advantage of eliminating the possibility of someone with malicious intent querying the PHP page without your permission. Various MySQL connectors: https://www.mysql.com/products/connector/
Advantages: Moderate Security. This method does remove the possibility of PHP exploits, and also assists in keeping the database secret.
Disadvantages: Moderate Insecurity. This method requires embedding the connection string (with username and password) into the application when distributed. Certain measures could be taken to assist in eliminating some of the issues with this, but in general this method is an average method. Code Rewrites. This method requires an entire rewrite of the programming infrastructure.
Custom User Agent
Edit: Forgot to mention, another simple/easy workaround that is extremely insecure.
You could utilize a custom User Agent (similarly to the secret in the POST method.) This would allow your PHP page to determine that the request likely came from your application. You should, again, use HTTPS for this method as well. This method would not require much code change, and could be combined with HTTP_REFERER to assist in securing the origin as well.
Advantages: Simplicity. This is, by far, the easiest method to implement.
Disadvantages: Insecurity. Much like the POST with Secret method, this is extremely insecure. Anyone who knows how your User Agent is formed could quite simply and readily exploit it. Using HTTPS would likely help mitigate this risk, but it would never go away.
Examples:
C#: client.Headers.Add ("user-agent", "my-super-insecure-user-agent");
https://msdn.microsoft.com/en-us/library/system.net.webclient.aspx
PHP: if ($_SERVER['HTTP_USER_AGENT'] === "my-super-insecure-user-agent") {/*Process request*/}
http://php.net/manual/en/reserved.variables.server.php
Tl;dr
Ultimately, the choice is yours. Given the situation, I would recommend using the following advisories:
If development time is not an issue, utilize the OAUTH model. This is the most expandable and secure method.
If you can eliminate the PHP in general, use the Database Visibility model. This has the advantage of removing the inherit security risks associated with having a publicly-visible PHP page. You could also use this model, with more efficiency and speed, if the database is always local to the users network. This also means that outsiders could not access your information, if properly fire-walled.
If you need a quick-and-dirty solution, use the POST model. This would be the fastest and simplest to implement, but the least secure.

Open url in browser and fill asp.net popup with values from wpf application

I have a Wpf application and I want to open url (asp page) and fill popup with values (login, password). How can I do it?
Now I open url with Process.Start:
var processStartInfo = new ProcessStartInfo(url);
Process.Start(processStartInfo);
But I can't find out a way to fill popup..
I find way to use webControl... but I need to open url in browser..
My first recommendation is to think whether a mechanism like this is really necessary because it deals with a lot of sensitive Information. If you can avoid it, I'd recommend not to use at least the password.
Can you make changes to the ASP-page? Then you can add some request parameters that the ASP application fills into the fields, you could do that.
However, in this specific scenario I strongly recommend NOT to fill the username and password directly in the URL because it can be read easily along the path. If the application runs in a completely safe, controlled area, one can argue about the username, but I would not recommend it.
What you could do is to create some kind of token mechanism, so that you do not transmit sensitive data:
WPF application creates token, e.g. in database. It is important that the token is random and cannot be guessed, maybe a GUID. Also it should be valid only for a short period of time. Also the WPF application stores the necessary login Information in the database.
WPF application opens the browser with an URL like https://srv?token=<random token>.
ASP application receives token through request Parameter, checks whether it is still valid and signs user in using the Information that is stored along with the token. It deletes the entry in the database immediately so that the token cannot be reused.
This approach requires you to be able to make changes to both the WPF application and also the ASP application.
And as said above, if you can avoid it, it is preferrable to have the user enter his or her credentials manually.

Is there any basic string obfuscation I can use whilst pair programming?

Whilst pair programming with database systems, sometimes we end up temporarily hardcoding credentials (typically of our own accounts), which leads to slight awkwardness with the partner trying to look away whenever the password is onscreen. Is there any simple way of using basic obfuscation (ie, rot13) to hardcode a password without other developers taking a quick look and seeing my password?
It doesn't need to be secure. It only needs to grease the social aspect. I don't want anything complex involving super secure encryption or reading passwords out of files etc. This has to be quick to implement (i.e. 10 seconds max) whilst coding on the fly. Ideally I want something like:
string password = string.rot13("zlcnffjbeq");
Does anything like this already exist?
To configure SQL Server for Windows integrated security
From the Windows Start menu, select Microsoft SQL Server, and then select Enterprise Manager.
Open the node for the server and expand the node for the database you want to give users permissions for.
Right-click the Users node and select New Database User.
In the Database User Properties dialog box, enter domain\username in the Login name box, and then click OK. Additionally, configure the SQL Server to allow all domain users to access the database.
From MSDN. Connection strings become Server=x;Initial Catalog=y;Integrated Security=true instead of Server=x;Initial Catalog=y;User=you;Pwd=yourpassword.
I would suggest to store your password in a config file. For source control, use a dummy one. Then after getting latest version of the config file on your PC, you can modify the config by adding your password.
You could use base64 and just keep the base64 version of your password somewhere handy for cut and paste, bearing in mind that your system admin will have a blue fit if they find out about this. Both the suggestions in comments (#Oli/#CodeCaster) are preferable to this, imo.
DPAPI is more work but arguably a balanced solution to your requirement, with some security.
The .NET Framework provides access to the data protection API (DPAPI),
which allows you to encrypt data using information from the current
user account or computer. When you use the DPAPI, you alleviate the
difficult problem of explicitly generating and storing a cryptographic
key.
Maybe you can store your password in a String variable like here
/* Variable that stores the password */ string pwd = "12345";
string password = string.rot13(pwd);
and tab it out of the visual range of the editor. This would be a proper solution to your problem.
Then you can use the string variable somewhere else in your code and no one can see your password unless he scrolls to the right

Categories

Resources