Many applications provide a services layer (to other applications, to a presentation layer, etc.). Or, they consume services exposed by third-parties (not necessarily trusted). A REST model is a simple, widely-used way for designing such service layers.
This article is about REST security issues, including:
We will center our discussion around Java-based REST frameworks. However, many concepts are also valid for other implementation languages, such as PHP, .Net, JavaScript, Python, Ruby, etc.
REST (REpresentational State Transfer) is an architectural style to build services on top of the Web. REST simplifies interaction with a web-based system by replacing complex HTTP requests with simplified URLs. A REST-enabled application consists of resources (“nouns“), each responding to different “verbs” (for example, HTTP methods like GET, POST, PUT, DELETE…) over well-defined URLs (typically HTTP/HTTPS URLs). These URLs map entities in the system to endpoints. Each REST request/response to a resource uses one or more resource representation. These are typically negotiated between client and server, for example, using Accept and Content-Type HTTP headers. The most common representation formats include JSON, XML or raw text. Many other alternatives like YAML, Atom and HTML are also used.
In the Java/J2EE platform, a standard Java API for RESTful Web Services (JAX-RS, JSR 311) is the most common API for building and consuming REST services. There are many widely used implementations, like Jersey, Apache CXF, Restlet, or RESTEasy.
Any services architecture is inherently “recursive”: services could aggregate information resources fetched from other services. A service vulnerability is not only due to implementation defects committed by service developers: the REST framework itself has much to tell us.
REST typically uses HTTP as its underlying protocol. This raises the usual set of security concerns:
In a REST architecture, end-to-end processing implies a sequence of potentially vulnerable operations:
The layered sequence of transformations in REST frameworks means that a single weak link in the chain could make your application vulnerable.
The act of extracting parameters from HTTP message and getting resource URLs could be vulnerable to injection attacks. These attacks can change the semantics of the intended resource. Two classes of attacks are relevant here: HTTP parameter/path pollution (HPPP) and Server-Side Request Forgery (SSRF). Remember that our attacker has full control over the HTTP request or the HTTP response.
In an HPPP (HTTP parameter/path pollution) attack, a parameter is used to compose the resource URL which prepares a REST request for a resource (or generates an embedded link). The attacker may either alter the path or add/overwrite unexpected parameters in the “query string”. Additionally, REST frameworks may use a parameter (like _method) to allow the specification of a REST verb different from the incoming HTTP method, so a GET request could be interpreted as a PUT operation. An attacker may change the semantics of the REST resource URL!
with the following code:
String entity = request.getParameter("entity");
String id = request.getParameter("id");
URL urlGet = new URL("http://myserver.com/rest/" + entity + "?id=" + id);
// perform a REST query using urlGet
An attacker may provide the following parameters:
entity=../admin/users/user/badGuy
id=x&_method=PUT&isAdmin=true
So the operation that the application executes is like this:
GET url http://myserver.com/rest/../admin/users/user/badGuy?id=x&_method=PUT&isAdmin=true
Which is probably interpreted by myserver.com REST endpoint as this:
PUT /admin/users/user/badGuy?id=x&isAdmin=true
In a Server-Side Request Forgery (SSRF), the vulnerable application composes the URL using data from the HTTP request that could also affect the scheme, host and port parts of the URL. In this case, the vulnerable application acts as an open proxy/relay for the attacker. Remember, the wish for an attacker is to gain access to an interface that allows access to internal resources.
Remember that browsers impose at least a Same-Origin Policy (SOP) to control cross-site reads, but HTTP clients (and REST stubs/proxies) do not enforce any kind of SOP. This is your business.
Of course, if your app is so naive as to use untrusted input directly as the prefix part of a resource URL to be retrieved, SSRF is open. But there are other enablers for SSRF. Some REST frameworks provide proxies (RESTlet Redirector) for server-side redirections that may use an input URL directly. XML External Entity vulnerabilities (more on this later) may force unintended connections to internal URLs. And when the attacker has control over the target URL, you may hear really loud laughter across your office window!
The logical entity representing the current state is mapped to its representation (marshaling or unmarshalling), which often means converting between a Java object (e.g. a POJO) and the representation text (like XML or JSON). This marshaling/unmarshalling could be the weak link in the chain. For example, under XML representation, either an XML parser, or a higher-level XML marshalling framework (like schema-free XMLEncoder/XMLDecoder or XStream or schema-based JAXB) is used.
There are at least three kinds of potential issues with XML in Java REST frameworks:
– XML entity injection attacks, either an XML entity expansion denial-of-service (“billion laughs” attack) or as XML external entity injection (XXE attacks). Common Java XML parsers use an insecure default configuration for these threats, and the REST framework may not be performing adequate configuration of the underlying parser. This opens the playground for bad consequences like denial-of-service, code injection, sensitive file disclosure, internal network port scanning…
Well-known examples of such XML-based attack vectors are:
<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>
<!DOCTYPE root [
<!ELEMENT root ANY >
<!ENTITY windowsfile SYSTEM "file:///c:/boot.ini">
]>
<root>
<sometag>&windowsfile;</sometag>
</root>
<!DOCTYPE foo [
<!ELEMENT root ANY >
<!ENTITY unixfile SYSTEM "file:///dev/random" >
]>
<root>&unixfile;</root>
The JAXP API for XML parsers in Java recently adopted a more robust default configuration.
If the REST framework (or REST application) uses a generic Java-XML marshaling API, like JDK XMLEncoder/XMLDecoder or XStream, that needs to include method and constructor invocations during XML unmarshalling to Java objects, a potential Java code injection could be leveraged by the attacker.
The following XML attack payload for XMLDecoder will overwrite a sensitive file. Similar to new PrintWriter(“/myapp/WEB-INF/sensitive.dat”).println(“hacked!”) . The bad guys could install a JSPShell page, modify configuration files, deface web contents, etc.
<java>
<object class="java.io.PrintWriter">
<string>/myapp/WEB-INF/sensitive.dat</string>
<void method="println">
<string>hacked!</string>
</void>
</object>
</java>
The good news is that newer versions of some Java REST frameworks have patched this. But often a specific configuration on XML parser and XML marshaling components should be performed by the REST application. For example, Jersey fixed this bug (“All Jersey web services that accept XML are vulnerable to XXE attacks“, bug-id JERSEY-323) just a few years ago.
Be cautious. For example, RESTlet uses XMLEncoder/XMLDecoder for its ObjectRepresentation, when the media type chosen was ‘application/x-java-serialized-object+xml’. This was deactivated by default, but insane developers may ignore the security warning and activate it.
Remember that the JSON payload used by our REST application is under the control of the bad guys. Frameworks provide extensions that allow more functionality at the expense of security, for example:
You need specific controls against well-known attacks, such as Cross-Site Request Forgery (CSRF). Your REST endpoints should enforce explicit controls for resource state-changing operations. Due to the stateless nature of REST, this could need a slight departure from conventional session-based anti-CSRF schemes, like synchonizer token pattern.
Jersey framework, for example, use a CsrfProtectionFilter for this. Remember that any cross-site scripting (XSS) vulnerability in the target application could allow injection of JavaScript code that creates XMLHttpRequest (XHR) with the anti-CSRF header. The browser SOP will allow that because JavaScript has same origin as the request target.
Authentication and session-management data (API keys, username/password, session tokens, etc.) should not appear in the URL. Sensitive info can leak in web server logs, intermediate proxies, etc. Authentication with client-side (and server-side, of course) SSL certificates could be useful here.
As RESTful (stateless) web services often need to maintain a transactional state, a state blob is typically exchanged between client and server. Your API should be designed to avoid replay attacks with the state blob. You can use a session token or API key to keep all information at server-side, in a similar way as conventional web applications use a session cookie + server-side session data.
Another general recommendation with REST is to avoid encoding sensitive information in the URL. REST principles always tell you to avoid using GET for state-changing operations. Since you can log or cache URLs, this may result in information leakage.
Documentation could provide too many details to potential attackers. Many REST frameworks disclose full information about the API, either through exposed pages (without authentication), or using HTML pages or WADL documents. You likely will need to do an active validation of the exposed documentation, as many frameworks expose API documentation “automagically”.
Providing detailed documentation for the API could be useful for API consumers. But it also provides valuable information for the bad guys.
So, what could you do to avoid security issues with your REST API?
For better control during URL construction, do not use concatenation with parts coming from untrusted inputs. A useful facility is the “URI-builders” that work like the PreparedStatement for SQL injection, for example, the javax.ws.rs.core.UriBuilder, or the Apache Commons HttpComponents org.apache.http.client.utils.URIBuilder. See URLs and Links for details on how to use UrlBuilder for building safer URLs that automatically encode the dangerous characters to avoid HPPP attacks.
Of course, input “whitelist” validation in untrusted inputs. Validate that the target composed URL really points to the intended resource. Neutralizations are also recommended here.
If you would like to determine whether your applications are susceptible to these types of attacks, request a free trial of Kiuwan Code Security with up-to-date rules for these vulnerabilities and many more in compliance with OWASP, Nist, CWE, etc.