-
Origin
-
Access-Control-Request-Method
The Cross-Origin Resource Sharing (CORS) filter allows Repose to manage CORS requests without the origin service needing to understand CORS. For an introduction to CORS, see the CORS Overview section below.
Before enabling the CORS filter, you should be familiar with the CORS specification and the associated security implications. Enabling CORS can increase an endpoint’s exposure. Configuring CORS improperly could expose Cross-Site Request Forgery (CSRF) vulnerabilities in the origin service that were previously hidden by not supporting CORS. |
Name: cors
Released: v7.2.0.0
Bundle: repose-filter-bundle
Default Configuration: cors.cfg.xml
Configuration Schema: cors-configuration.xsd
The presence and values of certain headers will indicate what kind of request is being made. All of these headers will be supplied by the client making the request.
Non-CORS Request | Preflight CORS Request | Actual CORS Request |
---|---|---|
None required |
|
|
* If the Origin
header matches the original Host
header in the request, it will be considered a non-CORS request.
See the Origin Header section for more details.
The CORS filter should be one of the first filters, if not the first filter, in the filter chain in order to properly handle CORS Preflight Requests and to properly handle exposing response headers in CORS Actual Requests. If you want to rate limit CORS Preflight Requests, you can add the following filters before the CORS filter in the filter chain:
This Rate Limiting filter would be in addition to any Rate Limiting filter you may already have in place. The first Rate Limiting filter would filter only by IP address, and the second Rate Limiting filter would continue to rate limit the way it’s currently set up.
This filter is not strictly required by any other filters.
This filter does not modify the response body, but it will set it in certain early termination conditions. See the [Response status codes] section for more details.
The filter will add the following headers to the response when the request is allowed to proceed:
Non-CORS Request | CORS Preflight Request | CORS Actual Request |
---|---|---|
None |
|
|
The following headers will be added to the response when the request is rejected by this filter:
Origin is not allowed | Method is not allowed | Origin header is malformed |
---|---|---|
None |
|
None |
These are the conditions in which the CORS filter will stop processing the request and immediately return a response:
Response Code | Response Body | Request Type | Reason |
---|---|---|---|
200 |
None |
Preflight Request |
Origin is allowed |
403 |
None |
Preflight Request |
Origin is not allowed |
403 |
None |
Preflight Request |
Method is not allowed |
400 |
Bad Origin header |
Actual Request |
|
403 |
None |
Actual Request |
Origin is not allowed |
403 |
None |
Actual Request |
Method is not allowed |
A basic CORS configuration would allow all origins to use any standard HTTP method on all resources.
If you configure an origin regex of |
<?xml version="1.0" encoding="UTF-8"?>
<cross-origin-resource-sharing
xmlns="http://docs.openrepose.org/repose/cross-origin-resource-sharing/v1.0">
<allowed-origins>
<origin regex="true">.*</origin> (1)
</allowed-origins>
<allowed-methods> (2)
<method>OPTIONS</method>
<method>GET</method>
<method>HEAD</method>
<method>POST</method>
<method>PUT</method>
<method>DELETE</method>
<method>TRACE</method>
<method>CONNECT</method>
</allowed-methods>
</cross-origin-resource-sharing>
1 | Allow all origins. |
2 | Allow these HTTP methods on all resources. |
To limit which origins are allowed to initiate a CORS request to your API, you can specify a literal value or a regular expression that the Origin
header must match in order to proceed with the request.
<?xml version="1.0" encoding="UTF-8"?>
<cross-origin-resource-sharing
xmlns="http://docs.openrepose.org/repose/cross-origin-resource-sharing/v1.0">
<allowed-origins>
<origin>https://subdomain.other-domain.com:8443</origin> (1)
<origin regex="true">http://.*.subdomain.rackspace.com(:\d*)?</origin> (2)
<origin regex="true">http://www.openrepose.org(:80)?</origin> (3)
</allowed-origins>
<allowed-methods> (4)
<method>GET</method>
<method>POST</method>
</allowed-methods>
</cross-origin-resource-sharing>
1 | Allow this specific origin. |
2 | Allow any subdomain of ".subdomain.rackspace.com" on any port. |
3 | Allow this specific origin and support both web browsers that will include the default port and those that will leave it out. |
4 | Allow HTTP methods GET and POST on all resources. |
If specific resources support additional HTTP methods, you can configure this per-resource using a regex to specify the path or paths.
The resource
configuration is processed in the configured order, so the first path regex to match the request URI will be used in conjunction with the global allowed-methods
configuration.
This is used to determine the complete list of allowed methods to return in response to a CORS Preflight Request and to determine whether or not a CORS Actual Request is allowed to proceed past this filter.
This is not a substitution for authorization.
Requests that do not contain the |
<?xml version="1.0" encoding="UTF-8"?>
<cross-origin-resource-sharing
xmlns="http://docs.openrepose.org/repose/cross-origin-resource-sharing/v1.0">
<allowed-origins>
<origin regex="true">.*</origin>
</allowed-origins>
<allowed-methods> (1)
<method>GET</method>
<method>HEAD</method>
</allowed-methods>
<resources>
<resource path="/v1/status.*"/> (2)
<resource path="/v1(/.*)?"> (3)
<allowed-methods>
<method>POST</method>
<method>PUT</method>
</allowed-methods>
</resource>
<resource path="/.*"> (4)
<allowed-methods>
<method>POST</method>
<method>PUT</method>
<method>PATCH</method>
<method>DELETE</method>
</allowed-methods>
</resource>
</resources>
</cross-origin-resource-sharing>
1 | Allow HTTP methods GET and HEAD on all resources. |
2 | The /v1/status endpoint doesn’t support anything other than GET and HEAD. |
3 | The rest of /v1 supports POST and PUT in addition to GET and HEAD. |
4 | All other non /v1 endpoints support POST, PUT, PATCH, and DELETE in addition to GET and HEAD. |
Using this configuration, you would see the following behavior:
Request URI | Matched Path | Access-Control-Allow-Methods |
---|---|---|
/v1/status/servers |
/v1/status.* |
GET, HEAD |
/v1/status?status=destroyed |
/v1/status.* |
GET, HEAD |
/v1/servers |
/v1(/.*)? |
GET, HEAD, POST, PUT |
/v1 |
/v1(/.*)? |
GET, HEAD, POST, PUT |
/v2/servers |
/.* |
GET, HEAD, POST, PUT, PATCH, DELETE |
/index.html |
/.* |
GET, HEAD, POST, PUT, PATCH, DELETE |
This is an example configuration with notes on all of the required and optional elements and attributes.
<?xml version="1.0" encoding="UTF-8"?>
<cross-origin-resource-sharing
xmlns="http://docs.openrepose.org/repose/cross-origin-resource-sharing/v1.0">
<allowed-origins>
<origin>https://subdomain.other-domain.com:8443</origin> (1) (2)
<origin regex="true">http://.*.subdomain.rackspace.com(:\d*)?</origin> (3)
</allowed-origins>
<allowed-methods>
<method>GET</method> (4)
<method>HEAD</method>
</allowed-methods>
<resources> (5)
<resource path="/v1/status.*"/> (6) (7)
<resource path="/v1(/.*)?">
<allowed-methods> (8)
<method>POST</method> (9)
<method>PUT</method>
</allowed-methods>
</resource>
<resource path="/.*">
<allowed-methods>
<method>POST</method>
<method>PUT</method>
<method>PATCH</method>
<method>DELETE</method>
</allowed-methods>
</resource>
</resources>
</cross-origin-resource-sharing>
1 | At least one origin element is required. |
2 | The regex attribute is not required.
If it is not present, it is defaulted to false and the specified URI is treated as a literal string. |
3 | When the regex attribute is true , the specified URI will be treated as a Java regular expression. |
4 | At least one method element is required. |
5 | The resources element is optional. |
6 | At least one resource element is required when the resources element is present. |
7 | The path attribute is required and is always treated as a Java regular expression. |
8 | The allowed-methods element is optional.
Leaving it out is useful when you need to prevent adding additional HTTP methods to a sub-resource as is the case with /v1/status.* in this example. |
9 | At least one method element is required when the allowed-methods element is present. |
CORS is not a security feature.
It is a mechanism for informing clients (e.g., web browsers) of conditions when client-side security may be slightly relaxed in certain circumstances.
That is, the security lies completely within the client.
Simply leaving out the |
For security purposes, web browsers follow the Same-Origin policy. If a user were to visit a website containing malicious code, the web browser would prevent the malicious code from trying to send requests to different websites on the user’s behalf. This is especially useful when the user is authenticated on those other websites. However, sometimes a website needs to be able to get data or perform an action on a different website, but how can the client know which websites allow this and under what circumstances? This is where CORS comes in.
Instead of the web browser immediately dropping any attempt to send a request to a third-party server, it can send the request to that server with CORS headers to see if the server trusts the origin server.
The address of the origin server is sent in the Origin
header.
If the response from the third-party server does not contain the appropriate CORS headers (i.e., the server is not CORS aware) or if the CORS headers indicate the Origin
is not allowed to send requests to it, the browser will drop the response (i.e., the client-side code from the origin server will not get to see the contents of the response from the third-party server).
Even though the web browser will prevent the client-side code from seeing the response from the third-party server, the request may have still been processed by the third-party server.
To mitigate this issue, the web browser will send a CORS Preflight Request to the third-party server to first verify that the Origin
and HTTP method are allowed (among a few other things) before sending the CORS Actual Request.
If the response to the CORS Preflight Request indicates the CORS Actual Request would not include the appropriate CORS headers, the web browser will not proceed with sending the CORS Actual Request.
Because the CORS Preflight Request is asking if a CORS Actual Request would be allowed and not for the request to actually be processed, this type of request is completely handled by the CORS filter in Repose. No other filters after the CORS filter will process the request, and the request will not reach the origin service.
A web browser may choose to skip sending a CORS Preflight Request if the HTTP method is GET, HEAD, or POST, the request headers do not include anything other than Accept
, Accept-Language
, and Content-Language
, and the request does not require any cookies, HTTP authentication, nor use of any client-side SSL certificates.
Otherwise, the web browser must make a CORS Preflight Request.
For example, if your origin service requires an X-Auth-Token
header, the web browser will always send a CORS Preflight Request before sending the CORS Actual Request.
Some web browsers (e.g., Chrome and Safari) will send the Origin
header for same-origin (i.e., non-CORS) requests in addition to CORS requests which is technically allowed under RFC 6454.
This is typically not a concern for servers handling CORS because the unnecessary inclusion of CORS headers will be ignored by the client if they are not needed to process the response.
Because Repose has the added ability to reject requests with unapproved origins, additional logic is required to differentiate between CORS requests and same-origin requests when the Origin
header is present.
Requests are considered same-origin requests when the Origin
header matches the original Host
header set by the client according to the comparison rules in RFC 6454 Section 5.
If the X-Forwarded-Host
header is present in the request, the first value will be used as the host.
If the header is not present or it cannot be parsed as a URI (when the URI scheme is prepended to it), then the Host
header will be used instead.
This check is not performed for CORS Preflight Requests since web browsers should not be sending a CORS preflight header for a same-origin request.
If a proxy server sitting between the client and Repose rewrites the |