Cross Site Request Forgery (CSRF) protection changes in Atlassian REST
Recent changes in Atlassian REST mean that some browser requests may be blocked because the origin of the request is not trusted.
A REST request is subject to origin CSRF checks if the following conditions are met:
- the request is a POST request (the http verb is POST)
- the request is from a known browser
- the request is sending a content-type which is not one of the following
- application/x-www-form-urlencoded
- multipart/form-data
- text/plain
- empty or not specified
When an untrusted origin attempts to send a request that meets the conditions specified above it will be blocked and a log entry similar to the following should be present in your application's log file:
2015-09-01 17:25:46.530585500 2015-09-01 07:25:46,530 ajp-nio-127.0.0.104-8009-exec-23 WARN anonymous 1045x1465x1 sibktb 127.0.0.1 /rest/auth/latest/session [c.a.p.r.c.security.jersey.XsrfResourceFilter] Additional XSRF checks failed for request: https://example.domain/rest/auth/latest/session , origin: https://another-origin.domain , referrer: null , credentials in request: true , allowed via CORS: false}}
Symptoms
The following symptoms have been experienced and resolved by fixing the configuration:
- update an add on, including the Universal Plugin Manager, from the Atlassian marketplace
How does the CSRF origin protection work?
The CSRF origin protection works by comparing the origin of incoming requests via the origin
and referer
headers. In simple terms it checks that the origin of a request is in the same origin as the application itself or if the request origin is trusted by the application.
Examples:
Note: Assume that https://trusted-origin.com is trusted by the application.
Referer Header Value | Origin Header Value | application URI | Allowed? |
---|---|---|---|
http://example.com | http://example.com | - the host, port and scheme match | |
https://example.com/foobar | https://example.com/example | - the host, port and scheme match | |
http://somethingelse.com | http://example.com | - the host does not match. | |
http://example.com:81/ | http://example.com/ | - the port does not match. | |
http://example.com | https://example.com | - the scheme does not match, http != https | |
http://example.com | http://example.com | - the host, port and scheme match | |
https://example.com/foobar | https://example.com/example | - the host, port and scheme match | |
http://somethingelse.com | http://example.com | - the host does not match. | |
http://example.com:81/ | http://example.com/ | - the port does not match. | |
http://example.com | https://example.com | - the scheme does not match, http != https | |
https://trusted-origin.com | https://example.com | - allowed because the request comes from a trusted origin. As per the assumption above, https://trusted-origin.com is trusted by the application. | |
https://trusted-origin.com | https://example.com/ | - allowed because the request comes from a trusted origin. As per the assumption above, https://trusted-origin.com is trusted by the application. |
How to fix it?
As of Bitbucket Server 5.0, you can't configure any Tomcat connectors directly.
server.xml
configurations have been replaced by <Bitbucket home directory>
/shared/bitbucket.properties
Please read through Migrate server.xml customizations to bitbucket.properties
This usually happens due to Tomcat proxy configuration issues.
If an Atlassian application is run behind a proxy and you are encountering issues with the origin based CSRF protection then please check the following parameters are configured in the server.xml
:
- the configured
proxyName
matches the hostname that the application is accessed on. - the configured
proxyPort
matches the port that the application is accessed on. - the configured
scheme
matches the scheme that the application is accessed with.
For example, if JIRA is running behind apache and the url to access JIRA is https://example.domain/ then the correct proxy settings are the following
- proxyName="example.domain"
- proxyPort="443"
- scheme="https"
For the same example, if there is a misconfiguration on the server.xml
and the parameters are configured pointing to HTTP, you'd reproduce this UPM issue:
- proxyName="example.domain"
- proxyPort="80"
- scheme="http"
Postman extension workaround
If you wish to use the Postman browser extension then you may need to install the Postman Interceptor browser extension. The following steps sets the Origin header to be in the same origin as the request destination as per the same origin policy:
- Click the 'Proxy / Interceptor' button at the top of the Postman application':
- Install the Postman Interceptor as directed:
- Enable the Intercepter in Postman:
- On the Headers tab, update the Origin to the server the request is being sent to and Content-Type to application/json:
For example, if you are using Postman to send a request to https://foobar.example/ then set the Origin header to https://foobar.example/.