Ionic $http request with 403 error on iPad device


#1

I’m scratching my head with one problem in ionic.
I have an app, I run it with simulator (ionic emulate -lcs), works find, $http can call the backend service with post. But after I deploy this app on to my iPad, same http call gets 403 error.

The backend server is an apache httpd server, I have added the “Header set Access-Control-Allow-Origin “*”” to httpd configuration file.
config.xml have all three whitelist tags:

  <access origin="*"/>
  <allow-intent href="*"/>
  <allow-navigation href="*"/>

Also in plist file of the iOS project, I have the NSAppTransportSecurity configured:

<key>NSAppTransportSecurity</key>
<dict>
  <key>NSAllowsArbitraryLoads</key>
  <true/>
</dict>

Same code runs on iPad got a 403 forbidden issue.

Can anybody help me with this? thank you.

cordova plugin list:
cordova-plugin-compat 1.0.0 "Compat"
cordova-plugin-console 1.0.3 "Console"
cordova-plugin-contacts 2.0.1 "Contacts"
cordova-plugin-device 1.1.2 "Device"
cordova-plugin-inappbrowser 1.2.1 "InAppBrowser"
cordova-plugin-splashscreen 3.1.0 "Splashscreen"
cordova-plugin-statusbar 2.1.3 "StatusBar"
cordova-plugin-whitelist 1.2.2 "Whitelist"
ionic-plugin-keyboard 2.0.1 “Keyboard”

codova version 6.0.0
ionic version 1.7.14

code of making $http request:

  .factory("Service", function($http){
    return {
      requestPayment : function(uuid, eventId, request){
        $http.post("https://hostinfo/"+uuid+"/"+eventId, request).then(
          function successCallback(response) {
            console.log(response);
          }, function errorCallback(error) {
            console.log("Error:"+JSON.stringify(error));
          }
        );
      }
    }
  });

#2

You might be dealing with CORS issue here. Check this article out and see if it can help.


Forbidden 403
#3

Thank you for reply. I found the reason is inside my backend.
My backend is using Tomcat, one of the tomcat filters is designed for handle CORS request, it named: org.apache.catalina.filters.CorsFilter, it has a design flaw in handling the “Origin” send from ionic, the $http sends “file:///” as the value of header “Origin”, however, CorsFilter can not recognize the “file:///”, it is expecting an URL start with “http://” or “https://”, so marked the request from ionic app as an invalid request, then response with 403.

I have to re-write the CrosFilter in Tomcat to handle Origin header from ionic.


#4

Hi zhangzzh, I have the same issue as you, Tomcat cannot deal with Ionic POST requests from iOS or Android devices, although they work just fine for GET requests or POST requests coming from emulators with livereload.

What did you change on Tomcat’s CorsFilter? Can you share the relevant source code?

Thanks!


#5

Hi, What I changed was to create a CustomizedFilter and registered it with Tomcat, in the filter, I copied the code from Tomcat CorsFilter and change the doFilter method,

switch (requestType) {
case SIMPLE:
// Handles a Simple CORS request.
this.handleSimpleCORS(request, response, filterChain);
break;
case ACTUAL:
// Handles an Actual CORS request.
this.handleSimpleCORS(request, response, filterChain);
break;
case PRE_FLIGHT:
// Handles a Pre-flight CORS request.
this.handlePreflightCORS(request, response, filterChain);
break;
case NOT_CORS:
// Handles a Normal request that is not a cross-origin request.
this.handleNonCORS(request, response, filterChain);
break;
default:
// Handles a CORS request that violates specification.
this.handleNonCORS(request, response, filterChain); //This line was: this.handleInvalidCORS(request, response, filterChain);

break;
}


#6

In the original CorsFilter, there is a parameter named allowdAllOrigin, but it does not work.


#7

I’ve been looking into this issue the whole day, and learned a few things. The problem is that this CorsFilter checks if the URI is valid in the isValidOrigin(String origin) method. It would be safer to just allow the “file://” origin right before the new URI() call:

protected static boolean isValidOrigin(String origin) {
    // Checks for encoded characters. Helps prevent CRLF injection.
    if (origin.contains("%")) {
        return false;
    }

    // "null" is a valid origin
    if ("null".equals(origin)) {
        return true;
    }
        
    //Added condition to accept Cordova-like "file://" origin
    if("file://".equals(origin)){
    	return true;
    }

    URI originURI;

    try {
        originURI = new URI(origin);
    } catch (URISyntaxException e) {
        return false;
    }
    // If scheme for URI is null, return false. Return true otherwise.
    return originURI.getScheme() != null;

}

Your change just ignores all invalid CORS calls, which seems a bit too much.

My problem now is that I can’t disable the default CorsFilter, and as it comes first in the filter chain I’m still getting the 403 forbidden response. How did you make Tomcat ignore its own CorsFilter and use the manual one?


#8

Hi,

I have the same issue. Did you manage to solve this? I have a Spring Boot backend with Tomcat embeded to which my requests are sent. Can you please post your solutions after you’ve solved them? Also, maybe Ionic should be documented for this issue.


#9

I didn’t solve it the way I wanted to, but it is working. If you find this a bit hacky, yeah, it’s more than a bit. It’s not pretty.

I had to download Tomcat source code, modify the CorsFilter java file as I described above, rebuild catalina.jar (read tomcat’s docs on how to build tomcat) and copy it over the original file.

Yeah, every time I want to update my tomcat installation I’ll have to redo this whole process :confused:

If you manage to disable Tomcat’s default CorsFilter so it won’t come up first in the filter chain and break things before our CustomizedFilter can run it would be much much better. I just gave up before finding a way to make it work.

Hope it helps.


#10

I did not have the problem with loading order of filter, My filter was marked with annotation WebFilter, and Tomcat picked it up automatically without configuration web.xml and put it in front of all other filters.

JJ