Web Application Security Guide/Checklist
- Do not rely on Web Application Firewalls for security (however, consider using them to improve security)
- If external libraries (e.g. for database access, XML parsing) are used, always use current versions
- If you need random numbers, obtain them from a secure/cryptographic random number generator
- For every action or retrieval of data, always check access rights
- Do not, under any circumstances, attempt to implement cryptographic algorithms yourself. Use high-level libraries for cryptography.
- Ensure debug output and error messages do not leak sensitive information
- Mark problematic debug output in your code (e.g.
//TODO DEBUG REMOVE) even if you intend to remove it after just one test
- Do not use “
eval()” and similar functions
- Avoid “
system()” and similar functions if possible
- Avoid “
- Ensure database servers are not directly reachable from the outside
- Consider to block old browsers from using your application
File inclusion and disclosure
- Do not take file names for inclusions from user input, only from trusted lists or constants.
- If user input is to be used, validate it against a whitelist. Checking if the file exists or if the input matches a certain format is not sufficient.
- Avoid having scripts read and pass through files if possible.
- If you read and deliver files using user-supplied file names, thoroughly validate the file names to avoid directory traversal and similar attacks and ensure the user is allowed to read the file.
- Ensure the application runs with no more privileges than required.
File upload vulnerabilities
- Avoid unnecessary file uploads
- Ensure that files uploaded by the user cannot be interpreted as script files by the web server, e.g. by checking the file extension (or whatever means your web server uses to identify script files)
- Ensure that files cannot be uploaded to unintended directories (directory traversal)
- Try to disable script execution in the upload directory
- Ensure that the file extension matches the actual type of the file content
- If only images are to be uploaded, consider re-compressing them using a secure library to ensure they are valid
- Ensure that uploaded files are specified with the correct Content-type when delivered to the user
- Prevent users from uploading special files (e.g. .htaccess, web.config, robots.txt, crossdomain.xml, clientaccesspolicy.xml)
- Prevent users from overwriting application files
- Consider delivering uploaded files with the “Content-disposition: attachment” header
- use prepared statements to access the database – or –
- use stored procedures, accessed using appropriate language/library methods or prepared statements
- Always ensure the DB login used by the application has only the rights that are needed
If the input for the title of the page on this website were vulnerable to SQL injection then the URL that would be used for the attack is https://en.wikibooks.org/w/index.php?title=. A simple test to reveal if the input is vulnerable would be to add https://en.wikibooks.org/w/index.php?title=' because this SQL syntax would break the query and show an SQL error on the page. The next query could be to select usernames and hashed passwords with something like https://en.wikibooks.org/w/index.php?title=1%20UNION%20ALL%20SELECT%20user_pass%20FROM%20wiki_user;--. The ;-- on the end ends the query and makes the remaining query a comment. Files containing password salts could be dumped to allow an attacker to begin cracking passwords and gain access to administrator accounts using the select load_file() query. A query like this one could be used to gain shell access to the server: https://en.wikibooks.org/w/index.php?title=UNION%20SELECT%20<? system($_REQUEST['cmd']); ?>,2,3%20INTO%20OUTFILE%20"shell.php";--
Cross-site scripting (XSS)
- Escape anything that is not a constant before including it in a response as close to the output as possible (i.e. right in the line containing the “echo” or “print” call)
- If not possible (e.g. when building a larger HTML block), escape when building and indicate the fact that the variable content is pre-escaped and the expected context in the name
- Explicitly set the correct character set at the beginning of the document (i.e. as early as possible) and/or in the header.
- don’t forget URLs in redirector scripts
- A Content Security Policy may be used as an additional security measure, but is not sufficient by itself to prevent attacks.
XML and internal data escaping
- Avoid XML if possible.
- For XML, use well-tested, high-quality libraries, and pay close attention to the documentation. Know your library – some libraries have functions that allow you to bypass escaping without knowing it.
- If you parse (read) XML, ensure your parser does not attempt to load external references (e.g. entities and DTDs).
- For other internal representations of data, make sure correct escaping or filtering is applied. Try to use well-tested, high-quality libraries if available, even if it seems to be more difficult.
- If escaping is done manually, ensure that it handles null bytes, unexpected charsets, invalid UTF-8 characters etc. in a secure manner.
XML, JSON and general API security
- Ensure proper access control to the API
- Do not forget that you need to correctly escape all output to prevent XSS attacks, that data formats like XML require special consideration, and that protection against Cross-site request forgery (CSRF) is needed in many cases.
- Use standard data formats like JSON with proven libraries, and use them correctly. This will probably take care of all your escaping needs.
- Make sure browsers do not misinterpret your document or allow cross-site loading
- Ensure your document is well-formed
- Send the correct content type
- Use the
- For XML, provide a charset and ensure attackers cannot insert arbitrary tags
- For JSON, ensure the top-level data structure is an object and all characters with special meaning in HTML are escaped
- Thoroughly filter/escape any untrusted content
- If the allowed character set for certain input fields is limited, check that the input is valid before using it
- If in doubt about a certain kind of data (e.g. server variable), treat it as untrusted
- If you are sure, but there is no real need to treat it as trusted, treat it as untrusted
- The request URL (e.g. in environment variables) is untrusted
- Data coming from HTTP headers is untrusted
- Server name (!)
- All POST and GET data is untrusted
- includes non-user-modifiable input fields like select
- All content validation is to be done server side
Cross-site request forgery (CSRF)
- Include a hidden form field with a random token bound to the user’s session (and preferably the action to be performed), and check this token in the response
- Make sure the token is non-predictable and cannot be obtained by the attacker
- do not include it in files the attacker could load into his site using
- do not include it in files the attacker could load into his site using
- Referer checks are not secure, but can be used as an additional measure
- Prevent (i)framing of your application in current browsers by including the HTTP response header “X-Frame-Options: deny”
Insecure data transfer
- Use SSL/TLS (https) for any and all data transfer
- Do not start communicating via http, only redirecting to https when “needed”
- Mark cookies with the “secure” attribute
- Use the Strict-Transport-Security header where possible
- Educate users to visit the https:// URL directly
- If your web application performs HTTPS requests, make sure it verifies the certificate and host name
- Consider limiting trusted CAs if connecting to internal servers
- Regenerate (change) the session ID as soon as the user logs in (destroying the old session)
- Prevent the attacker from making the user use his session by accepting session IDs only from cookies, not from GET or POST parameters (PHP: php.ini setting “session.use_only_cookies”)
- Set the “HttpOnly” attribute for session cookies
- Generate random session IDs with secure randomness and sufficient length
- Do not leak session IDs
Truncation attacks, trimming attacks
- Avoid truncating input. Treat overlong input as an error instead.
- If truncation is necessary, ensure to check the value after truncation and use only the truncated value
- Make sure trimming does not occur or checks are done consistently
- Introduce length checks
- care about different lengths due to encoding
- Make sure SQL treats truncated queries as errors by setting an appropriate SQL MODE
- Do not store plain-text passwords, store only hashes
- Use scrypt, bcrypt, or some other hashing algorithm specifically designed for secure password "storage".
- Use a secure hashing algorithm (e.g. SHA-256 as of 2011)
- Use per-user salts
- Use strengthening (i.e. multi-iteration hashing to slow down brute force attempts)
- Limit login attempts per IP (not per user account)
- Enforce reasonable, but not too strict, password policies
- If a password reset process is implemented, make sure it has adequate security. Questions like “mother’s maiden name” can often be guessed by attackers and are not sufficient.
- Know comparison types in your programming language and use the correct one
- When in doubt (especially with PHP), use a strict comparison (PHP: "
- When comparing strings for equality, make sure you actually check that the strings are equal and not that one string contains the other
- Do not use the short form “
<?”, always use the full form “
- When using the nginx web server, make sure to correctly follow the official installation instructions and pay attention to the "Pitfalls" page. Beware of tutorials that often contain working but insecure configuration examples.
preg_replacecan act as
eval()in certain cases. Avoid passing user input to it. If you must, correctly filter and escape it.
- Use the Suhosin (including the patch, if possible) and configure it with strict rules
suhosin.mail.protectto 2 if possible
- When updating PHP to PHP 5.4 from an older version, ensure legacy applications do not rely on magic quotes for security.
Prefetching and Spiders
- Use POST requests instead of GETs for anything that triggers an action
- Know the meaning of these files
- Ensure robots.txt does not disclose "secret" paths
- Ensure crossdomain.xml and clientaccesspolicy.xml do not exist unless needed
- If used, ensure crossdomain.xml and clientaccesspolicy.xml allow access from trusted domains only
- Prevent users from uploading/changing special files (see file upload vulnerabilities section)
SSL, TLS and HTTPS basics
- Follow SSLLabs best practices including:
- Ensure SSLv2 is disabled
- Generate private keys for certificates yourself, do not let your CA do it
- Use an appropriate key length (usually 2048 bit in 2013)
- If possible, disable client-initiated renegotiation
- Consider to manually limit/set cipher suites