Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using CORS and CSRF together in Ionic app

I'm developing a android app using Ionic Framework based in a AngularJS web site I developed using Jhipster. As I already have server code running in my web application, I've choose Ionic to work as UI and call server when needed, but I'm having some issues in my development enviroment.

  1. As I run my application using Ionic serve, I need use CORS to make requests to server.
  2. My web application was developed using CSRF token with Spring Security

I'm using Apache CORS filter configured this way:

private void initCORSFilter(ServletContext servletContext, EnumSet<DispatcherType> disps) {
    FilterRegistration.Dynamic corsFilter = servletContext.addFilter("cors", new CorsFilter());
    Map<String, String> parameters = new HashMap<>();
    parameters.put("cors.allowed.origins", "http://localhost:3000");
    parameters.put("cors.allowed.headers", "x-auth-token, x-requested-with, Content-Type, Accept, cache-control, x-csrf-token, Origin, Access-Control-Request-Method, Access-Control-Request-Headers");
    parameters.put("cors.allowed.methods", "POST, PUT, GET, DELETE");
    parameters.put("cors.exposed.headers", "Access-Control-Allow-Origin, Access-Control-Allow-Credentials");
    parameters.put("cors.support.credentials", "true");
    corsFilter.setInitParameters(parameters);
    corsFilter.addMappingForUrlPatterns(disps, true, "/*");
}

then I used angular-csrf-cross-domain plugin to help with cross domain csrf requests:

.config(function ($urlRouterProvider,csrfCDProvider) {
    $urlRouterProvider.otherwise('/');
    //enable CSRF
    csrfCDProvider.setHeaderName('X-CSRF-TOKEN');
    csrfCDProvider.setCookieName('CSRF-TOKEN');
});

Then I try send a post request to my local server:

angular.module('consamiApp')
.factory('Register', function ($resource) {
    //globalURL is https://localhost:8080
    return $resource(globalURL+'api/register', {}, {
    });
});
.
.
.
createAccount: function (account, callback) {
    var cb = callback || angular.noop;

    return Register.save(account,
        function () {
            return cb(account);
        },
        function (err) {
            this.logout();
            return cb(err);
    }.bind(this)).$promise;
}

However I'm getting this message in firefox console:

Cross-origin locked request: The same origin policy (Same Origin Policy) prevents reading the remote resource in https://localhost:8080/api/register. (Reason: CORS heading 'Access-Control-Allow-Origin' is not present)

NEW INFORMATION

AngularJs make 2 CORS requests to the server when I submit the form I'm testing: OPTIONS and POST, the results of the requests are 200 OK and 403 Forbidden. These are the headers of the 2 requests and responses:

OPTIONS Request headers:

Host: localhost:8080
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:38.0) Gecko/20100101 Firefox/38.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: pt-BR,pt;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Origin: http://localhost:3000
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache

OPTIONS Answer headers:

Access-Control-Allow-Origin: http://localhost:3000
Content-Length: 0
Date: Tue, 30 Jun 2015 22:07:58 GMT
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=485A653AEAC8B8756DD3057BBF7FB862; Path=/; Secure; HttpOnly
CSRF-TOKEN=e8b3396c-63b2-47bf-9ad6-c1454628eb3b; Path=/
X-Application-Context: application:dev:8080
access-control-allow-credentials: true
access-control-allow-headers: origin,access-control-request-headers,x-requested-with,x-csrf-token,content-type,access-control-request-method,cache-control,x-auth-token,accept
access-control-allow-methods: POST
access-control-max-age: 1800

POST Request Headers:

Host: localhost:8080
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:38.0) Gecko/20100101 Firefox/38.0
Accept: application/json, text/plain, */*
Accept-Language: pt-BR,pt;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Content-Type: application/json;charset=utf-8
Referer: http://localhost:3000/
Content-Length: 109
Origin: http://localhost:3000
Cookie: _ga=GA1.1.123103160.1428358695; connect.sid=s%3AwD4KP4WBfhGO0JpFND3LpCzW.augts9fos9NMaZw%2B7XrNuilgaM8ocwSxaEUeDlIaVJ4; JSESSIONID=93200F4F4AFCEB28F10B130841808621
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache

POST Answer Headers:

Content-Type: application/json;charset=UTF-8
Date: Tue, 30 Jun 2015 22:07:58 GMT
Server: Apache-Coyote/1.1
Transfer-Encoding: chunked

Is there something I didn't noticed? The Ionic's official blog says I should not worry about CORS issue when deploying the app, however at least for tests, I really need solve this problems. Could you give me any options?

like image 863
brevleq Avatar asked Jun 25 '15 23:06

brevleq


3 Answers

Have you installed and configured cordova plugin whitelist that is mandatory for CORS query since Cordova 5.0.0

install it :

cordova plugin add cordova-plugin-whitelist

configure config.xml

You can keep your current setup with * or change for more restrictive rules

add a html policy on index.html, you shall add a Policy also. To authorise everything, here it is :

 <meta http-equiv="Content-Security-Policy" content="default-src *;
 style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline'
 'unsafe-eval'"

To verify that you have properly the plugin installed, check it into your cordova plugins with the following command:

cordova plugins 

You shall see the cordova-plugin-whitelist in it.

Secondly, you may need to add withCredentials to your $http (and therefore $resource) queries :

  .config(function($httpProvider) {
        $httpProvider.defaults.withCredentials = true;
    });
like image 171
aorfevre Avatar answered Oct 16 '22 12:10

aorfevre


When I edited the question and saw the OPTIONS response header with HttpOnly clause, I started believe that the problem was with self signed certificate I'm using in development enviroment.

Set-Cookie: JSESSIONID=485A653AEAC8B8756DD3057BBF7FB862; Path=/; Secure; HttpOnly

So I've decided disable https protocol in the web server and it worked correctly. Thanks for your help.

like image 20
brevleq Avatar answered Oct 16 '22 10:10

brevleq


The CORS spec is all-or-nothing. It only supports *, null or the exact domain: http://www.w3.org/TR/cors/#access-control-allow-origin-response-header

I don't think you can specify port numbers as its value.

like image 1
ThiagoPXP Avatar answered Oct 16 '22 11:10

ThiagoPXP