Ways to Keep Your PHP App from Getting Owned

Just spent the last three hours cleaning up a hacked site for a client. Not fun.

People are still getting owned by script kiddies with vulnerability scanners.

Here's my quick and dirty list for keeping PHP apps secure. Do these basic things, and you'll be ahead of of the pack.

  • Stop trusting user input. If someone can type it, they can break it. Always escape and validate user data before using it queries or output. Stop dropping $_POST and $_GET variables directly into your SQL queries. Use prepared statements.
  • JavaScript validation is nice for user experience, but it's trivial to bypass. Always validate on the server side.
  • HTML inputs can be easily edited, even select boxes and hidden fields. Always validate them on the server.
  • Don't trust the MIME type of uploaded files. It can be easily spoofed. Always validate the extension as well. Whitelist extensions, don't blacklist. i.e. Clearly define which extensions are allowed.
  • Error messages are for you, not the world. These messages can provide attackers with a blueprint of your app and database. Turn off display_errors on production.
  • Do not leave a phpinfo file on your server.
  • md5 and sha1 aren't for passwords. They are too fast. Use something slower like bcrypt.
  • Don’t echo raw data. Wrap it with htmlspecialchars(). Otherwise, you are leaving yourself open to XSS attacks.
  • Session hijacking is real. Use session_regenerate_id() after login. Make sure that session IDs are not appended to URLs. Use the Cookies method to propagate sessions instead of the URL parameter.
  • Use HTTPS. The old days are behind us now. Certs are no longer expensive.
  • Don't allow users to view your directories. If you're on a shared host that doesn't allow you to configure these details, then drop an index.php file into any folder that shouldn't be "browsable."
  • Turn off register_globals. It's a nightmare.
  • If you're running your own server, keep your house clean. Keep PHP and other software up to date.
  • SFTP, SSH, and FTP accounts should not have usernames such as "admin". They should not have simple passwords. Bad password: hello123 Good password: !P%X5iKqeaFI{5m-
  • Variables such as $_SERVER['PHP_SELF'] cannot be trusted. They come from the client. Never trust the client.
  • The HTTP referrer header can be easily modified. Never use it for any kind of custom authentication method.
  • Don't store secrets in your code. Config files shouldn't have your DB password hard-coded. Use environment variables or put config files outside the webroot.
  • Your MySQL user doesn't need DROP DATABASE. Give it just enough rights to do its job.
  • Rate-limit logins. Don't let someone brute force your passwords by hammering the login form. Even a simple timeout helps.
  • Don’t eval() anything. Ever.
  • Don't reinvent cryptography. Trust what has already been battled tested in the wild. Base encoding stuff and moving characters around is not cryptography.
  • Backup. Backup. Backup. Always backup. And use version control.
  • Cap the upload size. Nobody should be uploading a 300MB PNG file. Use php.ini limits.
  • Your folders do NOT need to be 777. Learn how unix permissions work.
  • Disable allow_url_fopen unless you have a specific reason to use it.
  • Log stuff. Failed logins, weird requests, all of it. Logs are boring until you actually need them.

If you stick to the principles above, you will be way ahead of the other sloppy PHP apps floating around on the Internet.