I've created a GAE project and I deployed two services:
default (https://myservice.appspot.com) for the front-end app
backend (https://backend-dot-myservice.appspot.com) for the backend (Node.js)
I've also added a custom domain so that the default service is reachable also at https://myservice.com.
The problem I have is that each AJAX requests performed by the browser is preceded by an OPTIONS request (to handle the CORS).
What's the best solution to avoid this OPTIONS request? It should be fixed if both front-end/backen-end are on the same host, but how can I do it on Google App Engine?
Thank you!
I solved adding a dispatch.yaml file on the default service
dispatch:
- url: "*/api/*"
service: backend
where backend is my backend service.
And I changed my backend in order to listen on addresses like /api/something.
So now the browser has origin https://myservice.com and the url of ajax requests to the beckend are like https://myservice.com/api/something.
Since now client and server have the same origin, the CORS settings is not needed anymore, and the OPTIONS request is not performed by the browser.
I don't know if it's the best solution, but for me it worked.
As it was mentioned in this Stackoverflow post:
OPTIONS requests are pre-flight requests in Cross-origin resource sharing (CORS).
This pre-flight request is made by some browsers as a safety measure to ensure that the request being done is trusted by the server. Meaning the server understands that the method, origin and headers being sent on the request are safe to act upon.
Your server should not ignore but handle these requests whenever you're attempting to do cross origin requests.
CORS Support for Google App Engine in your app.yaml:
One important use of this feature is to support cross-origin resource sharing (CORS), such as accessing files hosted by another App Engine app.
For example, you could have a game app mygame.appspot.com that accesses assets hosted by myassets.appspot.com. However, if mygame attempts to make a JavaScript XMLHttpRequest to myassets, it will not succeed unless the handler for myassets returns an Access-Control-Allow-Origin: response header containing the value http://mygame.appspot.com.
handlers:
- url: /images
static_dir: static/images
http_headers:
Access-Control-Allow-Origin: http://mygame.appspot.com
Note: if you wanted to allow everyone to access your assets, you could use the wildcard '*', instead of http://mygame.appspot.com.
Related
I am working on setting iframe and stuck with local testing. I have my app running on localhost:3000
I have setup Iframe in my app with src url set to localhost:1234 for local testing. I was hoping accessing via local host would resolve the cross origin error but looks like since port numbers are different, this doesn't seem to work
SecurityError: Blocked a frame with origin "http://localhost:3000" from accessing a cross-origin frame.
I have looked into various stack overflow posts and tried disabling chrome web security, even then this doesn't seem to let me do some local testing.
Any suggestions on how to prevent the cross origin error in this case?
Thanks!
Your app (the backend) should send a CORS header (from localhost:3000 if I understand correctly). A different port (just like a different hostname) counts as a different origin, so the same origin policy applies to requests, and you have to explicitly enable cross-origin requests.
The way to do so is your "backend" must send the response header
Access-Control-Allow-Origin: localhost:1234
if that's where your frontend app is running. For development, you can also send
Access-Control-Allow-Origin: *
Don't do * in later stages of your pipeline and especially not in production as you might open your app to further vulnerabilities (CSRF).
If your frontend app uses cookies to authenticate cross-origin, the backend must also send Access-Control-Allow-Credentials: true, and your frontend javascript must add withCredentials: true to the request. However, it doesn't sound like this is the case for you.
I think this is better than disabling cross-origin restrictions as this would work for any developer without any setup, and without compromising browser security. It gives you full control over which client can access your API, and also allows you to understand cross origin requests better.
I was able to do local testing via Safari following the steps here:
Safari -> Preferences -> Advanced
then at the bottom tick Show Develop Menu in menu bar
then in the Develop Menu tick Disable Cross-Origin Restrictions
Cross-Origin Resource Sharing is disabled on some modern browsers by default. Allow CORS: Access-Control-Allow-Origin plugin for Chrome adds necessary HTTP headers to perform development on localhost without CORS error.
I was testing out the new API Gateway to secure a cloud function for my React application. So far the process has been much nicer than the previous alternatives, but I am currently getting CORS errors when trying to reach out to my API Gateway from my React app. I am setting the CORS headers correctly in my Cloud Function, but I have no known way of doing the same on the API Gateway endpoint. I am using Postman to test a request to the gateway endpoint and everything is working great, so it is just when I request from my React app.
Error: "Access to fetch at 'https://my-gateway-a12bcd345e67f89g0h.uc.gateway.dev/hello?key=example' from origin 'https://example.netlify.app' 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."
Would love some insight into this issue. Thanks!
This is not yet supported, however, there is a temporary workaround to get this working. You should add options to the paths in your openapi.yaml. Additionally, both get and options operations should point to the same cloud function, since the options request then acts as a warmup request for the cloud function. This is the most efficient setup, in terms of latency. Here is a simplified example:
paths:
/helloworld:
get:
operationId: getHelloWorld
x-google-backend:
address: $CLOUD_FUNCTION_ADDRESS
responses:
'200':
description: A successful response
options:
operationId: corsHelloWorld
x-google-backend:
address: $CLOUD_FUNCTION_ADDRESS
responses:
'200':
description: A successful response
Then, in your cloud function backend, you must also handle the preflight request (source). The Google documentation also provides an example with authentication, which has some additional headers. Here is an example without authentication:
def cors_enabled_function(request):
# For more information about CORS and CORS preflight requests, see
# https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request
# for more information.
# Set CORS headers for the preflight request
if request.method == 'OPTIONS':
# Allows GET requests from any origin with the Content-Type
# header and caches preflight response for an 3600s
headers = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET',
'Access-Control-Allow-Headers': 'Content-Type',
'Access-Control-Max-Age': '3600'
}
return ('', 204, headers)
# Set CORS headers for the main request
headers = {
'Access-Control-Allow-Origin': '*'
}
return ('Hello World!', 200, headers)
Note: the downside of API gateway not managing preflight requests in a proper manner results in a penalty of running the cloud function twice. But your second request should always be very fast since the first request acts as a warmup request.
Turns out that API Gateway does not currently have CORS support.
Reference.
Solution
Here is the solution. It is just as user14982714 stated. Add a host and x-google-endpoints to your oepnapi.yaml file at the top level:
host: my-cool-api.endpoints.my-project-id.cloud.goog
x-google-endpoints:
- name: my-cool-api.endpoints.my-project-id.cloud.goog
allowCors: True
However, be sure to replace my-cool-api.endpoints.my-project-id.cloud.goog with your API Managed Service URL. This can be found in your google cloud console under the API Gateway API here:
I covered the start to my endpoint name for privacy, however, yours should also end with .cloud.goog. If you haven't deployed a configuration yet, deploy it without the x-google-endpoints and host, then update it to include both. (To update your configuration go to API Gateway -> Your API -> Gateways Tab -> Your Gateway -> Edit- > Change API Config -> Create New)
Explanation
Now to explain why this works with Google Cloud API Gateway. The API Gateway uses endpoints under the hood. Most people don't know this is the case, however, after giving up on the API Gateway and moving back to Endpoints I noticed that my API Gateways were listed under the endpoint services. They do not show in the UI, but with the gcloud CLI, run this command gcloud endpoints services list and you should see your API Gateways. Crazy! But Google does this a lot.
So knowing this I tried adding allowCors: true to the x-google-endpoints and viola. It worked. I hope this helps someone out there.
swagger: "2.0"
host: "my-cool-api.endpoints.my-project-id.cloud.goog"
x-google-endpoints:
- name: "my-cool-api.endpoints.my-project-id.cloud.goog"
allowCors: True
Note: host and name should have the same API endpoint name
Configuring these lines in your config file enables CORS for API GATEWAY
[Reference][1]
[1]: https://cloud.google.com/endpoints/docs/openapi/support-cors#:~:text=CORS%20(Cross%2Dorigin%20resource%20sharing,would%20prevent%20cross%2Dorigin%20requests.
I had the same issue and solve it with a load balancer (originally used to add a custom domain to my API gateway).
I use my load balancer to add the missing header into the response.
You just need to add the "Access-Control-Origin" header:
Allow all
Access-Control-Origin:'*'
Allow a specific origin
Access-Control-Allow-Origin: http://example.com:8080
You can find the instructions here GCP - Creating custom headers.
If you do not have a load balancer implemented,
you can follow this tutorial to implement a new one Google API Gateway, Load Balancer and Content Delivery Network.
You can find more information regarding CORS at https://www.w3.org/wiki/CORS_Enabled.
I had similar issue with other API so I am not sure the same will work in your case but you can try - in react app when fetching the data, lets say with axios you can try
axios.post('http://localhost:3003/signup',this.data,{headers:{'Access-Control-
Allow-Origin':'*','Content-Type': 'application/json'}})
on the backend side - try this -
let cors=require('./cors')
app.options('*', cors());
It works in my case , hope it will help you.
I was able to render Text contents from Magnolia public REST API on Salesforce community.
ISSUE: Image files are being blocked by CSP (Content Security Policy)
TRIED: Added the Base URL a few different ways to in Site URL in CSP Trusted Sites
https://*.magnolia-cms.com
https://*.demopublic.magnolia-cms.com
https://demopublic.magnolia-cms.com
Also, included https://demopublic.magnolia-cms.com url in Trusted Sites for Script
What I am missing here?
That looks like a typical case of forgetting setting the CORS headers on Magnolia site, hence browser blocking the request as required by the spec:
For security reasons, browsers restrict cross-origin HTTP requests initiated from scripts. For example, XMLHttpRequest and the Fetch API follow the same-origin policy. This means that a web application using those APIs can only request resources from the same origin the application was loaded from unless the response from other origins includes the right CORS headers.
More details here
If you haven't done so before, you can add simple static CORS definition in headers using AddHeadersFilter. It was discussed previously eg here
I am trying to enable HTTPS on my Go App deployed to GAE flex environment. I have my custom domain successfully mapped, and am using Google-managed SSL certificates. I have app.yaml configured to redirect HTTP to HTTPS as follows:
handlers:
- url: /.*
script: _go_app
secure: always
Now there are two problems that I haven't been able to resolve so far.
First, the above configuration is supposed to redirect HTTP traffic to HTTPS, but apparently it is not happening.
Second, when I add https:// in the url box, I see three different behavior on Firefox, Chrome, and Edge. Edge identifies the website as secure, Firefox marks the website as secure connection, but says that it "has blocked parts of this page that are not secure", and surprisingly Chrome marks the website as Not secure (though it says certificate is valid!).
With these symptoms I was wondering if I should take additional steps to make redirecting and SSL work for my website? Specifically, I would like to know with App Engine, and managed SSL enabled:
Should I continue serving pages on HTTP using http.ListenAndServe(..), or need to switch to http.ListenAndServeTLS(..)?
In my Go app should I redirect HTTP to HTTPS? or the above setting is expected to work just fine?
Thanks in advance for your help and advice.
PS:
Trying out with different suggestions, I added Strict-Transport-Security: max-age=31536000; includeSubDomains to handlers' response. Does not seem if this helped with redirection either.
EDIT/PARTIAL ANSWER:
According to this documentation, under Authentication changes, the secure and login handlers are deprecated. The documentation suggests using Strict-Transport-Security or X-Forwarded-Proto instead.
I am using Strict-Transport-Security on the server side to enrich my response header:
func (h *STLHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
w.Header().Add("Strict-Transport-Security", "max-age=63072000; includeSubDomains")
h.nextHandler.ServeHTTP(w, req)
}
I was wondering if I am using this header in the right place?
For the second set of my problems I realized I have mixed content on my page. My mixed content was a http link to a set of fonts. When I fixed the mixed content, i.e. changed http to https, both Chrome and Firefox security warnings disappeared. You may also find this page Avoiding the Not Secure Warning in Chrome useful on this matter.
You need to check your app using:
http://[YOUR_PROJECT_ID].appspot.com
Or if you nedd HTTPS:
https://[YOUR_PROJECT_ID].appspot.com
If you want your own certificate you will need to upload it and then be available to use: https://your-domain.tld
From the docs:
For APIs that will be hosted on App Engine flexible environment, you must use the appspot.com domain, and the service name must be in the following format:
YOUR_PROJECT_ID.appspot.com
When you deploy your API to App Engine, a DNS entry with a name in the format YOUR_PROJECT_ID.appspot.com is created automatically.
For APIs that will be hosted on Compute Engine, Kubernetes Engine, or Kubernetes, you must use the cloud.goog domain, and the service name must be in the following format:
YOUR_API_NAME.endpoints.YOUR_PROJECT_ID.cloud.goog
Or you could just put a CDN in front like Cloudflare which will do all the SSL termination for you and if required redirect all HTTP to HTTPS
when trying to $.ajax to fetch some content from other websites in my website, I got the error.
Failed to load https://www.pinterest.com/: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8100' is therefore not allowed access.
I knew if the target website didn't allow localhost:8100 to fetch the data, I cannot fetch it in the client side on the web.
However, I found that mobile app (not mobile browser, but android/ios application) does not have the issue, they can simply get the website content by their default mobile built-in HTTP get function.
Do i want to ask why mobile will not encounter CORS issue (mobile can fetch the webcontent simply by the built-in http get function)?
thanks.
CORS is enforced by the browser to fulfill the security standard they have to meet. It does not affect requests made programmatically from any language, like a curl call on bash.
This is how CORS works, based on Wikipedia:
The browser sends the OPTIONS request with an Origin HTTP header. The value of this header is the domain that served the parent page. When a page from http://www.example.com attempts to access a user's data in service.example.com, the following request header would be sent to service.example.com: Origin: http://www.example.com.
The server at service.example.com may respond with:
An Access-Control-Allow-Origin (ACAO) header in its response indicating which origin sites are allowed. For example Access-Control-Allow-Origin: http://www.example.com
An error page if the server does not allow the cross-origin request
An Access-Control-Allow-Origin (ACAO) header with a wildcard that allows all domains: Access-Control-Allow-Origin: *
The way CORS works means it is optional. Browsers enforce it to prevent Javascript AJAX calls to perform malicious calls. But other types of consumers built by hand don't need to enforce CORS.
Think in this example:
You are the owner of somesite.com
Users authenticate to your site using the traditional cookie method
User logins into anothersite.com, built by an attacker. This site has the following code:
<script>fetch('http://somesite.com/posts/1', { method: 'DELETE' });</script>
... effectively performing a request to your site and doing bad things.
Happily, the browser will perform a preflight request when it sees a cross-domain request, and if your site does not respond saying that requests coming from anothersite.com are OK, you will be covered by default from a potential attack
This is why CORS only makes sense in the context of a browser. Javascript you send to the browser can not (at least easily) circumvent CORS because the only API that allows you to perform requests from the browser is written in stone. Additionally, there are no local storage or cookies outside of the browser.
Corolarium: Enforcing CORS is a deliberate action from the requester, or whoever is making the requests for you, not the sender. Javascript APIs in browsers enforce it. Other languages don't have the need for the reasons explained.
When running on a device, your files are served over the file:// protocol, not http://, and your origin will therefore not exist. That's why the request from the native device does not trigger CORS.