1 minute, 36 seconds
I recently documented best security practices for writing a web app. Since I was most of the way there for a nice tidy blog post on the topic, I’m using the contents of those docs as a cheat sheet for web app security. Best to refer to OWASP for a more exhaustive list, but here’s mine in PHP/Apache:
title | description | sample |
---|---|---|
No Traffic on Port 80 | Always use an encrypted channel for web traffic, never send a session cookie in the clear | RewriteEngine On RewriteCond %{HTTPS} off RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} |
HSTS | Set header so after 1st redirect, client goes directly to SSL connection | Header always set Strict-Transport-Security “max-age=15768000” |
Forward Secrecy | Use ephemeral keys for TLS connections to prevent wholesale decryption if private key is compromised | SSLCipherSuite EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH SSLProtocol All -SSLv2 -SSLv3 SSLHonorCipherOrder On |
Anti-Clickjacking | Prevent your site from being included in an iframe | Header always set X-Frame-Options DENY |
Anti-CSRF Nonces | No one getting tricked to submit pre-filled forms using their existing session cookie | $_POST[$NONCEKEY] == $_COOKIE[$NONCEKEY] (but more to it – see this gist) |
XSS escaping | NEVER TRUST USER INPUT, save raw values to DB, cleanse on display | print htmlspecialchars($user_string_here, ENT_QUOTES, ‘UTF-8’) |
Secure cookies | Never transmit cookies in the clear, works well with HSTS | setcookie( ‘session’, $sessionId, 0, ‘/’, ‘www.example.com’, isset($_SERVER[“HTTPS”]), true); |
HttpOnly cookies | don’t allow JavaScript/XSS to access your cookies | setcookie( ‘session’, $sessionId, 0, ‘/’, ‘www.example.com’, isset($_SERVER[“HTTPS”]), true); |
bcrypt hashes | Use a *slow* hashing method instead of a *fast* one (I’m looking at you MD5…) | password_hash(“rasmuslerdorf”, PASSWORD_DEFAULT) Though Argon2 is up and coming! |
strong session ID | don’t store anything but pseudo random ID in the cookie. Again NEVER TRUST USER INPUT! | bin2hex(openssl_random_pseudo_bytes(50)) |
no session fixation | on logout, delete cookie **and** server side entry in DB so session is dead dead dead | NA |
re-prompt for passwords | on email, password or username change or when showing/changing sensitive data | NA |
no SQL injection | still NEVER TRUST USER INPUT, parameterize all queries | $dbh = new PDO(…); $stmt = $dbh->prepare(‘SELECT * FROM users where username = :username’); $stmt->execute( array(‘:username’ => $_REQUEST[‘username’]) ); |