Overview
Web security is a field that includes many threat models and counter-attack techniques. Since from Documentum REST Services release 7.3, we have provided users with a number of web security related configuration parameters that help to protect the transfer data in the REST API. In this article, we will talk about what they are, and how to configure them.
The security models covered in this post include:
- Cross-site request forgery (CSRF)
- Cross-origin resource sharing (CORS)
- Request sanitization
- HTTP strict transport security (HSTS)
- Cacheable HTTPS response
- Browser cross-site scripting (XSS)
- Cross-frame scripting (XFS)
- Response content sniffing
Cross-site request forgery (CSRF)
Cross-Site Request Forgery (CSRF) is an attack that forces an end user to execute unwanted actions on a web application in which they're currently authenticated. CSRF attacks specifically target state-changing requests, not theft of data, since the attacker has no way to see the response of a forged request. Here is a simple scenario.
- Alice logins to her bank account via web browser and the browser remembers a session cookie (doesn't logout).
- Alice visits another website that tells her she can earn some money for free.
- Alice clicks below form showing “Win Money!“.
<form action="https://bank.example.com/transfer.json" method="post">
<input type="hidden" name="payee" value="MARIA"/>
<input type="hidden" name="amount" value="100000"/>
<input type="submit" value="Win Money!" />
</form>
- The request is actually redirected to her bank website with a POST method to transfer her
- money out from her account.
- Alice has no perception on the money lost because she was not asked for a second login.
In Documentum REST Services, we support Client Token cookie authentication for some specific authentication schemes, for instance, Central Authentication Services (CAS), SAML2 Web SSO and so on. The Client Token cookie can be remembered by web browsers until it times out. So the weakness of the cookie preservation exists. To protect Client Token cookie against CSRF attack, we enable CSRF prevention since Documentum REST 7.3.
Client Token authentication with CSRF token
In REST server runtime properties file, there is a parameter to turn on|off CSRF protection for Client Token cookie. The value is true by default, meaning CSRF token is required.
rest.security.csrf.enabled=true
When it is enabled, the Client Token authentication request MUST carry a CSRF token with it, either by a request header or a request query parameter. The CSRF protection design in Documentum REST Services conforms to Synchronizer Token Pattern.
Here is an example with a CSRF token in the request, where DOCUMENTUM-CSRF-TOKEN is set as the CSRF token header name by default.
GET /dctm-rest/repositories/REPO1
DOCUMENTUM-CSRF-TOKEN: zMp3O7u5mOu37Z1SsiuN9he/OtA7YZlf5cqcMXt9HFA=
Host: localhost:8080
cookie: DOCUMENTUM-CLIENT-TOKEN=J9Z3J0IZHfy8ib7GB8SsxbRGTBP4UJtr49…
Here's a request with CSRF token in query parameters, where csrf-token
is defined as the parameter name.
GET /dctm-rest/repositories/REPO1?csrf-token=zMp3O7u5mOu37Z1SsiuN9he/OtA7YZlf5cqcMXt9HFA=
Host: localhost:8080
cookie: DOCUMENTUM-CLIENT-TOKEN=J9Z3J0IZHfy8ib7GB8SsxbRGTBP4UJtr49…
Configuring CSRF token generation
A CSRF token is negotiated between the client and the server. Documentum REST Services supports to generate the CSRF token either from the client side or from the server side. There is a server runtime property to control this.
rest.security.csrf.generation.method= server | client
When the CSRF token is generated from the server side, the response for the initial authentication (Basic, CAS, SAML2, etc.) returns the CSRF parameters and token in headers. The client is expected to use these parameters for further Client Token authentications.
GET /dctm-rest/repositories/REPO1 HTTP/1.1
Host: localhost:8080
Authorization: Basic QWRtaW5pc3RyYXRvcjpQYXNzd29yZEAxMjM=
HTTP/1.1 200
DOCUMENTUM-CSRF-HEADER-NAME: DOCUMENTUM-CSRF-TOKEN
DOCUMENTUM-CSRF-QUERY-NAME: csrf-token
DOCUMENTUM-CSRF-TOKEN: 54msohR+0TSZbC6wrUnVUaqAOWpM2eQ7PhOEb8au+F8=
Set-Cookie: DOCUMENTUM-CLIENT-TOKEN=cblcwodoxcK_MybUbNSejQYeX7U8dgS4F9SZeM4YIjh48…
When the CSRF token is generated from the client side, the request in the initial authentication (Basic, CAS, SAML2, etc.) provides the CSRF parameters and token in the headers. Documentum REST server takes these parameters into the generation of a Client Token cookie. The client is expected to use these parameters for further Client Token authentication.
GET /dctm-rest/repositories/REPO1 HTTP/1.1
Host: localhost:8080
Authorization: Basic QWRtaW5pc3RyYXRvcjpQYXNzd29yZEAxMjM=
DOCUMENTUM-CSRF-HEADER-NAME: {csrfHeaderName}
DOCUMENTUM-CSRF-QUERY-NAME: {csrfQueryName}
DOCUMENTUM-CSRF-TOKEN: {csrfTokenValue}
HTTP/1.1 200
Set-Cookie: DOCUMENTUM-CLIENT-TOKEN=cblcwodoxcK_MybUbNSejQYeX7U8dgS4F9SZeM4YIjh48…
Configuring HTTP methods for CSRF
As CSRF attack usually harms for requests that change the server data, a secure HTTP method (GET, OPTIONS, etc.) can be excluded from requiring the CSTF token during Client Token authentications. Documentum REST provides another server runtime property to control which HTTP methods are required for CSRF token.
rest.security.csrf.http_methods= POST,PUT,DELETE
Other properties for specifying the token header name, query name and token length are also supported in Documentum REST Services. You can refer to the Documentum REST Services Development Guide or the template file rest-api-runtime.properties.template for more details.
Cross-origin resource sharing (CORS)
Normally JavaScript clients should make requests in the same origin for a website. This restriction prevents JavaScript from making requests across domain boundaries, and has spawned various hacks for making cross-domain requests. Cross-origin resource sharing (CORS) introduces a standard mechanism that can be used by all browsers for implementing cross-domain requests. Here is a simple scenario.
- Alice visits a website on domain-a.acme.com
- The server returns a main HTML web page that contains resource access to the other
- domain domain-b.acme.com
<button onclick="callOtherDomain()">
ClickMe
</button>
<script>
var invocation = new XMLHttpRequest();
var url = 'http://domain-b.acme.com';
var callOtherDomain = function() {
invocation.open('GET', url);
invocation.send();
}
</script>
- Alice gets errors on clicking the button ClickMe
The failure is normal because CORS prevents cross domain access from domain-a.acme.com to domain-b.acme.com. Documentum REST Services provides fine-grained CORS configuration to control REST request access from other domains. By default, cross domain access is denied.
Making cross-origin requests
Most modern web browsers have already supported CORS on the client side. CORS uses HTTP headers to control access to the remote resource. On the client side, the web browser adds a request header Origin: http://other-domain.com with the request. The server returns a CORS-specific header with the response, Access-Control-Allow-Origin: http://some-domains.com, which denotes the origin domains allowed to make requests to the API. A “*” would mean all domains are allowed.
Here is an example. The REST server is configured to accept requests with origin http://opentext.com. If the request doesn't contain a specified origin, the server will return a 403 Forbidden error.
GET /dctm-rest/repositories
Host: localhost:8080
Origin: http:
HTTP/1.1 200
Access-Control-Allow-Origin: http:
Access-Control-Expose-Headers: Location, DOCUMENTUM-CSRF-TOKEN
Access-Control-Allow-Credentials: true
Many JavaScript clients send CORS preflight requests with HTTP method OPTIONS before performing the actual requests for the safety. The mechanism is similar except for an additional preflight request ahead.
OPTIONS /dctm-rest/services
Host: localhost:8080
Origin: http:
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Location
HTTP/1.1 200
Access-Control-Allow-Origin: http:
Access-Control-Allow-Methods: PUT
Access-Control-Allow-Headers: Location
Access-Control-Expose-Headers: Location, DOCUMENTUM-CSRF-TOKEN
Access-Control-Allow-Credentials: true
Configuring CORS on server side
As mentioned earlier, cross domain access is denied by default. To enable it, Documentum REST server provides runtime properties to allow CORS access for specific domains or all domains. The value is false by default, meaning CORS is disabled. For the detail usage of these parameters, please refer to Documentum REST Services Development Guide.
rest.cors.enabled=false
rest.cors.allowed.origins=
rest.cors.allowed.methods=
rest.cors.allowed.headers= *
rest.cors.allow.credentials=true
rest.cors.exposed.headers=Location
rest.cors.max.age=3600
Request sanitization
Stored cross-site scripting allows the permanent injection of JavaScript code. This is a security vulnerability because this JavaScript code can result in the theft of user sessions. Request sanitization in Documentum REST Services cleans up user input to secure against this vulnerability. Request sanitization filters two parts of the input:
- The input object metadata
- The input HTML content
Here is an example of scripting injection in object metadata. When the stored property value for object_name
is rendered into a HTML page, the unexpected alert box will be pop up.
{
"name" : "document",
"type" : "dm_document",
"properties" : {
"object_name" : "The<script>alert('****')</script>Document",
}
}
When creating documents or other objects in Documentum REST Services, the server can sanitize both the metadata and the HTML content and remove any suspicious scripting code from the text. Here is the result of the object metadata sanitization for the above JSON.
{
"name" : "document",
"type" : "dm_document",
"properties" : {
"object_name" : "TheDocument",
}
}
For HTML content sanitization, by default only html and pub_html formats are sanitized. But you can still add other formats into content sanitization by configuring runtime properties.
Configuring sanitization on server side
Sanitization is turned off by default because of its performance impact. To turn it on, Documentum REST server provides runtime properties to configure the sanitization for metadata and content, respectively. For the detail usage of these parameters, please refer to Documentum REST Services Development Guide.
rest.sanitize.type.metadata=false
rest.sanitize.type.content=false
rest.sanitize.content.max.size=500000
rest.sanitize.content.default.charset=UTF-8
rest.sanitize.content.format=html,pub_html
Please note Documentum REST Services uses OWASP AntiSamy library to sanitize the text. The sanitization policies can be configured as well by creating your own policy files. Documentum REST Services Development Guide has all the details.
Customizing sanitization
In a custom REST service development with Documentum REST SDK, you may want to enable the sanitization for your resource models. REST provides an annotation com.emc.documentum.rest.binding.SanitizeConfig which allows to customize sanitization on your own resource models. Here are examples.
@SerializableType(...)
public class MyModel {
@SerializableField
@SanitizeConfig(skipSanitize=true)
private String wontBeSanitized;
...
}
@SerializableType(...)
public class MyModel {
@SerializableField
@SanitizeConfig(enforeceSanitize=true)
private String mustBeSanitized;
...
}
HTTP strict transport security (HSTS)
Some websites require HTTPS/SSL protocol on access, but allow HTTP to HTTPS redirect for client requests. This may result into man-in-the-middle attack vulnerability. Here is an example.
- Alice visits a website http://mybank.acme.com with her credentials in clear text.
- Server sends a redirect (302) response to https://mybank.acme.com.
- Alice visits to https://mybank.acme.com with her credentials in encrypted text.
As you can see, if a man is hijacking Alice's socket packages in the middle, he can easily obtain Alice's credentials in clear text. In this case, although host mybank.acme.com has strengthened its communication protocol to HTTPS, it doesn't protect users from leaking confidential information to attackers.
HTTP Strict Transport Security (HSTS)is a web security mechanism which helps to protect websites against protocol downgrade attacks and cookie hijacking. If a server requires HTTPS connections, it sends a header Strict-Transport-Security: max-age= in its response, telling the client that all further requests during that time span should be issued in HTTPS. If a client supports HSTS, it stores this setting in it with an expiration policy. Since the timeout could be long (e.g. one year), web browsers usually save the setting in offline storage.
Documentum REST Services adds server configuration parameters enabling HSTS response headers when the protocol is HTTPS. The Strict-Transport-Security header is enabled by default. For the detailed usage of these parameters, please refer to Documentum REST Services Development Guide.
rest.security.headers.hsts.disabled=false
rest.security.headers.hsts.include_sub_domains=true
rest.security.headers.hsts.max_age_in_seconds=31536000
When HSTS is turned on, the HTTPS response from REST server will include the Strict-Transport-Security header. Here is an example.
GET /dctm-rest/services
Host: localhost:8443
…
HTTP/1.1 200
Strict-Transport-Security: max-age=31536000 ; includeSubDomains
…
Cacheable HTTPS response
Unless directed otherwise, browsers may store a local cached copy of content received from web servers. If content transferred via https is stored in the local cache, it may be retrieved by other users who have access to the same computer in the future. To eliminate the vulnerability, responses should contain directives, through headers Cache-Control, Pragma and Expires, that indicate clients not to store local copies.
Since from release 7.3, Documentum REST Services has added a server runtime parameter to control headers for caching. The value is false by default, meaning cache prevention over HTTPS is enabled.
rest.security.headers.cache_control.disabled=false
When caching is disabled, the REST server response is like this.
GET /dctm-rest/services
Host: localhost:8080
HTTP/1.1 200
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
…
Browser cross-site scripting (XSS)
Cross-site scripting (XSS) attacks are a type of injection, in which malicious scripts are injected into otherwise benign and trusted web sites. XSS attacks occur when an attacker uses a web application to send malicious code, generally in the form of a browser side script, to a different end user.
- Alice often visits the search website http:// acme.com/find?q= for web search
- If there are no result for the search item, the website returns an error “404 Not Found for
- URL /find?q=”
- One day Alice receives a mail which provides a hidden link to the search website with
- URL http://acme.com/find?q= .
- Alice clicks on the link and gets a pop up message box alerting xss.
- If this is a malicious script written by an attacker, Alice's confidential information may be
- stolen silently.
One approach to prevent XSS attack is to prevent web browsers from running the scripts on the client when receiving a potentially malicious response. XSS Filter is one approach for that. When a dedicated response header X-XSS-Protection is set, the client will normalize the received response message, or even stop rendering the page.
Documentum REST Services has server configuration parameters to enable XSS protection. The value is false by default, meaning XSS protection is enabled. For the detail usage of these parameters, please refer to Documentum REST Services Development Guide.
rest.security.headers.xss_protection.disabled=false
rest.security.headers.xss_protection.explicit_enable=true
rest.security.headers.xss_protection.block=true
When XSS protection is enabled (false), the REST response message adds the HTTP header X-XSS-Protection.
HTTP/1.1 200
X-XSS-Protection: 1; mode=block
…
Cross-frame scripting (XFS)
Cross-frame scripting (XFS) is an attack that combines malicious JavaScript with an iframe that loads a legitimate page in an effort to steal data from an unsuspecting user. Here is a simple example.
- Alice often visits her bank web site http://mybank.acme.com.
- One attacker creates an evil site and sends a mail to Alice to check her account with the
- hidden link http://mybank.evil.com, the link points to a page hides an iframe like below.
<iframe style="position:absolute;top:-9999px" src="http://mybank.acme.com/flawed-page.html"></iframe>
- Alice clicks on the link and she see everything the same as mybank.acme.com.
- Alice logins and checks her bank account.
- Alice's confidential information is stolen.
One approach to eliminate frame scripting vulnerability is to prevent web browsers rendering pages within a <frame>
, <iframe>
or <object>
. Mozilla proposed the response header X-Frame-Options to do that.
Documentum REST Services adds server runtime configuration parameters to disable frame scripting. The value is false by default, meaning frame scripting prevention is enabled.
rest.security.headers.x_frame_options.disabled=false
rest.security.headers.x_frame_options.policy=DENY
When frame scripting prevention is enabled, the REST response message adds the header X-Frame-Options.
HTTP/1.1 200
X-Frame-Options: DENY
…
Response content sniffing
Content sniffing is the practice of inspecting the content of a byte stream to attempt to deduce the file format of the data within it. It is useful when there is not a suitable mechanism between the client and server to detect the content MIME. However, it opens up a serious security vulnerability, in which, by confusing the MIME sniffing algorithm, the browser can be manipulated into interpreting data in a way that allows an attacker to carry out operations that are not expected by either the site operator or user, such as cross-site scripting.
In Documentum REST Services, the client and server negotiates the content MIME by Accept and Content-Type headers, so in most cases, there is no need for content sniffing. Further, Documentum REST Services provides a server runtime parameter to stop content sniffing. It's false by default, meaning content sniffing prevention is enabled.
rest.security.headers.content_type_options.disabled=false
When content sniffing is prevented, the response from REST server will include the header X-Content- Type-Options.
HTTP/1.1 200
X-Content-Type-Options: nosniff
…