API Security Testing: Think Like a Bad Guy
Join the DZone community and get the full member experience.Join For Free
Article written by John Mueller
You want to check an API to ensure that it’s secure, but just how do you think like a bad guy intent on breaking your API and potentially into your site? Performing the right sorts of API security testing is essential.
Every day it seems like you see another security issue appear in the trade press. In some cases, the news even appears in the national press for the entire world to see, ruining an organization’s reputation in a manner that can cause failure and bankruptcy. A break-in that exposes user information, especially sensitive information such as credit card numbers, is something that every organization wants to avoid. The only way to avoid appearing in the news in the most negative way possible is to ensure the bad guys can’t access your site through one of the most porous borders imaginable: an API used for application development. Here, I’ll outline some common forms of API security testing so that you can create a custom suite of tests for your own API that will help keep the bad guys at bay.
Understanding Essential Security Testing Issues
Testing your API for potential security issues is absolutely essential. However, simply performing tests isn’t enough—you must perform tests that actually simulate the kinds of attacks that an outsider might try. This means that you must think like a bad guy in order to figure out the kinds of attacks that an outsider might try.
You don’t need to go it alone, however. There are ways to think like a bad guy that don’t involve much more than reading the trade press to determine how other organizations have lost their battle to remain predator free, and by avoiding common errors that the bad guys target most often.
Of course, it’s important to know which kinds of security problems to target and test for as part of your API. One of the most important sources of information is the Web Hacking Incident Database (WHID), which lists the following top contenders for hacking.
- SQL Injection (18.87%)
- Cross-Site Scripting (12.58%)
- Denial of Service (8.06%)
- Predictable Resource Location (4.35%)
- Unintentional Information Disclosure (4.35%)
- Brute Force (4.03%)
Using WHID lets you check out the specifics of most incidents by clicking one of the entries in the Quick Downloads section of the page. Using theFull WHID Data on Google Fusion Tables option is probably the fastest way to go. The statistics also tell you that keeping the bad guy at bay is the responsibility of everyone in the organization, but as a developer, you can knock out the two highest contenders just by creating secure applications and fully testing them.
It’s essential to remember that creating secure software, testing it fully, and even performing mock attacks against it will only keep the average bad guy away. If someone is truly determined to break your security, they will. So, part of what you need to take away from this post is that the need for testing is constant, as is the need for vigilance. Looking for the break-in will let you repair problems before they become front page news.
Thwarting SQL Injection Attacks
The SQL injection attack has been around for a long time. The reason that hackers continue to use it is because the technique continues to work. In addition, the technique is extremely simple, so anyone can use it with ease. Let’s say you have the following statements as part of your application:
txtUserID = getRequestString(“UserId”); SQLCmd = “SELECT * FROM Users WHERE UserId” + txtUserID;
The command, SQLCmd, looks harmless enough. However, what if the user inputs a value that will always be true, such as 100 or 1 = 1? The command will now return every entry in the Users database. If the database contains user passwords, the hacker has now gained access to every account in your system. In fact, there are many ways that a hacker can use to inject all sorts of terrible things. For example, the hacker may simply decide to tell the database manager to drop the Users database, relieving you of the burden of maintaining it any longer.
Fortunately, there are relatively easy ways to overcome such an attack. All you really need to do is check the incoming data. If you’re expecting a simple number, then verify the user has input a simple number, such as 100. Don’t allow anything but numeric input. You can also limit the length of the input, the kinds of characters used for the input, and so on. For example, if a field is supposed to contain a name, it shouldn’t contain a semicolon. The previous example could have allowed for dropping the database if the user had typed 100; DROP TABLE Users. Note that the user would have had to include a semicolon to make this approach work.
Another common way to avoid problems is to rely on SQL parameters. In this case, you force the database manager to verify that each entry is of the right type for a particular field. In addition, this technique ensures that the text isn’t executed as code. Here is an example of the same code using SQL parameters:
txtUserID = getRequestString(“UserId”); SQLCmd = “SELECT * FROM Users WHERE UserId @0″; db.Execute(SQLCmd, txtUserId);
A SQL parameter is a number preceded by an @ (at) sign. In this case, you see there is one parameter, @0. When your application callsdb.Execute(), the parameter, txtUserID, is passed along with the command to the database manager.
When creating your test, you must include all sorts of errant input to ensure whatever technique (or combination of techniques) you use actually works. For example, a tester may not think to use punctuation marks as input, but a user might. Try entering control characters by pressing ALT+<Three Digit Number>. For example, ALT+000 will enter a null character that can cause some serious problems. Don’t assume that the database manager or other entity will actually stop an attack—be proactive in your testing.
Dealing with Cross-Site Scripting
A cross-site scripting attack is one in which your page is infected with a client side script that is then downloaded to a victim. The script executes on the victim’s system and does something bad, such as causing the victim to give up valuable information or cause the victim system to act as a zombie. The sequence of events goes like this:
- A bad guy adds a client side script to your page.
- An innocent victim visits your page and downloads the script along with the rest of the page.
- The script executes on the victim’s machine.
- The victim ends up losing data or causing damage to someone else’s system in the bad guy’s name.
Of course, the best way to avoid this whole problem is to keep step 1 of the attack from happening. The problem is that content today is an amalgamation of data from all over the Internet. You probably use code from a lot of different places. So, it’s not always easy to see the interactions that can take place on your page because your page is dynamic.
For example, many pages include a comments section. A hacker can include a reference to a script as part of a comment on your page. Every user who downloads and reads that comment will also download and execute the script. In this case, you can overcome the problem with proper comment moderation.
This article hasn’t even started to cover many of the vulnerabilities that you could face, such as boundary values, data fuzzing, and XML bombs. The picture painted in this article might look bleak at first, but you can overcome a great many of the potential holes in your API by thinking like a bad guy and then taking appropriate steps to overcome the vulnerabilities through a combination of testing, site management, and user training. In addition, you can rely on the features provided by third party products, such as SoapUI Pro, to automatically test for some of the vulnerability (reducing your workload, while keeping your site safe).
Published at DZone with permission of Denis Goodwin, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.