Can your API be hacked? As more and more APIs are driving websites and businesses, it's more important than ever to make sure yours is secure. These guidelines will give you a starting point to testing your web services for security vulnerabilites.
We've seen it in the news a hundred times now: a data breach at XYZ Corp leaks thousands of user credentials, or valuable data was lost in a malicious hack. Surprisingly, API security testing is still not a top priority for a lot of teams running publicly accessibly web services.
I think we would all agree that it's beneficial to find vulnerabilities in our own APIs before someone else does. While ideally the application is designed correctly to prevent well-known exploits, having API security testing and monitoring in place can prevent a lot of trouble.
In this post, I'll take a dive into some well-known attack vectors common in APIs and web services, and provide guidelines for starting to test them in your own applications:
- Why you need API security tests
- Methods of testing API security
Why you need API security tests
An exploit in a web service can be detrimental to a business or even a small project owner who's releasing their work into the public. More and more of these APIs are being used to access sensitive data that, if accessed by a hacker, can put the business and other users of that API in risk. Here's a few famous examples:
It's widely accepted these days that
httpsshould be used for all transactions on the public internet. Instagram did not follow this rule of thumb and was susceptible to account takeovers by intercepting unecrypted
In October of 2015, TalkTalk announced that customer names, addresses, and other sensitive information had been stolen during a data breach. It appears this breach was possible via an SQL injection attackfrom the TalkTalk website.
Methods of testing API security
Security issues can manifest in many different ways, but there are many well-known attack vectors that can easily be tested. This type of testing requires thinking like a hacker. That is, learning the system as a whole and looking for openings other people missed.
Without testing the security of our applications, we can't understand the risks to those applications or even begin to protect them from potential attack.
As with all good API testing, a little bit of creativity, spontaneity, and knowledge about HTTP web services is the key to finding and fixing security bugs. There are many well-known attack vectors that are a good starting point for testing, so let's go over a few:
Fuzz testing is one of the more common and simple ways to test for vulnerabilities in a web service. The OWASP organization defines it as follows:
Fuzz testing or Fuzzing is a Black Box software testing technique, which basically consists in finding implementation bugs using malformed/semi-malformed data injection in an automated fashion.
This is a great starting pointing for implementing securty tests for
your API because it doesn't require advanced tooling or programs and
can be done using command line tools like
curl. Simply put, send
unexpected values to your API and see if it breaks. Use these
examples as a good starting point for fuzz testing your application:
Fuzz testing numbers
When an API expects numbers as input parameters, try sending values like 0, negative numbers, and very large numbers. A badly coded application will be reliant on some specific format, so this is a good way to find bugs.
Fuzz testing strings
One of the most common examples of fuzz testing strings, is to send SQL queries (discussed more in the Command injection section) in a parameter where the API is expecting some harmless value. Obviously, an API shouldn't run any SQL sent in a request.
Other types of tests here would be to send very large strings, (un)escaped strings, and everything single listed in this Big List of Naughty Strings.
Other types of fuzz testing
Fuzz testing can be done on any sort application, whether it's an API or not. Fuzz testing a user interface, for example, could consistent of entering various random values into HTML input fields and ensuring validation and submission is correct.
In the case of APIs and web services, an injection flaw occurs when a web application passes information from an HTTP request through to another command, like a system call, database command, or a request to an external service.
As a basic example, say you send a request to an API, and within one
of the query parameters, you have the following command:
-rf /. If the API does not properly sanitize or validate that data
within that parameter, it could potentially run that command,
destroying the contents of the server.
Obviously, command injection can be one of the most detrimental vulnerabilities for any web service. Here's a couple of ways to test for these vulnerabilities:
Operating system commands in API requests
A good starting point is to determine the operating system the API runs on, generally Linux or Windows. From there, attempt to send commands within the API request that would run on that OS. Take the following case where an API request deletes a file by name:
$fn = $_GET['filename']; system("rm $file")
If a user's request sends a malicious command in the
filenameparameter, it would be executed:
This example is from the OWASP wiki
As a software tester, it's good to familiarize yourself with different operating systems and commands so you can get creative in in these tests.
SQL in API parameters
In a similar fashion as operating system command injection, SQL injection is another common type of vulnerability that happens when unsanitized data from an API request is used in a database command.
Modifying the example above slightly, imagine an API with the following code:
$name = $_GET['username']; runDbTransaction("UPDATE user SET username=$name WHERE id = ...")
If the input data from the API isn't properly validated, then an attacker can run any database command just by making an API request! These are perhaps the most destructive types of vulnerabilities for any web service.
Testing for command injection can sometimes be difficult to measure because whether or not the command was run might be opaque to the user. In any case, destructive commands can result in the web service going down, data being deleted or sent to a third-party, and exposed user credentials. Testing for command injection is one of the more important security tests to do.
(Un)authorized endpoints and methods
All web services should implement some sort of authorization. When an API exposes any sensitive data and allows users to call destructive actions, it's even more important that it authorizes every single request before processing.
If you have some actions that require authorization and others that do not, it is much safer to deny by default and override any actions that don't require a permission.
As Cade and Daniel note in that article, a great rule-of-thumb is to Deny by Default. This means that if your API has some resources that should require authorization and others that don't, the best default behavior in your application should be to deny requests.
Along with checking authorization, testing various HTTP methods is a great way to find possible exploits. Let's go over a few to ways test these two topics:
Test for authentication on all endpoints
One of the most basic ways to test your API's security is to set up automated tests for a few scenarios:
Test authorized endpoints without authorization
If your API has an endpoint, say
/users, that requires an authenticated request, set up checks that do not use authentication and ensure the service responds with the proper message and status code.
Test with incorrect authentication
More simply, try and access authorized endpoints with incorrect tokens or credentials.
Test user privileges
When a web service has different levels of users, like members and admins, set up tests that ensure that lower-level privileges can't access higher-level privileges.
Test unhandled HTTP methods
APIs that talk over HTTP have several different methods, or verbs, that are used for retrieving, saving, and deleting data. Some web servers have insecure defaults for unsupported HTTP methods. Verbs that aren't explicitly included may be given access by default. Here's a few ways to set up security tests for these cases:
HEADto bypass authentication
Find pages or endpoints in your web service that require authentication or authorization, and make a request using
GET. If the service is secure, you should get a
405 Method Not Allowedor
501 Method Unimplementedresponse. If you get a
200 OKresponse, you've disovered a vulnerability.
For a more in-depth example, read this awesome post on OWASP.
Test arbitrary HTTP methods
The HTTP specification lists a few supported methods that web servers should handle. But since an HTTP request is just text, it's it's possible to send an arbitrary method in the request that's not in the specification, like
Make requests to your API using a random method and ensure you get a proper response back from the API. If a
200 OKresponse is returned from any of these requests, further investigation is warranted.
Parameter tampering is a type of exploit that manipulates parameters
sent in an API requests by taking advantage of backend validation
errors. A common example of this is in forms submitted by a user in
web applications. Forms that use
type="hidden" inputs should always
be tested to ensure the backend server correctly validates them.
Imagine a website that has a checkout form with the following input:
<input type="hidden" name="price" value="100.00" />
Hypothetically, if a user can open their browser, change that input
1.00, and submit the form successfully, then
the service is vulnerable to parameter tampering (and they just saved
a ton of money!).
Kate Paulk puts in nicely in her post about security testing for non-security testers:
For any kind of web application where people are entering data and expecting their data to be secure, it's crucial to make sure the application checks the user has access rights when the data is displayed, and again when it's saved.
I highly recommend reading through that article's examples if you're wanting to learn more (after you're done with this one, of course!). So let's go over a few ways to test for this in your web service:
Modifying input fields in a web form
Extending the example above, if your web app uses forms with hidden input fields that are read by the backend, you should test that they are correctly validated. This can generally be done in any web browser by opening up the dev tools console, finding the input elements, changing the value, and submitting the form.
Modifying query parameters in API requests
Changing parameter values isn't specific to web forms. API requests should be tested directly as well. Test various combinations of invalid query parameters and ensure the API returns correct error codes. This is especially important on descructive endpoints and actions, like
These are just a few of the ways you can start improving your API security with automated testing. Creativity is perhaps one of the most important characteristics of a good test-suite, so don't be afraid to try something new. After all, it's better for you to find an issue before an attacker.
Below I've gathered some additional resources for continued learning on API and web service security. It's a vast an interesting topic with a lot of great tutorials and papers.
- The Basics of Web Application Security
- API Security Checklist
- Best Practices for API error handling
- Hack Your API First
- Web Application Security Testing 101
- Security Considerations in JSON APIs
Have you found any vulnerabilities in your API, have a question, or want me to add something to the article? Reach out on Twitter or send me a message! I'd love to hear how you implemented these tips.
:: Cody Reichert
PS - a note on ethics
These types of tests should only be done on web services you control, or web services in which you're participating in a bug bounty. Some of the ideas in this post can be destructive to an API, so please keep in mind which service your testing and who might be upset if something is deleted.
The easiest way to test and
monitor your web services
Reduce bugs in web applications by using Assertible to create an automated QA pipeline that helps you catch failures & ship code faster.Get started with GitHubSign up for free