The Basics of Web Hacking: Tools and Techniques to Attack the Web (2013)
Chapter 7. Fixes
■ Hardening your web server to stop the riff-raff
■ How to prevent all flavors of injection attacks
■ Securing the authentication process
■ Serious cheat sheets for XSS and CSRF prevention
■ Preventing SET-based attacks: user education is your only chance
While exploits and payloads garner the most attention from the hacking community, very few of you will get to play the role of the hacker without having to also consider how to fix the vulnerabilities.
Most professions that involve ethical hacking also require specifying and implementing mitigation strategies to help prevent the attacks in the future. Just as our approach targets the web server, the web application, and the web user, it also includes the mitigation strategies that can help fix this mess.
These are best practices developed by a wide audience and sources over several years, but the key to successfully fixing and preventing these attacks is to actually implement these strategies fully.
Web Server Fixes
There are several mitigation strategies to best protect against web server vulnerabilities from a wide range of reputable sources. The scary thing is that some of these mitigation strategies are well over 10 years old and are still 100% applicable to securing your web server. The even scarier thing is that these easy-to-follow precautions aren’t being followed by enough practioners!
There are three mitigation strategies directly from the OWASP Top 10 that I believe are sound advice to best protect your web server. If a bunch of web application security professionals can come up with these, it’s my hope that all web server administrators agree these are a good idea. Although these security strategies have been beat to death, I will list them here again in hopes that even a couple of web server administrators will heed the advice.
■ Develop a repeatable hardening process that makes it fast and easy to deploy another environment that is properly locked down. Development, test, and production environments should all be configured identically. This process should be automated to minimize the effort required to set up a new secure environment.
■ Develop a process for keeping abreast of and deploying all new software updates and patches in a timely manner to each deployed environment. This needs to include all code libraries as well, which are frequently overlooked.
■ Consider running scans and doing audits (internal and external penetration tests) periodically to help detect future misconfigurations or missing patches.
Generic Error Messages
Another important aspect of web server vulnerabilities is information leakage, also known as verbose error messaging. When a web application fails (and it will undoubtedly fail), it is critical for the web server to not to give up sensitive information to the hacker that can be used for a more detailed attack. Some of the best sources for social engineering attacks come directly from information gathered via web application error messages thrown by the web server. You will often hear advice to use generic error messages instead. This style of error messaging has given web server administrators an unexpected creative outlet as shown in Figures 7.1 and 7.2 error message pages.
FIGURE 7.1 Twitter’s “Fail Whale” error page that started the creative error message page movement.
FIGURE 7.2 Generic 404 error code landing page.
While these pages, and thousands of other pages created in the same vein, are funny and cute, they also do a tremendous job of not divulging additional information to would-be hackers. It is not even required to let them know what error occurred (404 vs. 503, for example). It’s best practice just to say, “Something went wrong. Try again later” and leave actual technical details in the dark. As you know, it’s actually very easy to retrieve the error code from such a situation by using an intercepting proxy, but a generic error page is at least one layer of defense that you can use as a start to a layered security, also known as defense in depth, model. To better control the verbosity of your web application’s error messages (including the HTTP status codes), consider the detailed advice from OWASP’s Development Guide, Testing Guide, and Code Review Guide for your specific development and web server environments.
Web Application Fixes
Unfortunately, just like the best practices for securing the web server, the web application mitigation strategies are not implemented as widely as they need to be. OWASP’s Enterprise Security Application Programming Interface (ESAPI) is a great project that includes a long list of libraries that help secure the web application. These libraries are designed to make it easier for programmers to retrofit security into existing applications as well as a solid foundation for new development. The Microsoft Web Protection Library is a collection of .NET assemblies that also helps protect web applications from the most common attacks. It is another great resource and is available at http://wpl.codeplex.com/.
These mitigation strategies all tie together to help protect against injection attacks. The programming environments that most web programmers are using today also implement many of the ideas presented in this section.
1. Use parameterized queries: This is the oldest advice to battle SQL injection where placeholders (think: variables) are used to store user input before it is acted on by the SQL interpreter. This prevents the hanging quote problem because the SQL syntax isn’t being dynamically generated in the same fashion. An attacker’s attempt to close off the SQL statement would be useless without having the ability to dictate what portions of the prewritten SQL actually executes. This idea of using a placeholder also allows further processing to be done to the user’s input before being passed onto the SQL interpreter. The further processing is usually the two mitigation strategies discussed below. Please realize that parameterizing a query is NOT the same as using parameters in SQL-stored procedures. Stored procedures that make use of variables can most definitely have SQL injection vulnerabilities in them just as a query can!
2. Escape malicious syntax: This is done in server-side code before user input reaches the SQL interpreter, so all malicious characters have been identified and suppressed to be benign. OWASP’s ESAPI includes many powerful and popular encoding and decoding functions to perform this escaping in its Encoder interface which contains several methods for decoding input and encoding output so it’s safe to pass onto an interpreter. ESAPI also makes use of canocalization, which reduces user input to its simplest format before being acted on; this ensures no malicious characters slip past the safety checks.
3. Make use of stored procedures: These are similar to prepared statements and parameterized queries but differ by existing on the database server rather than in code. Stored procedures allow for central code management and help reduce the attack surface. All stored procedure code is declared and processed on the database and the application only passes parameters to the stored procedure to process the SQL statements.
4. Remove unnecessary functionality on your database server: For example, Microsoft’s SQL Server includes the xp_cmdshell stored procedure that allows system commands to be invoked from the database. Unless you have a definitive reason enable this feature, it should most certainly be disabled to help protect your system and data.
5. Encrypt sensitive data: Too many times we hear of data breaches, which are bad enough in itself, but the problem is exacerbated when the data harvested are clear text. Sensitive data such as passwords, credit card information, social security numbers, and related data items need to be encrypted during storage as well as when it’s in transit.
6. Use whitelist validation for input including canonicalization: These are two main ideas related to sanitizing user input before it reaches the database interpreter. Whitelisting is simply the use of only known-good values. A perfect example of whitelisting is selecting what state you live in. If you provide the user a textbox, he can type whatever he wants in that textbox—including malicious input. A whitelist would be implemented by using a dropdown box that only includes the two-letter abbreviation for each of the 50 states. There is no other way to select a value for the state. Of course, a responsible web application programmer will also make sure that the value received for this parameter is one of the 50 expected values to ensure it hasn’t been edited in a proxy before reaching the web application on the web server. Canonicalization is the processing of taking user input and “boiling it down” (normalizing it) to its simplest form. This is especially useful in injection and path traversal attacks to fully understand what the attacker is attempting. The Validator interface in ESAPI defines the methods for canonicalizing and validating untrusted input, but is only appropriate to use when the application implements a whitelist approach to processing input.
7. Use regular expressions: A regular expression is an object that performs pattern matching on user input and can be assigned to individual controls (i.e., textbox) on a web form. A majority of programming languages have prebuilt instances of regular expressions such as RegularExpressionValidator in .NET. Regular expressions can help save time and reduce human errors when trying to create sanitization routines. A really great resource for help on implementing regular expressions is available at:http://regexlib.com/CheatSheet.aspx.
8. Implement a lease privilege model on your database: This simply means the credential level of the accounts used to access the database need to be tightly restricted and monitored. It is not wise to never allow an administrator level account access the database. You can always use different accounts for different types of database interactions. For example, you can use different accounts for reading data versus creating new records in the database.
9. Use your development environment’s API for system-level calls: Although there is a strong argument to never allow user input to be processed by an operating system directly, if you must do it the best mechanism is to use preconfigured application programming interfaces (API). An API is the safest way to interact with the operating system command interpreter as they do not allow metacharacters and other malicious input from users. The APIs will only start a process based on name and command-line parameters instead of allowing an entire string and supporting chained commands. This limits the possibilities of attack breaking out of the expected input values.
Broken Authentication And Session Management Fixes
To me, this is the most frightening vulnerability that web applications currently face because everything that a web application is charged to do relies on authentication and session management. Without these two core pieces of functionality, there are no transactions or user personalization to anything we do on the web. We’d be back to the mid 1990s where everything was just static HTML files. The most common error that programmers make is to not use the authentication and session management capabilities inherent in the web server and development environment. You will often see the advice “don’t roll your own crypto.” This also holds true for session management. The Application Security Verification Standard from OWASP has extensive checklists for both authentication and session management security. These are both definitely worth your investigation if you’re responsible for securing web apps.
2. Verify that all password fields do not echo the user’s password when it is entered, and that password fields (or the forms that contain them) have autocomplete disabled.
3. Verify that if a maximum number of authentication attempts is exceeded, the account is locked for a period of time long enough to deter brute force attacks.
5. Verify that all authentication controls (including libraries that call external authentication services) have a centralized implementation.
6. Verify that all authentication controls fail securely.
7. Verify that the strength of any authentication credentials is sufficient to withstand attacks that are typical of the threats in the deployed environment.
8. Verify that all account management functions are at least as resistant to attack as the primary authentication mechanism.
9. Verify that users can safely change their credentials using a mechanism that is at least as resistant to attack as the primary authentication mechanism.
10. Verify that reauthentication is required before any application-specific sensitive operations are permitted, such as email account changes, profile updates, and modifying stored payment information.
11. Verify that after a configurable period of time, authentication credentials expire to ensure proper changing of passwords. You can also limit how long each administrative session persists on the application to help decrease session attacks against these powerful accounts.
12. Verify that all authentication decisions are logged.
13. Verify that account passwords are salted using a salt that is unique to that account (e.g., internal user ID, account creation) and hashed before storing.
14. Verify that all authentication credentials for accessing services external to the application are encrypted and stored in a protected location (not in source code).
15. Verify that all code implementing or using authentication controls are not affected by any malicious code. This is especially important when you integrate third party code into your environment. It’s very difficult to audit code that you didn’t write and is only available in a packaged module from an outside source.
1. Verify that the framework’s default session management control implementation is used by the application.
2. Verify that sessions are invalidated when the user logs out.
3. Verify that sessions timeout after a specified period of inactivity.
4. Verify that sessions timeout after an administratively configurable maximum time period regardless of activity (an absolute timeout).
5. Verify that all pages that require authentication to access them have working logout links.
6. Verify that the session id is never disclosed other than in cookie values, particularly in URLs, error messages, or logs. This includes verifying that the application does not support URL rewriting of session cookies when possible.
7. Verify that the session id is changed on login.
8. Verify that the session id is changed on reauthentication.
9. Verify that the session id is changed or expired on logout.
10. Verify that only session ids generated by the application framework are recognized as valid by the application.
11. Verify that authenticated session tokens are sufficiently long and random to withstand attacks that are typical of the threats in the deployed environment.
12. Verify that cookies which contain authenticated session tokens/ids have their domain and path set to an appropriately restrictive value for that site.
13. Verify that all code implementing or using session management controls are not affected by any malicious code.
ESAPI also has two appropriate interfaces that deal with authentication and session management to further provide protection against these attacks. One is the Authenticator API that includes methods for generating and handling session identifiers and account credentials. The other API is User that securely manages all the variables associated with the state of a user account.
Path Traversal Fixes
Mitigating insecure direct object references vulnerabilities is straight forward even though automated scanners will not detect the flaw. Manual review of the code and manual requests of unauthorized resources is the easiest way to check for the vulnerability. Preventing this attack boils down to making sure each user is authorized to request only his resources and that all reference to objects are indirect. These simply means to not use the database key for the resource identifier displayed to the user (or sent as a parameter that could be manipulated) and instead use a behind-the-scenes mapping procedure of what these values actually mean to the back-end database. This is another great use of dropdown boxes to restrict the possible values that a user can select. Another great example of this is to use a GUID instead of a filename to download a file. So instead of a download link like http://somesecuresite.org/download.php?file=EpicInfo.txt, the application could use a link such as http://somesecuresite.org/download.php?file=53636f747-4205768697-46520465457. Although unpleasant to read, it does prevent trivial guessing of web resources. It’s also much safer because the application would perform the servers-side mapping of this GUID to retrieve the resource—after an authorization check on that user, of course!
ESAPI has two interfaces that can help a great deal in preventing insecure direct object reference attacks. The Access Reference Map API performs this style of behind-the-scenes mapping with random strings to help protect database keys and filenames from being exposed to hackers. This is also a worthy defense against CSRF. The Access Controller API includes methods dedicated to controlling access to URLs, data, files, services, and business functions. This API works closely with the Authenticator API to retrieve the access level and permissions of the requesting user.
Instead of blacklisting character sequences, you can compare the path supplied by the input with known-good paths. In PHP, for example, you can use the realpath() method, which will turn any provided path into an absolute path rather than a relative path by resolving ../ type sequences. You then compare the returned path to the known-good paths to ensure the user is not trying to break out of the expected directories. This same functionality is available in C with realpath(), in Java with GetCanonicalPath(), in .NET withGetFullPath(), and in Perl with abs_path().
Web User Fixes
As the most widespread web application vulnerability is existence at the time of this writing, XSS has no shortage of mitigation strategies to help prevent it. CSRF and technical social engineering attacks are just as noteworthy when it comes to preventative measures. The key is to understand which of these approaches to use, when to implement them during the software development lifecycle, and what ongoing maintenance is necessary to make sure the safeguards remain applicable.
There are several best practices to best combat CSRF and it’s just as difficult to prevent XSS because the user is involved heavily. There is no amount of safeguards that can be put in place to ensure a user won’t click a link or visit a site, but developers can ensure their applications are free of CSRF vulnerabilities.
The XSS Prevention Cheat Sheet
This is the de facto standard to consult when trying to prevent XSS vulnerabilities in your web applications. All the other XSS mitigation strategies that are listed in this section are linked directly off of the XSS Prevent Cheat Sheet. The Cheat Sheet treats an HTML page like a template, with slots where a developer is allowed to put untrusted data. Putting untrusted data in other places in the HTML is not allowed. In a way, this approach treats an HTML document like a parameterized database query; the data are kept in specific places and are isolated. There are nine rules that are included in the XSS Prevention Cheat Sheet.
1. Never insert untrusted data except in allowed locations
2. HTML escape before inserting untrusted data into HTML element content
3. Attribute escape before inserting untrusted data into HTML common attributes
5. CSS escape and strictly validate before inserting untrusted data into HTML style property values
6. URL escape before inserting untrusted data into HTML URL parameter values
7. Use an HTML policy engine to validate or clean user-driven HTML in an outbound way
8. Prevent DOM-based XSS
9. Use HTTPOnly cookie flag
Input Validation Cheat Sheet
The Input Validation Cheat Sheet is a great place to start when tackling how to best implement input validation. There are two basic ideas when dealing with input validation: whitelist and blacklist. Whitelist is when you only allow known values to enter the application. Just as important as restricting the input, the parameter is then checked on the server-side to ensure the value hasn’t been altered in an intercepting proxy. Some of the most popular web development frameworks already have this type of functionality built-in; .NET’s event validation for example: http://msdn.microsoft.com/en-us/library/system.web.ui.page.enableeventvalidation.aspx.
Blacklist validation is the exact opposite where the filter looks for known malicious characters in the user’s input and strips away any offending input. For example, an anti-XSS blacklist filer is surely going to catch the < script> </script > tags. The battle becomes when hackers get innovative in their attempts to circumvent a blacklist. It is always the preferred choice to use whitelist input validation where possible.
One caveat about input validation: security professionals that are the best at implementing input validation have a strong understanding of regular expressions (regex). Don’t run in fear! But be aware that strong input validation does rely on regular expressions.
Code Defenses For XSS
There are several approaches during the development process that implement what the cheat sheets prescribe and are a great start to prevent XSS attacks. Some of the best examples include the following.
■ Encode relevant characters such as <, >, &, ‘, and “. In ASP.NET you can use HttpUtility.HtmlEncode and HttpUtility.UrlEncode to assist with this step. HttpUtility.HtmlEncode turns characters like ‘>’ into ‘>’ preventing the browser from executing it as code, instead displaying it as HTML. HttpUtility.UrlEncode works similarly, except on any relevant input instead of just HTML characters.
■ You can also HTML escape these values where < and “ would be < and ". C# has a built-in function (Server.HTMLEncode) that performs HTML encoding. Check out a very succinct description of these two .NET strategies at:http://blog.diegocadenas.com/2008/03/serverhtmlencode-vs-httputilityhtmlenco.html.
■ PHP has two functions that perform HTML encoding (tmlspecialchars() and htmlentities()), which accepts two parameters: the string to inspect and the string of allowable values, so it’s very simple to implement!
Browser Defenses For XSS
There are a number of add-ons and plug-ins for almost every browser that will help mitigate XSS vulnerabilities. But be aware that none of them are a silver bullet to keep you completely safe from all flavors and variants of XSS.
■ Internet Explorer’s XSS Filter: Microsoft’s browser filter behaves in much the same way that NoScript does. It inspects all requests and responses traveling through the browser and makes a judgment on if they are malicious XSS or not. Malicious scripts are blocked, the user is notified, and the page is rendered without the potentially damaging script as part of the source code. More information is available at: http://windows.microsoft.com/en-US/internet-explorer/products/ie-9/features/cross-site-scripting-filter.
■ Mozilla FireFox’s Content Security Policy is a web server configuration approach to add more robust features to the content sent to the browser. Think of it as the Same Origin Policy on steroids. You just have to enable the returning of the X-Content-Security-PolicyHTTP header on the web server. Browsers that aren’t compatible with this simply use the same origin policy. More information is available at https://developer.mozilla.org/en-US/docs/Security/CSP/Introducing_Content_Security_Policy.
■ Chrome’s Anti-XSS Filter and other security offerings are harder to pin down. The browser does include an anti-XSS filter, but details are more difficult to track down compared to those listed above. Chrome also makes use of sandboxing each tab as a separate process and auto-updates itself (if configured to do so). More information is available at https://support.google.com/chrome/?hl=en.
The CSRF Prevention Cheat Sheet
The OWASP community has produced a great resource, The CSRF Prevent Cheat Sheet, to prevent CSRF attacks. This cheat sheet not only includes best practices to mitigation CSRF vulnerabilities but also debunks common myths as to what can be used to prevent CSRF. The CSRF Prevention Cheat Sheet includes details on how to implement the Synchronizer Token Pattern that requires the generating of random challenge tokens that are associated with the user’s current session. By including a challenge token with each request, the developer has a strong control to verify that the user actually intended to submit the desired requests. Inclusion of a required security token in HTTP requests helps mitigate CSRF attacks as successful exploitation assumes the attacker knows the randomly generated token for the target victim’s session. This is analogous to the attacker being able to guess the target victim’s session identifier, which is very unlikely to happen!
More CSRF Defenses
There are additional approaches to protecting your users against CSRF that you can follow such as the following list.
■ Add tokens (anti-CSRF token) to each request that are tied to a particular user’s session. By doing so, the application can ensure that each request is indeed coming from that user and not somewhere else. The challenge tokens are often unique to the user, but can also be unique by request.
■ Use only POST requests and include a random value independent of the user’s account. This random value should also be set as a cookie for the user when they first visit a site. That way even if an attacker tries to submit a form on behalf of a user, they will not be permitted to as the post request value does not match the cookie on the user’s machine.
■ Mandate a timeout of active sessions as CSRF is used against an authenticated user to perform an action. A quicker timeout lowers the probability of an active user being victimized.
■ A relatively new idea is to implement a proxy between the web server and the application to act as a firewall-type device to scan all incoming requests. If the request does not include a session ID, it would be allowed through as it would not be attempting to complete an authenticated request. If a session ID was present, the value of session ID would be compared to currently valid session IDs. This is similar to adding additional tokens but allows for scanning of both requests and responses from the application and allows for modifications to be made to those that are determined to be attacks.
Technical Social Engineering Fixes
The good news is that this section is going to be short and to the point. The bad news is that it’s because there’s not a lot you can do to prevent the user attacks we covered in this chapter. Certainly making sure your application is free of XSS and CSRF vulnerabilities will take the sting out of some of the attacks, but others will run perfectly fine on a fully patched computer. That’s truly scary!
So while it’s always a good idea to encourage users to stay current on patches and updates from operating system and software vendors, there’s an entire class of attacks that will still exploit them. One good mitigation strategy for users is to not click on links in emails from people you don’t know, don’t visit websites that you don’t trust, and when faced with a “do you want it to run?” pop-up box in your browser, always click No. But that’s the same advice that has been given for over a decade and we are still getting exploited.
So this, in a nutshell, is the battle that security professionals now face. How to educate the mass population of web users to protect themselves against these attacks? How to reach out to the actual users of our web applications, and show them the right and wrong way to live online? Because as long as there are uneducated users who will click on a link, we will always have web user attacks that can’t be stopped.