Hacker used picture upload to get PHP code into my site

Client side validation

The validation code you have provided is in JavaScript. That suggests it is code that you use to do the validation on the client.

Rule number one of securing webapps is to never trust the client. The client is under the full control of the user - or in this case, the attacker. You can not be sure that any code you send to the client is used for anything, and no blocks you put in place on the client has any security value what so ever. Validation on the client is just for providing a smooth user experience, not to actually enforce any security relevant constraints.

An attacker could just change that piece of JavaScript in their browser, or turn scripts off completely, or just not send the file from a browser but instead craft their own POST request with a tool like curl.

You need to revalidate everything on the server. That means that your PHP must check that the files are of the right type, something your current code doesn't.

How to do that is a broad issue that I think is outside the scope of your question, but this question are good places to start reading. You might want to take a look at your .htaccess files as well.

Getting the extension

Not a security issue maybe, but this is a better way to do it:

$ext = pathinfo($filename, PATHINFO_EXTENSION);

Magic PHP functions

When I store data from edit boxes, I use all three of PHP's functions to clean it:

$cleanedName = strip_tags($_POST[name]); // Remove HTML tags
$cleanedName = htmlspecialchars($cleanedName); // Allow special chars, but store them safely. 
$cleanedName = mysqli_real_escape_string($connectionName, $cleanedName);

This is not a good strategy. The fact that you mention this in the context of validating file extensions makes me worried that you are just throwing a couple of security related functions at your input hoping it will solve the problem.

For instance, you should be using prepared statements and not escaping to protect against SQLi. Escaping of HTML tags and special characters to prevent XSS needs to be done after the data is retrieved from the database, and how to do it depends on where you insert that data. And so on, and so on.

Conclusion

I am not saying this to be mean, but you seem to be doing a lot of mistakes here. I would not be surprised if there are other vulnerabilities. If your app handles any sensitive information I would highly recommend that you let someone with security experience have a look at it before you take it into production.


First off, if someone exploited a file upload function, ensure that you're verifying the file on both the client and server. Bypassing client-side JavaScript protection is trivial.

Second, ensure that you go through and implement these ideas from OWASP.

That should cover most of your problems. Also ensure that you don't have any other unpatched flaws on your server (for example, outdated plugins, exploitable servers, etc.)


It is super-important to note here that PHP was designed to be embedded in other content. Specifically, it was designed to be embedded within HTML pages, complementing a largely static page with minor bits of dynamically updated data.

And, quite simply, it doesn't care what it's embedded in. The PHP interpreter will scan through any arbitrary file type, and execute any PHP content that's properly marked with script tags.

The historic problem that this has caused is that, yes, image uploads can contain PHP. And if the web server is willing to filter those files through the PHP interpreter, then that code will execute. See the Wordpress "Tim Thumb" plugin fiasco.

The proper solution is to make sure that your web server never, ever treats untrusted content as something it should run through PHP. Attempting to filter the input is one way to go about it, but as you've found, limited and error prone.

Much better to verify that both file location and file extension are used to define what PHP will process, and to segregate uploads and other untrusted content into locations and extensions that won't be processed. (How you do so varies from server to server, and suffers from the "making things work usually means loosening security in ways you're not aware" problem.)