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’]) ); |