Allowing multiple origins in CORS for Apigee proxy

I have a set of proxies being consumed by multiple sites. I have added CORS policy to send below headers to fix CORS issue.

<Header name="Access-Control-Allow-Origin">*</Header>
<Header name="Access-Control-Allow-Headers">*</Header>
<Header name="Access-Control-Max-Age">3628800</Header>
<Header name="Access-Control-Allow-Methods">GET, PUT, POST, DELETE</Header>

I read that CORS helps to add security and is not a recommended to allow all origins since the proxy can be accessed by any website. I tried to give comma separated values (<Header name="Access-Control-Allow-Origin">https://www.site1.com,https://www.site2.com</Header>) inside the allowed origins. However, browser gives error saying that header contains multiple values.

Is there any inbuilt way to configure in Apigee to allow multiple valid origins so that Apigee will send only the valid origin according to the incoming request ?

This kind of options are available in other frameworks where we can configure all the allowed origins and the server will response with appropriate headers. I was thinking of doing a JS callout to check the value of origin against a comma separated list stored in KVM. Please let me know if there is any easier way to solve this. @dchiesa1 @API-Evangelist 

0 2 2,041
2 REPLIES 2

Per the W3.org "living spec" for fetch, 

`Access-Control-Allow-Origin`

Indicates whether the response can be shared, via returning the literal value of the `Origin` request header (which can be `null`) or `*` in a response.

Which means the response header should not contain a list. It should contain exactly one value, the Origin request header or * to indicate "any origin". 

If you are using Apigee X or hybrid, then you should use the CORS policy.  The configuration looks like this:

<CORS name='CORS-1'>
  <AllowOrigins>https://origin1, https://origin2</AllowOrigins>
  <AllowMethods>GET, PUT, POST, DELETE, OPTIONS</AllowMethods>
  <AllowHeaders>x-requested-with</AllowHeaders>
  <ExposeHeaders>*</ExposeHeaders>
  <MaxAge>1800</MaxAge>
  <AllowCredentials>true</AllowCredentials>
  <GeneratePreflightResponse>true</GeneratePreflightResponse>
  <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
</CORS>

As implied by the AllowOrigins element name, the text within AllowOrigins is a list, you can specify a list of origins that are valid.  Then, when constructing the response to send to the caller, this policy will compare the  actual passed-in Origin with the elements in the list. If it finds a match, it will return in Access-Control-Allowed-Origin, the original request.header.origin, a single value in keeping with the fetch spec. So basically it solves the problem you described very nicely - how do I support multiple distinct allowed origins?  The text value  of the AllowedOrigins element is a message template, which means you can refer to a variable within curly-braces, by which you can dynamically specify the list of allowed origins at runtime (or maybe through a configuration item from a .properties file).The policy resolves the message template and then does the right thing as described above.

If you are not using Apigee X or hybrid, then you must resort to using AssignMessage and figuring out when and how to attach it, and also you must explicitly perform the logic of comparing the passed-in request.header.origin against your acceptable list (stored where? it depends).  You could do the comparison logic in a compound Condition statement, or a JS step, as you described.  In the case of AssignMessage, the Header element is a message template, and you can again reference a variable, probably request.header.origin. Just be sure to validate that header before inserting that origin in the response.

Does this help? 

I think originally the CORS spec 

 

May be follow thru this ways.

1. Push the possible cors domains into KVM (comma separated)
2. Use JS policy (use properties to pass kvm cors var)
https://docs.apigee.com/api-platform/reference/policies/javascript-policy#Property
3. In js
-read the properties
-validate properties exists & not empty
-validate request.header.origin header exists & request verb exists with OPTIONS (for CORS its OPTIONS)
-if everything good with origin header then split the values and validate the url format (use regexp) to test with predefined expressions - https://stackoverflow.com/questions/1410311/regular-expression-for-url-validation-in-javascript
-finally compare & enable flag to proceed or stop the flow.
-use proper error handling

same applies to Access-Control-Allow-Headers & Access-Control-Allow-Methods (everything needs to tightened for any given api - meaning accept only those headers,verbs etc) & also finally clean up un-necessary headers while sending to backend /responding back to client(why to share un-necessary information)..

Make sure you configure well to avoid CORS attack if you mis-configure..


https://docs.apigee.com/api-platform/develop/adding-cors-support-api-proxy

Good luck.