I have an aws lambda setup using nodejs to basically receive a request with query parameters, trigger another https request and then send the response back.
Configuration for this otherwise is essentially default.
I have then added a trigger to this lambda in the form of an api gateway HTTP api (not REST api).
I have managed to get the api itself to work however I am getting blocked with the usual CORS issues. (i verified the path with Moesif CORS and origin changer to make sure everything else works and it does).
My CORS configuration in the api gateway is basically set to have
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: *
Access-Control-Allow-Methods: *
Access-Control-Expose-Headers: No Expose Headers are allowed
Access-Control-Max-Age: 0 seconds
Access-Control-Allow-Credentials: No
I keep finding different pages explaining how to enable cors and so on but mostly seem to be either for an old version of the configuration or for REST api's which look to be quite different.
As it stands, I get this error so i never am allowed to use my api:
Access to fetch at 'https://path.to.my.api?query1=a' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
I would want to either allow all origins or disable CORS completely for this really.
Disclaimer: I am quite new to the whole aws infrastructure so some terminology related to it might still be not yet understood.
Edit 1:
After some more digging. I have realised that the call that is failing with the cors error is the first of the two calls happening.
That is to say, this is the call that is ending up on my google domain (which normally would redirect temporarily to my aws gateway - this was setup following instrctions on aws to make a "synthetic record" on the domain settings to return a 302 to the execute-api.eu-central-1.amazonaws.com url), not the call that returns the actual data.
Edit 2:
I have tried adding a route in my api gateway for OPTIONS on the same path, pointed to my lambda which returns the appropriate headers when triggered, however this doesn't seem to get called at all in this case. So i imagine api gateway is trying to handle it on its own but failing somehow
Related
Framework: Vue.js
Sending DELETE request(axios) to aws api gateway, that triggers a lambda function.
In API Gateway, I have created the DELETE method
screenshot
I have created/configured the OPTIONS method, where Gateway Responses DEFAULT 4XX AND DEFAULT 5XX are checked. Methods: DELETE and OPTIONS are checked, Access-Control-Allow-Headers: 'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token' and Access-Control-Allow-Origin were manually set. i.e. a list of origins.
I confirm configuration was saved by taking a look at Gateway Responses
screenshot
Lambda Function created, responds with the following headers.
screenshot
Code on client side
screenshot
Executing program - Request Response does not include the Access-Control-Allow-Origins.
I've been stuck for a couple of days now, I don't know where else I should look into.
I have tried adding headers to request e.g. Access-Control-Allow-Origin: '*' ,and tried the list of specific origins that will ping the api.
set Access-Control-Allow-Origin in api gateway to '*'
uncheck Lambda Proxy Integration in Delete Method, Any Method in api gateway
lambda function response with 'Access-Control-Allow-Methods': 'list of methods'
use fetch
So I want a same-origin policy which only allows my API to be called from the same-origin in browser, I don't want CORs.
After hours testing whether nginx or my node web app was setting Access-Control-Allow-Origin:* , it turns out that AWS EC2 is setting CORs headers without my permission. I can override this using Nginx to remove response headers and replace (if necessary)...
However I do not believe this is how it should be done, why is AWS putting extra strain on my web server without giving me the option to customise their default "allow all origins"?
This is such an unnecessary problem AWS is creating for me and was wondering if anyone else is experiencing the same and how we should go about it?
What I've tried:
In local development without AWS, neither nginx nor my node app add any access control headers (without my permission) - there is no mention of it. I even disabled CORS on my node app to make sure!
Turning on cors in my node app to see if I can override the response that is being set by AWS EC2 downstream.
This results in two separate Access-Control-Allow-Origin headers, the AWS one taking precedence over mine.
Using Nginx to respond to Options, so AWS knows that I have considered CORs requests and that I want to reject them... However my nginx response to Options is once again overrided by AWS downstream on the response! Additionally I would add CORs options to my responses using NGinx but they are still overrided by AWS.
when I say AWS overrides my response I mean that, my response is included but so is AWS response.
[example AWS with Nginx response][1]
[1]: https://i.stack.imgur.com/9xnlr.png
Maybe AWS are saying something, that all API's should be accessible from all origins? just doesn't make sense to me!
Btw here is what amazon have to say about cors, that it is "standardised" https://docs.aws.amazon.com/AWSEC2/latest/APIReference/cors-support.html
I don't understand the difference between an EC2 instance running MY API, vs and EC2 API? my main concern is changing the AWS cors headers, which I cant find any help on!
So after playing around more and realising that the Access-Control-Allow-Origin:* is being returned only by all GET requests, and all successful POST requests (from my own domain - no CORs, as i have it disabled), I thought something has to be up (all my get requests are allowed cross domain).
This post explains it beautifully by Amazon themselves, pretty annoyed they have taken the liberty to take my web security into their own hands, but atleast we know what side they are on now!
https://docs.aws.amazon.com/AWSEC2/latest/APIReference/cors-support.html
"For all simple requests such as GET & POST(simple post), the Access-Control-Allow-Origin * is returned" by AMAZON.
"Therefore, Amazon EC2 allows any cross-domain origin, and never allows browser credentials, such as cookies." because " Access-Control-Allow-Credentials is never returned" - so cookies should not be at risk of cross-site attacks from this setup I hope. However this setup also encourages spam botting from any domain, which will make amazon more money - which is the only plausible reason for why they have decided to enabled CORs for all simple requests.. #jeff.
If you prefer images, and so we can quote amazon on this!
Simple Requests Response from EC2
Finally, Amazon EC2 even have the courtesy to accept OPTIONS requests on our behalf, for more dangerous requests - to which they send a response of:
Access-Control-Allow-Origin: * "This is always returned with a * value."
Access-Control-Allow-Credentials is NOT returned. Setting browser for default false which will not send any cookies with the now permitted cross origin requests.
Access-Control-Expose-Headers is NOT returned. EC2 doesn't permit your browser to read response headers?
Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT, DELETE - "this depends on whether you use our Query API or REST" have no idea what that means but a cross site preflight for my REST API returned GET, OPTIONS, POST - thankfully.
Access-Control-Allow-Headers "Amazon EC2 accepts any headers in preflight requests."
The general sense is that Amazon wants us to outsource basic CORs security to the EC2 instance? Would love to test out the pre-flight they provide better but it seems they do most of the boilerplate and let you decide if you want to accept any complex/notsimple CORs requests - as detailed here https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-cors.html
Took me a while and a bit of shock, but glad we got here!
I have scoured over 25 SO posts about this but cannot find a solution to my problem. I have an API Gateway with an HTTP API + route that utilizes a Lambda function integration. From SO posts and AWS documentation, I am reading conflicting information:
From the AWS documentation, I see
If you configure CORS for an API, API Gateway automatically sends a response to preflight OPTIONS requests, even if there isn't an OPTIONS route configured for your API. For a CORS request, API Gateway adds the configured CORS headers to the response from an integration.
If you configure CORS for an API, API Gateway ignores CORS headers returned from your backend integration.
This is exactly what I did; I configured my CORS as follows:
photo
However, I still get the errors:
Access to fetch at 'https://domain.execute-api.aws-region.amazonaws.com/dev/upload' from
origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight
request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is
present on the requested resource. If an opaque response serves your needs, set the
request's mode to 'no-cors' to fetch the resource with CORS disabled.
From Cloudwatch, I can see the requests being sent to the API, but for some reason the header isn't properly configured. I do not understand this because I thought API Gateway should handle OPTIONS pre-flight requests for HTTP APIs. I cannot find out what I'm doing wrong.
I had a similar issue, the preflight response had no CORS headers. I noticed that the preflight request included the header: Access-Control-Request-Headers: Content-Type
As soon I added Content-Type to the list of Access-Control-Allow-Headers in the HTTP API configuration it worked for me.
If you configure CORS for an API, API Gateway automatically sends a
response to preflight OPTIONS requests
I think that rule doesn't work for the POST method, because I met the same issue. Then I tried to add an OPTIONS route manually, everything works well.
Route image
I have such a configuration of a serverless application: Route53, CloudFront, S3Bucket, APIGateway, Lambda.
The frontend makes a call to the Lambda function via the API. Accordingly, the URL from the API is practically freely available.
An attacker can get it and call many times the Lambda function directly.
How to Make, URL from API causing Lambda accessible only in case of a call from a particular domain?
That is, I need to configure the APIGateway so that it responds only to a specific Origin header. How to do it?
Sounds like what you want is a Custom Authorizer. You create an aws lambda that checks the appropriate headers and then allow/reject the request. The result is then cached as well.
However, you'll want to setup some sort of authentication like AWS Cognito as well to verify who is calling your API.
The solution turned out to be quite simple. In the Request Method of my API, I added Request Validator -> Validate query string parameters and headers, and HTTP Request Header - "Origin" in which I specified the required domain (https://example.com).
Also did Enable CORS and added "Origin" to Access-Control-Allow-Headers, and Access-Control-Allow-Origin specified``https://example.com
And when I called the API from the client, I passed Access-Control-Request-Headers: Origin (although maybe it was not necessary).
As a result: the API that calls the Lambda function, when called directly (from the browser or using curl) produces: {"message": "Missing required request parameters: [Origin]"}.
When called from another, not allowed domain, it gives: "The 'Access-Control-Allow-Origin' header has a value https://example.com that is not equal to the supplied origin".
But when called from https: //example.com API is triggered and the Lambda function is started, which was required.
I am using AWS API Gateway and Lambda Function for one of my applications.
When I send a POST request to API Gateway, it results in an error:
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:8888' is therefore not allowed
access. The response had HTTP status code 400
I enabled CORS in the API Gateway console and added 'Access-Control-Allow-Origin' to "Access-Control-Allow-Headers" and clicked "Enable CORS and replace existing CORS Header" button. It was a success.
But when I reloaded the page, I found 'Access-Control-Allow-Headers' header was not present in "Access-Control-Allow-Headers".
I don't know why AWS is not allowing me to edit "Access-Control-Allow-Headers".
I enabled CORS in the API Gateway console and added 'Access-Control-Allow-Origin' to "Access-Control-Allow-Headers" and clicked "Enable CORS and replace existing CORS Header" button. It was a success.
OK, these are two entirely separate headers. Access-Control-Allow-Origin is a response header which must be sent in response to both preflight OPTIONS requests and the actual POST/GET requests. Access-Control-Allow-Headers is a separate response header which is only sent in response to a preflight OPTIONS request.
Can you provide a screenshot showing exactly what you entered where?
I just enabled CORS for two of my APIs in AWS Gateway.
Even after enabling CORS in Gateway API CORS settings, I had faced CORS problem due to these reasons.
CORS Settings: That's the starting point. In CORS settings on API Gateway allow CORS for you origin.
Till you debug CORS issue, you may keep the least restrictive setting as shown below.
Access-Control-Allow-Origin=*
Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE
(you may even add all headers here during debugging)
Access-Control-Max-Age=0
Access-Control-Expose-Headers, Access-Control-Allow-Headers may be left as default.
Null Origin: For local development, I was running my front-end application directly from the file system without a web-server. AWS CORS setting do not support null origin. I then hosted my local application on nodejs http-server. Now the application has origin localhost. And CORS setting worked fine on one of my APIs.
API path must match. For the second API, I still faced the CORS issue. Despite have the same settings as other API and hosted on a web server. The problem here was that this API had integration at the root and for this case, API must end with /. It was very annoying that I was focusing only on CORS setting where the problem was somewhere else.
If CORS settings do not work for you, you may want to implement root OPTION and return proper CORS headers.