The Web Application Hacker’s Handbook is written by Dafydd Stuttard and Marcus Pinto, the founders of MDSec. This post has some notes from the book on securing applications. The book itself has much more information as well as helpful examples.
Handling Client-Side Data Securely:
• In the application, include sufficient context within the encrypted data to prevent it from being replayed in a different context.
• Regard every item of data received from the client as tainted and potentially malicious.
• Log anomalies and terminate the user’s session or even suspend the account.
Securing Authentication:
• Enforce minimum password quality requirements including rules regarding minimum length, the appearance of characters (alphabetic, numeric, typographic), the appearance of both uppercase and lowercase characters, the avoidance of common passwords (dictionary words, names, etc), preventing a password from being set to the username, and preventing a similarity or match with previously set passwords.
• Assign unique usernames.
• Create system-generated usernames and passwords with sufficient entropy that they cannot feasibly be sequenced or predicted.
• Protect client-server communications with a well-established cryptographic technology such as SSL.
• If using HTTP in parts of the application, ensure that the login form itself is loaded using HTTPS rather than switching to HTTPS at the point of the login submission.
• Only use POST requests to transmit credentials to the server.
• Never place credentials in URL parameters or cookies.
• Never transmit credentials back to the client, even in parameters to a redirect.
• Use a strong and appropriately salted hash function to store credentials.
• Client-side “remember me” functionality should in general remember only nonsecret items such as usernames.
• Implement a password change facility and require users to change their password periodically.
• Send credentials for new accounts as securely as possible and in a time-limited manner.
• Consider capturing some of the user’s login information using drop-down menus rather than text fields to prevent keyloggers from capturing all the data the user submits.
• Validate passwords in full in a case-sensitive way, without filtering or modifying any characters, and without truncating the password.
• Use catch-all exception handlers around all API calls to delete all session and method-local data being used to control the state of the login processing and to invalidate the current session.
• Code-review all authentication logic to identify logic errors such as fail-open conditions.
• Strictly control multistage logins by the following:
1. Hold all data about progress through the stages and the results of previous validation tasks in the server-side sesion object and never transmit to or read it from the client.
2. Prevent information from being submitted more than once by the user.
3. Prevent the user from modifying data that has already been collected and/or validated.
4. Verify that all prior stages have been correctly completed and mark the authentication attempt as bad if they have not been correctly completed.
5. Proceed through all stages of the login, even if the user failed to complete earlier stages correctly, and even if the original username was invalid.
6. Always employ a multistage process in which users identify themselves at an initial stage and the randomly varying question is presented to them at a later stage.
• Do not disclose any information about authentication parameters via the authentication mechanisms used by the application.
• Use a single code component to respond to all failed login attempts with a generic message.
• Respond to any series of failed login attempts from the same browser with a generic message advising that ccounts are suspended if multiple failures occur and that the user should try again later.
• Possibly use the e-mail address as a username.
• Use unpredictable usernames and prevent their enumeration.
• Use CAPTCHA challenges on every page that may be a target for brute-force attacks.
• Implement a password change function that is accessible only from within an authenticated session and which requires users to reenter their existing password and enter their new password twice.
• Never use password hints.
• E-mail the user a unique, time-limited, unguessable, single-use recovery URL to enable users to regain control of accounts.
• Log all authentication-related events, including login, logout, password change, password reset, account suspension, and account recovery.
Securing Session Management:
• Use token generation mechanisms that use an extremely large set of possible values and contain a strong source of pseudorandomness.
• Only transmit tokens over HTTPS.
• Never transmit session tokens in the URL.
• Implement logout functionality to dispose of all session resources held on the server and invalidate the session token.
• Implement session expiration after a suitable period of inactivity.
• Prevent concurrent logins.
• Restrict the domain and path scope of an application’s session cookies.
• Create a fresh session after authentication.
• Monitor requests that contain invalid tokens.
• Alert users to anomalous events relating to their session, such as concurrent logins or apparent hijacking.
Securing Access Controls:
• Evaluate and document the access control requirements for every unit of application functionality.
• Drive all access control decisions from the user’s session.
• Use a central application component to check user access control and process every client request via this component to validate that the user making the request is permitted to access the functionality and resources being requested.
• Mandate that every application page must implement an interface that is queried by the central access control mechanism.
• Restrict access by IP address to administrative pages.
• Consider implementing per-transaction reauthentication and dual authorization for security-critical application functions.
• Consider using a multilayered privilege model that implement access controls at each of the application server, database, and operating system layers.
Preventing SQL Injection:
• Use parameterized queries for every database query.
• Properly parameterize every item of data inserted into the database query.
• Have the application use the lowest possible level of privileges when accessing the database.
• Remove or disable unnecessary functions.
• Evaluate, test, and apply vendor-issued security patches in a timely way.
Preventing XPath Injection:
• Check user input against a white list of acceptable characters, which should ideally include only alphanumeric characters.
Preventing OS Command Injection:
• Use a whitelist to restrict user input to a specific set of expected values.
• Use command APIs that launch a specific process via its name and command-line parameters, rather than passing a command string to a shell interpreter that supports command chaining and redirection.
Preventing Path Traversal Vulnerabilities:
• Avoid passing user-submitted data to any filesystem API.
• Check whether a user-submitted filename contains either of the path traversal sequences or any null bytes. If so, the application should stop processing the request.
• Use a hard-coded list of permissible file types and reject any request for a different type.
• Use suitable filesystem APIs to verify that nothing is amissed and that the file to be accessed using that filename is located in the start directory specified by the application.
Preventing SOAP Injection:
• Employ boundary validation filters at any point where user-supplied data is inserted into a SOAP message.
• HTML-encode any XML metacharacters appearing in user input.
Avoiding Logic Flaws:
• Reflect on every assumption made within the design and try to imagine circumstances under which each assumption might be violated.
• Think about the ways in which the application will handle unexpected user behavior and the potential side effects of any dependencies and interoperation between different code components and different application functions.
• When implementing functions that update session data on the basis of input received from the user, or actions performed by the user, carefully consider any impact that the updated data may have on other functionality within the application.
Preventing Cross-Site Scripting Attacks:
• Validate input by ensuring that the data is not too long, the data contains only a certain permitted set of characters, and the data matches a particular regular expression.
• Validate output by HTML encoding data to sanitize potentially malicious characters.
• Avoid inserting user-controllable data directly into existing script code.
• Perform server-side data validation to verify that the query string contains a single parameter, the parameter’s name is message, and the parameter’s value contains only alphanumeric content.
Preventing CSRF Flaws:
• Supplement HTTP cookies with additional tokens that are transmitted via hidden fields in HTML forms.
Preventing UI Redress:
• Use the X-Frame-Options response header with the deny and sameorigin values.
Preventing JavaScript Hijacking:
• Have the application accept only POST requests for potentially vulnerable script code.
Preventing Header Injection Vulnerabilities:
• Perform context-dependent validation of the data being inserted in as strict a manner as possible.
• Filter every piece of data being inserted into headers to detect potentially malicious characters.
Preventing Open Redirection Vulnerabilities:
• Remove the redirection page from the application, and replace links to it with direct links to the relevant target URLs.
Preventing Local Privacy Attacks:
• Avoid storing anything sensitive in a persistent cookie.
• Use suitable cache directives to prevent sensitive data from being stored by browsers.
• Never use URLs to transmit sensitive data.
Preventing ActiveX Vulnerabilities:
• Perform a source code review and penetration test to locate vulnerabilities such as buffer overflows.
• Avoid exposing inherently dangerous methods that call out to the filesystem or operating system using user-controllable input.
Securing Shared Environments:
• Use a remote access mechanism that implements robust authentication, cryptographic technologies that are not vulnerable to eavesdropping, and is fully security hardened.
• Grant access to individual customers on a least-privilege basis.
• Use a separate operating system account for each customer’s application and make sure it has read and write access only to that application’s file paths.
• Use a separate database instance for each customer.
Securing Web Server Configuration:
• Change any default credentials.
• Remove any default accounts that are not required.
• Block public access to administrative interfaces, either by placing ACLs on the relevant paths within the web root or by firewalling access to the nonstandard ports.
• Remove all default content and functionality that is not strictly required for business purposes.
• Where possible, disable directory listings.
• Disable all methods other than those used by the application.
• Ensure that the web server is not configured to run as a proxy.
Securing Web Server Software:
• Choose software with a good track record.
• Apply vendor patches.
• Disable any built-in functionality that is not required.
• Rename functions and resources from their default values.
• Configure the web server process to use the least powerful operating system account possible.
• Impose strict network-level filteres on traffic to and from the web server.
• Use an intrusion detection system to identify any anomalous network activity that may indicate that a breach has occurred.