XHR Request fail with CORS Access-Control-Allow-Origin on Cordova android 10
See original GitHub issueBug Report
Problem
Simple GET xhr request (https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests) in cordova-android@^10.0.0 trigger CORS
What is expected to happen?
Simple xhr GET request should not trigger CORS
What does actually happen?
Simple xhr GET request should trigger CORS
Example: Access to XMLHttpRequest at ‘https://www.google.com/’ from origin ‘https://localhost’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.
Information
I have tested with two Cordova applications out of the box :
- The first one in Cordova 9.1 works fine the GET xhr call retrieve the remote site content XHR request save as CURL from Chrome network
curl ‘https://www.google.com/’
-H ‘authority: www.google.com’
-H ‘user-agent: Mozilla/5.0 (Linux; Android 11; SM-G991B Build/RP1A.200720.012; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/93.0.4577.82 Mobile Safari/537.36’
-H ‘accept: /’
-H ‘x-requested-with: com.example.hellocdv9’
-H ‘sec-fetch-site: cross-site’
-H ‘sec-fetch-mode: cors’
-H ‘sec-fetch-dest: empty’
-H ‘accept-language: fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7’
-H ‘cookie: CONSENT=PENDING+960’
–compressed
Result in Chrome console :
The XMLHttpRequest in status 200 with Google.com site content
- The second one in Cordova 10.1.1 does not work and is blocked by CORS XHR request save as CURL from Chrome network
curl ‘https://www.google.com/’
-H ‘authority: www.google.com’
-H ‘user-agent: Mozilla/5.0 (Linux; Android 11; SM-G991B Build/RP1A.200720.012; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/93.0.4577.82 Mobile Safari/537.36’
-H ‘accept: /’
-H ‘origin: https://localhost’
-H ‘x-requested-with: com.example.hellocdv10’
-H ‘sec-fetch-site: cross-site’
-H ‘sec-fetch-mode: cors’
-H ‘sec-fetch-dest: empty’
-H ‘referer: https://localhost/’
-H ‘accept-language: fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7’
–compressed
Result in Chrome console :
The XMLHttpRequest in status 0 with the following error Access to XMLHttpRequest at ‘https://www.google.com/’ from origin ‘https://localhost’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.
Command or Code
I’ve created two Cordova applications
- Cordova 9.x
cordova create hellocdv9 com.example.hellocdv9 HelloWorldcdv9 cd hellocdv9/ cordova platform add android cordova build android adb install ./platforms/android/app/build/outputs/apk/debug/app-debug.apk
- Cordova 10.x
cordova create hellocdv10 com.example.hellocdv10 HelloWorldcdv10 cd hellocdv10/ cordova platform add android@^10.0.0 cordova plugin remove cordova-plugin-whitelist cordova build android adb install ./platforms/android/app/build/outputs/apk/debug/app-debug.apk
- File changes for both applications
www/index.html
32c32
< <meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *; img-src 'self' data: content:;">
---
> <meta http-equiv="Content-Security-Policy" content="default-src * data: gap: https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *; img-src 'self' data: content:;">
www/js/index.js
28a29,37
> let xhr = new XMLHttpRequest();
> xhr.open('GET', 'https://www.google.com');
> xhr.onload = function() {
> console.log(xhr, xhr.responseText);
> };
> xhr.onerror = function(e) {
> console.error(e, xhr);
> };
> xhr.send();
Environment, Platform, Device
Device
android: 11 target api: 30
Version information
First app
cordova: 9.1.0 cordova-plugin-whitelist: 1.3.5
Second App
cordova: 10.1.1 No plugin
Cordova Cli: 10.0.0
Checklist
- I searched for existing GitHub issues
- I updated all Cordova tooling to most recent version
- I included all the necessary information above
Issue Analytics
- State:
- Created 2 years ago
- Reactions:2
- Comments:12 (4 by maintainers)
Some background knowledge…
Content-Security-Policy
is a different security mechanism than CORS (Cross-Origin Resource Sharing).In cordova-android@10, we implemented something called a WebAssetLoader, which proxies requests through
https://localhost
protocol. The WebAssetLoader kind of acts like a private web server only accessible to your app. This was done because some web view features requires you to be on a “secure context” (e.ghttps
) for the features to be enabled. In doing so, it does enable the CORS enforcement.Cordova android 9.x uses the plain old file system (
file://
) which didn’t enforced CORs. This is why you see the XHR request work in 9.x, but not in 10.x. You can make 10.x behave like 9.x by enabling theAndroidInsecureFileModeEnabled
preference:<preference name="AndroidInsecureFileModeEnabled" value="true" />
But let’s assume you don’t want to use this workaround
CORS is a security mechanism for CORS-enabled browsers that are controlled by the backend server. So in this case,
https://google.com
must provide the required response headers for the browser to accept the request response. They do not provide theAccess-Control-Allow-Origin: https://localhost
orAccess-Control-Allow-Origin: *
response header, therefore the request is rejected by the browser / webview.There is no API available in the webview to disable CORS. Assuming you don’t have access to
https://google.com
to make the appropriate backend change, the only workaround at this point is to not use the browser’s request mechanism (neitherfetch()
orXMLHttpRequest
) and instead find/build a cordova plugin that does a native request, which is not bounded by CORS.Another approach is to configure a proxy server that is configured to use the CORS protocol in which your app can make request to, which will be redirected to
https://google.com
, then you can relay the response back to the client. This approach will still allow you to use the browser’s HTTP request APIs.Now that we got all that information out there… May I ask more details on your use case?
This maybe the most detailed answer I have ever read , thank you!