CORs - Securing My Endpoint to only allow Apigee Edge

djohnsonkc
Participant I

Hi, I'm currently using the "Add CORs" policy in the Apigee Edge proxy for my endpoint, but I would like to secure my actual endpoint by adding Access-Control-Allow-Origin at my endpoint so that access to my endpoint can only come though the Apigee proxy. I can't seem to find any request headers that identify the Apigee Edge proxy. For example, my Apigee Edge proxy is "http://djohnsonkc-test.apigee.net/" and my actual endpoint is "http://api.mydomain.com" (example). For some reason, all request that pass through my proxy, show my endpoint as the request host instead of the proxy. How can I identify the request as coming from Apigee proxy (http://djohnsonkc-test.apigee.net)? Is there a setting in my CORs policy? Thanks. Dywayne

Solved Solved
1 4 1,688
1 ACCEPTED SOLUTION

Hi Dwayne. CORS works through cooperation of the user-agent, in other words the browser.

Mainstream browsers like IE Firefox Chrome and Safari all enforce the same origin policy , which says that JS code running in the browser may not call out to services via AJAX calls that are hosted on origin servers that are different from the source html. In other words, if you point your browser to http://example.com, the script loaded there cannot call out to http://dinochiesa.net . Browsers enforce this as a security policy.

CORS was designed as a way for websites to allow browsers to call to them, in effect to work around the restrictions of the same origin policy, in a controlled manner. If a website such as http://dinochiesa.net trusted the website http://example.com then the server at dinochiesa.net could emit the appropriate CORS headers and the browser would allow outbound calls.

Apigee Edge is not a browser and is therefore not subject to the Same-origin policy; and because SOP doesn't apply, CORS is also irrelevant. Remember, CORS is just a way to work around the restrictions of SOP.

> I would like to secure my actual endpoint ... so that access to my endpoint can only come though the Apigee proxy.

Yes, this is a common scenario. There are two ways to do this: One is via IP whitelisting. The other is via 2-way SSL.

For the former, your Apigee Edge system will generate outbound requests via few (usually 2 on free/developer accounts) IP addresses. To learn them, create a proxy and use http://api.lo5.at/info as the target. Send in several GET requests. The response will tell you your IPs.

The SSL approach is more reliable. You can set up Edge to use client-side SSL certs for outbound requests. You load the certs in, and you would need to configure your actual target to inspect and verify the certs on inbound requests.

View solution in original post

4 REPLIES 4

Hi Dwayne. CORS works through cooperation of the user-agent, in other words the browser.

Mainstream browsers like IE Firefox Chrome and Safari all enforce the same origin policy , which says that JS code running in the browser may not call out to services via AJAX calls that are hosted on origin servers that are different from the source html. In other words, if you point your browser to http://example.com, the script loaded there cannot call out to http://dinochiesa.net . Browsers enforce this as a security policy.

CORS was designed as a way for websites to allow browsers to call to them, in effect to work around the restrictions of the same origin policy, in a controlled manner. If a website such as http://dinochiesa.net trusted the website http://example.com then the server at dinochiesa.net could emit the appropriate CORS headers and the browser would allow outbound calls.

Apigee Edge is not a browser and is therefore not subject to the Same-origin policy; and because SOP doesn't apply, CORS is also irrelevant. Remember, CORS is just a way to work around the restrictions of SOP.

> I would like to secure my actual endpoint ... so that access to my endpoint can only come though the Apigee proxy.

Yes, this is a common scenario. There are two ways to do this: One is via IP whitelisting. The other is via 2-way SSL.

For the former, your Apigee Edge system will generate outbound requests via few (usually 2 on free/developer accounts) IP addresses. To learn them, create a proxy and use http://api.lo5.at/info as the target. Send in several GET requests. The response will tell you your IPs.

The SSL approach is more reliable. You can set up Edge to use client-side SSL certs for outbound requests. You load the certs in, and you would need to configure your actual target to inspect and verify the certs on inbound requests.

Hi @Dino, thanks for your response. I was originally considering the IP address, but I wasn't sure if IP address for the Apigee Edge proxy would change much/ever. I'll use that approach for now.

Thanks again, Dywayne

jovaniac
Participant II

hey guys, I implemented something like that, and it served me correctly.

ProxyEndpoint

In the proxy endpoint we must place in the preflow the next call of a Flowcallout to invoke a sharedflow which will have the policy of CORS.

  <PreFlow name="PreFlow">
    <Request>
      <Step>
        <Name>FC-CORS</Name>
      </Step>
      <Step>
        <Name>FC-OAuth2</Name>
      </Step>
    </Request>
    <Response/>
  </PreFlow>

Definition of flowcallout

where we invoke the sharedflow

<FlowCallout async="false" continueOnError="false" enabled="true" name="FC-CORS">
  <DisplayName>FC-CORS</DisplayName>
  <FaultRules/>
  <Properties/>
  <SharedFlowBundle>OPTIONS-CORS-Headers-Response</SharedFlowBundle>
</FlowCallout>

definition of sharedflow

<SharedFlow name="default">
  <Step>
    <Name>OPTIONS-CORS-Headers-Response</Name>
    <Condition>request.verb == "OPTIONS"</Condition>
  </Step>
</SharedFlow>

definition of the policy of raisefault

where we will indicate the headers of Access-Control-Allow-Origin with * that will allow the invocation from our browser.

<RaiseFault async="false" continueOnError="false" enabled="true" name="OPTIONS-CORS-Headers-Response">
  <DisplayName>OPTIONS CORS Headers Response</DisplayName>
  <Properties/>
  <FaultResponse>
    <Set>
      <Headers>
        <Header name="Access-Control-Allow-Origin">*</Header>
        <Header name="Access-Control-Allow-Headers">origin, x-requested-with, accept, ucsb-api-key, ucsb-api-version, authorization</Header>
        <Header name="Access-Control-Max-Age">3628800</Header>
        <Header name="Access-Control-Allow-Methods">GET, PUT, POST, DELETE</Header>
      </Headers>
      <Payload contentType="text/plain"/>
      <StatusCode>200</StatusCode>
      <ReasonPhrase>OK</ReasonPhrase>
    </Set>
  </FaultResponse>
  <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
</RaiseFault>

Regards

POST /resources/post-here/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
X-PINGOTHER: pingpong
Content-Type: text/xml; charset=UTF-8
Referer: http://foo.example/examples/preflightInvocation.html
Content-Length: 55
Origin: http://foo.example
Pragma: no-cache site
Cache-Control: no-cache
<?xml version="1.0"?><person><name>Arun</name></person>
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:40 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://foo.example
Vary: Accept-Encoding, Origin
Content-Encoding: gzip
Content-Length: 235
Keep-Alive: timeout=2, max=99
Connection: Keep-Alive
Content-Type: text/plain
[Some GZIP'd payload]