Synapse CORS Configuration - January 2023
This document was created for review by the Synapse engineering team to respond to - SWC-6374Getting issue details... STATUS . There is no guarantee that this information is up-to-date, nor is it prescriptive for future security concerns.
Findings
A recent penetration test performed by NCC has found a vulnerability in our Cross-Origin Resource Sharing (CORS) configurations for synapse.org
(Portal services) and repo-prod.prod.sagebase.org
(Repo services). The report describes how an XSS attack could be orchestrated to exfiltrate user credentials from an arbitrary subdomain of *.synapse.org
. The scenario is unlikely, but high impact; a successful attack would fully compromise the Synapse account of each affected user.
Our Portal services' CORS configuration enables us to retrieve and re-use authentication credentials across all *.synapse.org
sites, so users don’t have to authenticate multiple times. NCC recommends that we restrict this functionality to a whitelist of known subdomains of synapse.org
. Because this functionality is only provided on *.synapse.org
, our whitelist would not need to contain any origins that are not subdomains of synapse.org
.
To follow this recommendation, we must estimate the level of effort of, and perform the following:
Regularly or programmatically compile a list of valid
synapse.org
subdomains.Add functionality to the portal to utilize this list of subdomains to restrict valid
.synapse.org
origins.
The domain for the repository services (repo-<stack>.prod.sagebase.org
) were also specified in the report, but the services are not vulnerable to the same attack, and specific findings were not provided. There is a related misconfiguration that does not expose us to any vulnerability, but we should address it to reduce the risk of vulnerabilities introduced by future changes.
Both of our applications allow any origin to handle the responses of non-credentialed requests. Taking similar action against non-credentialed requests would require a much greater technical burden. We should seek further correspondence with NCC to determine if the above would be sufficient action to resolve the issue.
Background
This section will summarize the purpose of CORS, the HTTP response headers relevant to the penetration test findings, and outline the threat model that a “proper” CORS configuration is supposed to protect against.
Relevant CORS headers
By default, browsers restrict JavaScript code from accessing the response of an HTTP request to an origin different from that of the open window or frame. For certain types of requests, browsers send a “preflight” request to determine if the request would be allowed before it is sent. The server can set values in certain headers to loosen these restrictions. This document will focus only on the headers referenced in the penetration test and issue for the sake of brevity.
The Access-Control-Allow-Origin
response header is used by the browser to determine if the JavaScript environment should be able to read the response of a cross-origin request. The value may be "*"
, an Origin (e.g. https://www.synapse.org
), or null
.
The Access-Control-Allow-Credentials
response header is used by the browser to determine if a response can be exposed to the JavaScript that initiated the request in cases where the request includes credentials automatically attached by the browser (e.g. cookies). The value may be "true"
or null
. Note that the browser will always reject responses to requests with credentials if Access-Control-Allow-Origin
is "*"
(reference). Additionally, some modern browsers currently block, or plan to block, third-party cookies by default.
There are also additional response headers that can be used to restrict which request headers and methods are permitted, and which headers can be exposed in JavaScript.
Aside: CORS does not guarantee that a request will not be sent. Certain requests may trigger a preflight check that will cause a browser to not send a request, but this does not apply for all types of requests. For this reason, a strict CORS configuration does not eliminate the risk of CSRF attacks. A more appropriate solution for this threat model is to reject requests on the server based on the origin.
Current behavior of affected web applications
The penetration test reported this vulnerability across two different web applications that have server-side components: the repository app hosted on repo-<stack>.prod.sagebase.org
, and the servlet for the web portal hosted on <stack>.synapse.org
.
Service | Domain | Access-Control-Allow-Origin | Access-Control-Allow-Credentials | Implications |
---|---|---|---|---|
Synapse-Repository-Services |
|
|
| Any origin can access response data. Cross-origin sites cannot access response data sent with credentials. |
SynapseWebClient |
|
|
| Any origin can access response data. Only *.synapse.org origins can access response data sent with credentials. |
Portal
For requests originating outside of .synapse.org
, Access-Control-Allow-Origin
is *
. This is appropriate because some portal services provide content specifically designed to be rendered on other sites (e.g. snippets on social media).
At the time of writing, the portal has served content to 863 unique origin values in the past 30 days. Full data omitted, methods shown below.
The value for Access-Control-Allow-Credentials
changes based on the origin. If the origin ends with .synapse.org
, then we set the header to be true
and set the value of Access-Control-Allow-Origin
to match the request origin, so that the browser will permit using requests with credentials.
The only known scenario that depends on this configuration is that we persist authentication state across *.synapse.org
domains. When logging in to Synapse on a .synapse.org
site, a cookie is stored that contains the access token. The cookie is HttpOnly
, so to get this access token into JavaScript, the browser will call the Portal service GET /Portal/sessioncookie
with the cookie. The service responds with the access token in the response body, which can be stored in-memory in JavaScript. Because of our current CORS configuration, this functionality only works from .synapse.org
domains. The proposed change from NCC does not compromise this behavior.
No changes would be required with respect to the dev environment because the Portal dev instance (portal-dev.dev.sagebase.org
) is not configured to provide a shared authentication session.
As shown in the expandable section below, there are 22 unique .synapse.org
origins that are utilizing the service that provides credentials in a cross-origin context. To follow NCC’s recommendation, we must be able to compile this list of valid subdomains, and then pass them to the portal to selectively filter the subdomains that are allowed to use credentials.
Repo
Today, the Access-Control-Allow-Origin
header for the repository services is always *
. This means that JavaScript code running on any origin may view the responses in cross-site requests to the repository services.
Restricting the Access-Control-Allow-Origin
header to a whitelist would have substantial technical cost. Within a recent 30 day window, we have allowed requests from 46 different origins:
This is a wide range of origins that includes multiple applications, multiple environments, CDNs, and applications developed by other teams at Sage, so there would likely be significant technical complexity in maintaining this list.
Today, the current value of Access-Control-Allow-Credentials
is irrelevant because we do not specify a specific origin for Access-Control-Allow-Origin
. For this reason, we should change the repo to unset Access-Control-Allow-Credentials
.
Additionally, we should investigate removing functionality related to credential cookies, because it’s not clear if they are used by clients today. See Synapse-Repository-Services/services/authutil/src/main/java/org/sagebionetworks/authutil/CookieSessionTokenFilter.java at develop · Sage-Bionetworks/Synapse-Repository-Services.