Practical Aspects of Securing Web Applications
However, a reality check will easily disprove this! Unfortunately, many organizations realize that the time and effort invested in designing and building security as an integral component of the Software Development Life Cycle (SDLC) was too little or too late or both, and most often comes back to haunt them. In this post, I have enlisted few guidelines for building secure web applications.
Even the most elaborate application security can fail if a malicious user can use simple ways to gain access to your computers. General Web application security recommendations include the following:
- Back up data often and keep your backups physically secure.
- Keep your Web server physically secure so that unauthorized users cannot gain access to it, turn it off, physically steal it and so on.
- Protect the Web server and all of the computers on the same network with strong passwords.
- Close any unused ports and turn off unused services.
- Run a virus checker that monitors site traffic.
- Use a firewall.
- Learn about and install the latest security updates for the software you use.
- Use event logging and examine the logs frequently for suspicious activity
When your application runs, it runs within a context that has specific privileges on the local computer and potentially on remote computers.
To run with the minimum number of privileges needed, follow these guidelines:
- Do not run your application with the identity of a system user (administrator)
- Run the application in the context of a user with the minimum practical privileges
- Set appropriate groups and permissions (ACLs, or Access Control Lists) on all the resources required for your application. Use the most restrictive setting. For example, if practical in your application, set files to be read-only
- Keep files for your Web application in a folder below the application root. Do not allow users the option of specifying a path for any file access in your application. This helps prevent users from getting access to the root of your server
As a general rule, never assume that input you get from users is safe. It is easy for malicious users to send potentially dangerous information from the client to your application. To help guard against malicious input, follow these guidelines:
- In forms, filter user input to check for HTML tags, which might contain script.
- Never echo (display) unfiltered user input. Before displaying untrusted information, encode HTML to turn potentially harmful script into display strings
- Similarly, never store unfiltered user input in a database
- If you want to accept some HTML from a user, filter it manually. In your filter, explicitly define what you will accept. Do not create a filter that tries to filter out malicious input; it is very difficult to anticipate all possible malicious input
- Do not assume that information you get from the header (usually via the Request object) is safe. Use safeguards for query strings, cookies, and so on. Be aware that information that the browser reports to the server (user agent information) can be spoofed, in case that is important in your application
- If possible, do not store sensitive information in a place that is accessible from the browser, such as hidden fields or cookies. For example, do not store a password in a cookie
Follow these guidelines to access databases securely:
- Use the inherent security of your database to limit who can access database resources. The exact strategy depends on your database and your application:
- If possible use the appropriate operating system users to access the database
- If your application uses anonymous access, create a single user with very limited permissions, and perform queries by connecting as this user
- Do not create SQL statements by concatenating strings that involve user input. Instead, create a parameterized query and use user input to set parameter values.
- If you must store a user name and password somewhere to use as the database login credential, store them securely. If practical, encrypt or hash them.
If you are not careful, a malicious user can deduce important information about your application from the error messages it displays. Follow these guidelines:
- Do not write error messages that echo information that might be useful to malicious users, such as a user name.
- Configure the application not to show detailed errors to users. If you want to display detailed error messages for debugging, check first that the user is local to the Web server.
- Use the appropriate configuration control on the web server to determine who can view exceptions from the server.
- Create custom error handling for situations that are prone to error, such as database access
Sensitive information is any information that you need to keep private. A typical piece of sensitive information is a password or an encryption key. If a malicious user can get to the sensitive information, then the data protected by the secret is compromised. Follow these guidelines:
- If your application transmits sensitive information between the browser and the server, consider using Secure Sockets Layer (SSL).
- Use protected configuration (or encryption) to secure sensitive information in configuration files.
- If you must store sensitive information, do not keep it in a Web page, even in a form that you think people will not be able to view (such as in server code).
- Use the strong encryption algorithms supplied in the appropriate security pack.
An indirect way that a malicious user can compromise your application is by making it unavailable. The malicious user can keep the application too busy to service other users, or if nothing else can simply crash the application. Follow these guidelines:
- Close or release any resource you use. For example, always close data connections and data readers, and always close files when you are done using them.
- Use error handling (for example, try/catch blocks). Include a finally block in which you release resources in case of failure.
- Test size limits of user input before using or storing it.
- Put size safeguards on database queries to help guard against large queries using up system resources.
- Put a size limit on file uploads, if those are part of your application.
Better Session Management
- Do not store any critical information in cookies. For example, do not store a user’s password in a cookie, even temporarily. As a rule, do not store any sensitive information in a cookie that. Instead, keep a reference in the cookie to a location on the server where the information is located.
- Set expiration dates on cookies to the shortest practical time you can. Avoid permanent cookies if possible.
- Consider encrypting information in cookies
Following are the measures one could take to protect from session impersonation.
- Increasing the length of the value of the cookie or session id
For example, if the value of the account cookie consisted of say 32 characters rather than 3, it would take Edward a lot longer to successfully guess Sam’s account number. To be precise, a maximum of (1032 -1) attempts as compared to (103-1). The same applies to session ids.
- Increased randomness in the value of the session token
With a larger potential namespace, the value of the cookie or session id should also be made more random. This may involve the induction of alphabets into the legitimate character set of the cookie or session id and making the values non-sequential and thus harder to guess.
- Protecting the integrity of the session tokens
Appending a message authenticity code, like an MD5 sum of the original session token’s value as sent out by the server, and checking it (for every request) at the server-side to verify that it has not been tampered with, may serve this purpose appropriately. Thus, even if a malicious user modifies a cookie or session id value, it will not pass the data integrity check at the server and be rejected. This ensures that the original session token sent to the user is the only one received by the application for every subsequent request.
- Obfuscating the cookies
Obfuscating the entire cookie set can conceal the composition of the cookies from the user, making it harder if not impossible for a user like Edward to manipulate his cookies and accurately reflect the value of another valid set of cookies. This technique of obscuring the value is more pertinent to cookies as they contain actual authorization data unlike session ids.
- Use of server-supplied session ids
A viable alternative to creating your own session ids is to use those provided by the application servers (as in JBoss). These session identifiers have been thoroughly tested and are known to comply with the basic principles of session id security discussed above.
- Protecting the confidentiality of the session tokens
Apart from manipulating cookies and session ids, attackers may also attempt to sniff the tokens as they traverse the network. Such attacks can be thwarted through the use of appropriate encryption technologies. These include encrypting the entire communication channel using SSL or individually encrypting the session tokens using a tested algorithm.