Lockdown Pt. 3: Are Our Applications Secure Yet?
Tim Kulp | August 18, 2011
Welcome to the conclusion of Lockdown. In the previous two articles we looked at how to determine what we need to secure, how to secure the client side of the application and how to store data in an encrypted format. In this article, we are going to test to see if our security controls work. Any time you are securing an application you need to confirm that your security checks are working. This testing should occur early and often throughout your development process to ensure that as little as possible slips under the radar. At the end of this article you will be able to assess your code for security vulnerabilities as an individual and team.
Just like with any other software activity we need to make sure that our security controls work. The process of assessing our success is called Verification. Verification forces the development team to revisit their creations and assess how to improve what has been built. This process needs to occur throughout the software development process in two actions: Security Code Review and Attack Surface Testing.
Security Code Review
The concept of a Code Review is very interpretive. I have seen development shops who have extremely structured, almost draconian code reviews, and others whose code reviews focus more about caffeine and pizza than code. In general a code review involves another developer reviewing the work of the code author. Often a code review involves the developers talking through the code line by line and discussing what is happening and how it happens. Code reviews in general focus on the following:
- Enforce Conformity: Does the code produced match the coding standards of the organization?
- Ensure Quality: Does the code meet the quality standards of the organization?
- Enhance Clarity: Does the code explain what is happening in a clear manner?
- Education: Junior/Mid-level developers work with more senior developers to learn how to improve their code in a constructive and positive atmosphere.
So then what is the difference between a regular Code Review and a Security Code Review? A Security Code Review specifically analyzes the code for patterns that would lead to flaws or bugs. In “Writing Secure Code” by Michael Howard and Steve Lipner [http://www.amazon.com/Writing-Secure-Second-Michael-Howard/dp/0735617228/ref=sr_1_1?ie=UTF8&qid=1311551016&sr=8-1] the authors propose two activities that make a Code Review a Security Code Review:
- Review for specific insecure patterns by people who know the security domain. If your team is building a web application, then analyze the application for known vulnerabilities. The OWASP Top Ten is a great place to start for which vulnerabilities to watch out for. As part of this analysis, make sure that you have educated people who know how to spot these vulnerabilities examining the code.
- Analyze all assumptions. Sometimes as developers we assume certain conditions will be true. During a security code review these assumptions need to be analyzed to ensure that they do not provide a back door into the application. For example, if you pull a value from a configuration file, what would happen if the configuration file was corrupted by an attacker? Would the system display an error message or totally crash?
Many eyes approach
I have often heard the expression “with enough eyes all bugs are shallow”. While having many people reviewing your code is a good thing, do not leave security bugs to the assumption that someone in the project will catch them. When having others review your code, make sure that someone (or many people) are dedicated to looking for security bugs and know what they are looking for.
How do we do a Security Code Review?
Every line of code produced by your organization should be reviewed but for this article we are going to imaging that the sample application was just dropped on your lap. You were just given a few hundred lines of code and need to review it, but where do you start? Like most of our other activities in this series, the Security Code Review starts with your Risk Analysis (remember back to Part 1). The Risk Analysis will identify the segments of code that have been declared most important by the business. Our Risk Analysis pointed to several features that needed to be secured such as the contractor hour logging system, authentication system and accounting. While we will need to review every line of code, these features will be where we start.
Next we need to build a code review team. This will require people to fulfill at least four roles:
- The Reader: the person who reads the code to the review team. The Reader cannot be the Author.
- The Author: the person who wrote the code so that they can explain anything that is confusing or unclear and learn from the team.
- The Note Taker: the person who records the discussion and takes notes on the changes, points, etc… brought up during the review.
- The Moderator: the person who keeps the meeting focused, ensures that the code review does not turn ugly and follows up on the action items from the meeting.
Outside of these four roles you can have as many people as you want. Work on finding the right mix of people and team size for your Code Reviews. Too few people could miss bugs, too many could wander off topic or result in side conversations.
After building the team and deciding which code to review, now you simply walk through the code having the Reader discuss what the code is doing (not read exactly what the code says but what it is doing). As the Reader progresses through the code, assumptions and designs will become clear. Here is a starter list of some questions to ask about the code:
- What happens if the assumption in this block of code is false?
- Does the code conform to your organization’s standards?
- Does the code enable any attack patterns such as SQL Injections?
- Does the code make sense? Does it use comments to clarify?
- Does/could the code execute data as a command? (i.e. open itself to XSS attack)
Take your time through the code. Remember that this is a learning experience for everyone. Treat it as such and keep the conversation focused on constructive criticism/recommendations. Beware team members that use the forum to discuss “how they would have done it”. Focus on best practices and the standards of your organization to determine “the right way” to do something for your organization, not personal opinion.
Security Testing (a.k.a. Attack Surface Testing)
Once software is built how do you make sure it works how you think it should? While Functional Testing ensures that the system meets the design requirements, Security Testing ensures that the system maintains expected functionality while under malicious use. Security Tests focus on the production of evidence that security goals have been met and that the software does not have common, known vulnerabilities. Often Security Testing is paralleled with Penetration Testing. While the two are similar, Penetration Testing often occurs after deployment of the system. Security Testing needs to be performed throughout the development process to verify that security controls prevent or handle an attack appropriately.
Only test things that you have direct and explicit permission to test. If you test without documented permission you could be facing very serious legal problems. The topics discussed in this section are for you to use on your own code with permission from whoever owns the application, system, etc…
What do we test?
Easy answer to this question: Test everything. The realistic answer to this question is quite different. Unfortunately, software projects have two things that really impede software security: budget and deadlines. As developers/testers we have a budget that we must operate within deadlines we need to meet. While we are bound by both resources and time, attackers are not. They have as much time and money as they wish to dump into breaking our software. So using the realistic approach: We need to test as much as we possibly can and use the Risk Assessment (from Part 1 ) as guidance on features that require the most attention.
Do I need to test code libraries from trusted sources?
Never assume that someone else has reviewed their code from a security perspective. Always test third party libraries as thoroughly as possible. This is one area where open source libraries can be easier to work with as the code is available for complete review. Proprietary libraries can be more difficult to trust as you cannot get in to the code and walk through everything that is happening. In the end, running third party libraries through your security testing procedures will provide you the evidence (or lack thereof) to establish a level of trust in the code.
Getting warm and Fuzzy
Security Testing can be difficult for developers as their focus is on building software, not breaking it. Fuzzy Testing is the specific practice of trying to break your application by attacking any and every entry point into it. While we are going to examine the timeManager.php page from our sample project, try these techniques on every input into the system. This includes forms, query string variables, headers, cookies, Ajax transmissions, and any data that moves around and through your system. Tools like Fiddler (http://www.fiddler2.com) and WebScarab (https://www.owasp.org/index.php/Category:OWASP_WebScarab_Project) make it really easy to track and control HTTP requests coming from and going to your application. These tools allow you to test your backend security controls. We are going to take a more manual approach to testing so we can understand some of the concepts behind security testing. These concepts can be applied using many tools, but you need to have a firm grip on the ideas before you implement them in a tool like Fiddler.
Exercise #5: Building your security testing plan
We are going to test a section that we have not placed any security controls on yet, the Hour Logging process. This process takes hours from contractors and stores them in the database for accounting to bill on. In the Risk Assessment, the business owners have identified this process as an important item to secure so we need to evidence that security controls are in place to keep the data accurate and ensure that data into the system does not disrupt the availability of the system as a whole.
Security testing is comprised of three categories of tests:
- Boundary Tests: testing how the application reacts when input strays from expected boundaries. For example, if the field is only supposed to allow a value of 1 – 10, what happens when I enter in 11?
- Equivalence Partitioning: testing classes of entities to see of the application reacts to different types of input. As an example, if the field is a phone number field, what happens when I enter a name or decimal?
- Attack Patterns: testing known attack patterns such as passing in a SQL Injection string to a field.
Using these three categories we can start building some tests for our hour recording field. We know that the field is supposed to capture hours in a numeric format. These numbers can be a decimal or whole number. From this we can build out our boundary tests very easily:
- What happens when I enter in a number between 0 and 24? This is supported functionality but we need to check it to build our baseline behavior. In theory, this should work.
- What happens when I enter -1? Does it detract overall time?
- What happens when I enter a number greater than 24? Is there an upper limit to what we should be allowed to enter into the hours field? Can someone work more than 24 hours in a day?
- What happens when I put a VERY large number into the field? This is related to checking a number greater than 24 but using very large numbers can lead to issues on the web server or database.
Obviously outside of test #1, all of these can cause unintended functionality to bubble up in our application. Many times developers stop here (if they even test past Test #1). As security testers we need to press on to testing the Equivalence Partitions (sometimes called Partition Classes). Equivalence Partitions examine different types of input as valid and invalid based on the requirements. As we test invalid inputs (also called Partitions) we do not need to test every possible value in the Partition to evidence the system’s reaction to the Partition. As an example, if we take alphanumeric characters as a Partition and enter them into a text field, we do not need to enter every possible combination of Alphanumeric characters to determine how the system reacts to Alphanumeric characters. Here are some sample Partitions we could test in our hour recording field:
- What happens if I enter a person’s name in the hours field? This field should be numeric only.
- What happens if I enter in a decimal value into the field? This should work based on the requirements but what is the decimal length? 2 numbers? 20?
- What happens if we enter a name of a special value such as MAXINT? Does that get interpreted?
A little creative thinking can build out many more Partitions. You can also use the boundaries as types of Partitions but for this article we will keep Partitions and Boundary Values separate.
Finally, we need to specifically check for known vulnerabilities such as SQL Injections, XSS and other attack patterns. You can use the OWASP Top Ten as a starting point for what attacks to check for. The Top Ten provide an excellent starting point for checking your application for vulnerabilities but also works as a quick recipe book for how to test for the various vulnerabilities. When building out your test list, do not just stick to known web attacks but also consider attacks that are not always associated with web applications such as Buffer Overflows. While libraries such as PHP and ASP.NET can reduce the possibility of buffer overflows, never underestimate the creativity and ingenuity of a hacker. Three quick tests that jump out for the timeManager.php page are:
- Is the input field susceptible to SQL Injection using the common ‘ OR 1=1 string?
- Can we pass in an XSS string to affect the page using alert(“123”); as input into the field?
- Can we access the timeManager.php page without logging in to the system?
We were able to quickly build out 10 tests. This is in no way a complete list and can be extended with more Partitions and security checks. In developing your security tests, be as thorough as possible and test as many conditions as you can think of. When you have your tests ready, check every input into your application. As stated before, this is more than the obvious HTML input field. Create a checklist of all the inputs coming in to your application and test against all of them repeatedly to get the most code coverage possible. Provide the list to other testers and ask them to test against your system. The more tests and testers you have, the more likely you will catch bugs in your code. Like the ‘many eyes’ code review practice, many testers can make bugs shallow but make sure you have testers who know how to find security bugs.
Executing your test plan
In Exercise 5 we looked at building out our test plan. Now we need to execute the plan. This can be done manually with every input but there are easier ways. Using security testing tools can facilitate the execution the various permutations of your tests. There are many excellent security testing tools on the market but sometimes you do not have the resources to get an expensive security testing suite. Fortunately, Firefox and Chrome have many great extensions to help you test your web applications for free. These can be excellent tools for testing your applications or as a proof-of-concept to the bean-counters for an enterprise testing suite.
Exercise #6 Using the Hackbar Firefox add-on
One Firefox add-on to help you with Security Testing is Hackbar. This free toolbar allows you to easily manipulate many variables passing through the site, providing an excellent view of various attack vectors you can exploit. Hackbar can be downloaded from the Firefox add-on library [https://addons.mozilla.org/en-US/firefox/addon/hackbar/]. Once downloaded, this tool bar gives you many options for manipulating data flowing through your site. Let us return to our timeManager.php page to execute our tests. First, load the page into Firefox. Make sure Hackbar is loaded and active (if you do not see Hackbar, press F9. This will activate Hackbar.). Login to the Time Manager as a contractor user:
- Username = tkulp
- Password = testing123
Enter in some sample information such as:
- Date = 8/20/2011
- Hours = 5
Press the “Submit Query” button at the bottom of the page. This will send the date and hours to the server for processing. When the page reloads, press the Load URL button on Hackbar.
Notice that the Load URL button loads the page we just sent data to, the data (in either the Query String or POST) and the Referrer (the page the request came from). All of these options are open for your manipulation. To make the data more readable, place your cursor in the Post Data field and press the Split URL button. This will place each name value pair on a separate line.
From here, we are going to test our boundary values on the txtHours field. Highlight the “5” value for txtHours in the Post data field. Replace the 5 with -1 and press Execute. This will submit the POST data back to the server with the changed values.
What happened? The 5 was replaced by a -1 for the day. From here you would check the requirements to see if this is the intended behavior. Hackbar has a lot of other features that we can use for our testing as well. Let’s test what happens when we enter a long decial value (Equivalence Partition for Decimal) into the hours field. Again, highlight the value for txtHours. In Hackbar, select the Other > Useful Strings > Bigger PI. This will replace the value with a long decimal string. Click Execute and see what happens.
Each value can be manipulated using Boundary Tests and Equivalence Partitions to check that the system maintains functionality during various inappropriate inputs. Hackbar also provides functionality to test for web application attacks such as SQL Injections and XSS.
To test for a XSS attack, first select the text of the value you wish to manipulate. Click XSS > alert(XSS) statement. This will set the highlighted value to be a sample XSS string. In this case “String.fromCharCode(88, 83, 83)”.
Using Hackbar you can quickly load and execute the various test cases we built in Exercise 5. After each test, verify that the result matches the application’s requirements and when an error is thrown, that it is handled in a secure manner. Do not forget to try various encodings as well to see if you can sneak by any string based checks (remember Canonical form from Part 2). We barely scratched the surface of what Hackbar can do but this is a good start for executing your test plan against your site.
That was a server side test…
Review, Test, Repeat
I cannot stress enough the value of frequent code reviews and testing throughout the development lifecycle. Regular reviews and testing will bring many bugs to the surface prior to your customer’s ever seeing them. By continuously doing these activities you will produce more secure software and the proof of that security.
Securing your software is a journey not a destination. These techniques will provide a good start but we still have a lot to do. Cyber-villains around the world find new techniques or modifications to existing techniques to break through our security every day. The price of secure software is eternal vigilance on the client and server side of your application. By analyzing your risk, validating/sanitizing input, storing your secrets securely, reviewing and testing your software you can reduce your exposure to attack. Whether you have a mash-up, HTML 5 application or Ajax web site, client side security is a critical necessity not to be overlooked.
About the Author
Find Tim on: