I have a Chrome extension that needs to send data to a separate application I have running on Elastic Beanstalk via POST request. The POST endpoint itself is working fine via http, as confirmed using cURL.
However, given I am posting JSON data from a non-origin domain, the AJAX POST request is performed via https. This is causing the POST request to timeout, both from the Chrome extension and from cURL. I've done some research on how to change the CORS settings on the nginx server on Elastic Beanstalk, but I don't really know what I'm doing and kinda grasping at straws. How can I enable CORS on ELB/nginx?
NGINX instance working on EB machines are just proxying the request to your application and passing back the response to the client. You can set CORS headers in your application and that's it.
Related
Background: We are using Laravel v8.83.5 running on nginx and PHP 7.4 Amazon Linux EC2 instance which is powered by an Elastic Load Balancer. We provide an iCalendar feed as a URL to customers which they can import into AirBNB, VRBO and other OTA.
Issue:
When our iCal Feed URL is added to VRBO, it's accepted and parsed by it.
When we use our iCal Feed URL on AirBNB, it throws an error 'We're having trouble syncing this calendar. Try importing it again.'. The same URL downloads an .ics file when visited from the browser and also works when importing into another iCal compatible calendar. The syntax is valid as has been checked on https://icalendar.org/validator.html as well.
To identify the issue,
we tried a different URL on another Digital Ocean server which returns the same response but does not have an ELB behind it and also uses nginx and php 7.4. That URL is accepted by the AirBnB importer. A screenshot of the response headers for this second server's request is attached here
A screenshot of the response headers for which the request fails on AirBNB is attached here.
When trying via postman, both requests return the same response content. The general headers are same as well.
On checking nginx access logs, the response code return to AirBNB by the servers is 200 in both cases.
If we pass a static file into the AirBNB importer from the server that's behind the ELB, the URL works on AirBNB.
We have tried
disabling gzip and cache control in nginx on the response being returned.
switching between apache and nginx on the server that sits behind the Amazon ELB.
Removed all global middleware added by Laravel on that route
I deployed a FastAPI based backend on Heroku and whenever I query the url via cURL or Postman, it works fine. However, when it queried from a chrome extension (built on React for Github), it throws
Access to fetch at '<API>' (redirected from '<API>') from origin 'https://github.com' has been blocked by CORS policy: 'No-Access-Control-Allow-Origin' header is present on the requested resource.
Funny thing is that the request runs fine for most of the time but when the server is not queried for about 10 mins, it first throws this error 2-3 times then the subsequent requests succeed.
From the frontend, Javascript fetch API is used to query the API with method & Content-type header.
To set up CORS policy on backend, I followed this CORS docs. Following is the snippet:
app = FastAPI()
origins = [
"https://github.com",
"http://localhost:8000" # dev
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
I am not able to understand if this issue is from frontend, backend or Heroku free dyno going to sleep. Thanks.
The request to your API is most likely coming from "Origin": "chrome-extension://..."
You can change your FastApi controller to
origins = ["*"]
That should give you a temporary fix.
As far as adding your specific Chrome extension to the allowed origins ...that's what I'm on here searching for lol.
Scenario:
CORS is disabled. API is hosted in Azure. Why I'm allowed to post to the web api from my machine, that, that I suppose is localhost domain? Can someone let me know if I have a complete misunderstanding of what CORS does?
Thank you!
While CORS is configured on the server, it is up to the client to enforce it.
Most web browsers do enforce it, and fall back to the same origin policy if it is not enabled on the server.
If you make a request with an HTTP client like Postman, or code running in some other application, CORS is not a factor.
Using the following stack:
AWS amplify
NodeJS
ReactJS (built using create-react-app)
When running amplify mock it automatically assigns an endpoint with HTTP (as can be seen in the terminal and the aws-exports.js file).
I am however hosting my app locally in an HTTPS environment using ($env:HTTPS="true") -and (npm start) so as to better accommodate the social sign-ins which usually require all requests to come from HTTPS even if on localhost.
I constantly have to change my env to HTTP to try out things with the mock backend instead of just maintaining everything in HTTPS.
Is there a way to let the mock backend be served over HTTPS?
I have found a partial answer.
using the chrome browser settings, select privacy and security and go to site settings.
Add the URLS you are requesting over http into the insecure content allowable section. This allows an origin of https to request over http.
When I navigate to web.mysite.com, a static SPA hosted in S3, it has an iframe which has a src of mysite.com/some/path, which is a Spring Boot MVC application in Elastic Beanstalk. Both are behind Cloudfront distributions for HTTPS. This path is handled in the application with a custom resource resolver. This loads successfully, but inside the iframe content there is a script tag looking for mysite.com/some/path/thatsdifferent, handled by the same resolver.
This second request fails with a 403 and I cannot determine why. Navigating to the failing mysite.com/some/path/thatsdifferent directly in my browser or using postman succeeds with a 200 status. The server is configured to allow requests from web.mysite.com through CORS configuration (and there is no CORS-related error message) and Spring Security is configured to permitAll any requests to /some/** regardless of authentication. There is no response body or error message beyond the header x-cache: Error from cloudfront.
If I navigate to the-beanstalk-env-url.com/some/path, it loads the html and then successfully loads the content from the-beanstalk-env-url.com/some/path/thatsdifferent.
Requests to a few different but similar paths succeed. Going to a path which definitely 100% does not exists returns a 404.
The server logs show that the request is being successfully handled and Cloudfront is returning reasonable responses to the client. Looking at the Cloudfront logs simply reports a 403, without any additional information.
Almost 100% of Cloudfront 403 error articles and questions involve S3, which is not the part which is failing here.
Changing the Cloudfront distribution Allowed Methods from GET, HEAD to GET, HEAD, OPTIONS causes the requests directly to mysite.com/some/path/thatsdifferent to begin failing with invalid CORS request, this was fixed by whitelisting the Accept, Authorization, Host, Origin and Referer headers. This did not fix the underlying error.
Adjusting the logging for org.springframework.security doesn't log any extra information when a failing request occurs, my application security configuration is not what is causing the error.
After replacing Cloudfront with a load balancer on my environment in Route 53, the scenario works as expected, so the problem is definitely in Cloudfront.
The solution was to switch the Cloudfront Origin Protocol policy from HTTP Only to HTTPS Only.
I don't know why this mattered from the script file and not the html file, but I decided to test it out when I discovered that if I tried to connect to the Beanstalk environment URL via https, Chrome was warning me that the certificate being used was setup for the domain that was served by the Cloudfront distribution that was causing trouble.