From http to https -- preparing the app

Hello all, I am developing an ionic client for a 3rd party server.
The next version of the server will be switching from HTTP to HTTPs as a default so I need to prepare my app.

The server, running behind Apache on Ubuntu , during setup will automatically install a self signed cert using

make-ssl-cert generate-default-snakeoil --force-overwrite
a2enmod ssl
a2ensite default-ssl
service apache2 restart

From my app perspective, I assume I need to:
a) convert all http to https
b) What else? I read up that https://github.com/wymsee/cordova-HTTP is required --> is this still required as of today? I am concerned that it seems to state in usage that .success and .error wonā€™t work. Iā€™d like minimal rework to my code, as I plan to provide the user with enable/disable SSL in case both modes are supported

3 Likes

Where Cordova is concerned, Iā€™d recommend going through the following security checklist. We check through most of these things when doing SSL and other secure transfers, etc.

https://cordova.apache.org/docs/en/4.0.0/guide_appdev_security_index.md.html

There are other useful security links at the bottom of that page as well.

~ Brad

1 Like

@ArcReaction thank you. Looks like I am pretty much in compliance to this list - except self signed. I canā€™t do much about that - the server is not in my control.

Are you using cordova-HTTP too? If not, what do you use for https? And if you are using cordova-http do you have separate code blocks for http and https? I was hoping to abstract it via a variable for the URL, but cordoba-http seems to have a different handling expectation

For https we are using cordova-http, and you are correct in that we are using different code blocks to handle http vs https. We have created a http interceptor that routes us to different code areas depending on which we need to use. With interceptors, you can view and/or modify http header requests and responses. For this specific topic, I canā€™t really post any code since it mostly belongs to company-paid projects.

You seem to be on the right track though so Iā€™d continue along with how you are going. Do have a look into Angular http interceptors though - itā€™s very cool stuff.

~ Brad

Beware that on Android handling of ssl connections is different for debug and release versions of your apk. I learned this the hard way. Self-signed certificates work in debug mode but not in release mode. Test if your setup will work in release mode by setting ā€˜android:debuggable=ā€œfalseā€ā€™ in your manifest file.

Also run an ssl validation check such as https://www.digicert.com/help/ to check for certificate chain issues. These will also fail in release mode but work in debug mode.

I used the default $http module to connect to backend services over ssl.

3 Likes

@tomkuipers thank you for the note. Since you used the default http module and not cordoba-http I assume that means I can have the same code block in terms of .success .error callbacks. Would you by any chance have any code samples on how to do https using the default $http handler?

Brad, thanks for the hint. I am already using http interceptors to implement some global http timeouts and special handling for some requests

I am really very keen on not having to change all my http.get & http.post commands in various files into two code blocks as they all are of the format

$http.get(httpurl)
.success(foo)
.error(foo)

If I understand it right, I now need to do something like

if (useSSL)
{
  $http.get(httpurl)
  .success(foo)
  .error(foo)
}
else
{
$cordovaHTTP.get(httpsurl)
{},function(response){}, function(response){}
}

Is there any way to mask this calling difference within the interceptor so irrespective of http or https, the interceptor make sure the success and error callbacks work? Unfortunately, this is my first app and things grew in a spaghetti fashion with http calls in various modules.

Iā€™ve started integration and I seem be stuck on this the moment I run my app - any help?
thanks

1     482215   error    Error: [$injector:modulerr] http://errors.angularjs.org/1.3.13/$injector/modulerr?p0=zmApp&p1=%5B%24injector%3Amodulerr%5D%20http%3A%2F%2Ferrors.angularjs.org%2F1.3.13%2F%24injector%2Fmodulerr%3Fp0%3DcordovaHTTP%26p1%3D%255B%2524injector%253Anomod%255D%2520http%253A%252F%252Ferrors.angularjs.org%252F1.3.13%252F%2524injector%252Fnomod%253Fp0%253DcordovaHTTP%250Ahttp%253A%252F%252F10.6.1.20%253A8100%252Flib%252Fionic%252Fjs%252Fionic.bundle.min.js%253A38%253A422%250Ahttp%253A%252F%252F10.6.1.20%253A8100%252Flib%252Fionic%252Fjs%252Fionic.bundle.min.js%253A53%253A427%250Aa%2540http%253A%252F%252F10.6.1.20%253A8100%252Flib%252Fionic%252Fjs%252Fionic.bundle.min.js%253A53%253A54%250Ahttp%253A%252F%252F10.6.1.20%253A8100%252Flib%252Fionic%252Fjs%252Fionic.bundle.min.js%253A53%253A311%250Ahttp%253A%252F%252F10.6.1.20%253A8100%252Flib%252Fionic%252Fjs%252Fionic.bundle.min.js%253A67%253A48%250As%2540http%253A%252F%252F10.6.1.20%253A8100%252Flib%252Fionic%252Fjs%252Fionic.bundle.min.js%253A39%253A306%250Ag%2540http%253A%252F%252F10.6.1.20%253A8100%252Flib%252Fionic%252Fjs%252Fionic.bundle.min.js%253A66%253A430%250Ahttp%253A%252F%252F10.6.1.20%253A8100%252Flib%252Fionic%252Fjs%252Fionic.bundle.min.js%253A67%253A64%250As%2540http%253A%252F%252F10.6.1.20%253A8100%252Flib%252Fionic%252Fjs%252Fionic.bundle.min.js%253A39%253A306%250Ag%2540http%253A%252F%252F10.6.1.20%253A8100%252Flib%252Fionic%252Fjs%252Fionic.bundle.min.js%253A66%253A430%250Aab%2540http%253A%252F%252F10.6.1.20%253A8100%252Flib%252Fionic%252Fjs%252Fionic.bundle.min.js%253A70%253A136%250Ad%2540http%253A%252F%252F10.6.1.20%253A8100%252Flib%252Fionic%252Fjs%252Fionic.bundle.min.js%253A49%253A383%250Atc%2540http%253A%252F%252F10.6.1.20%253A8100%252Flib%252Fionic%252Fjs%252Fionic.bundle.min.js%253A50%253A180%250Ahttp%253A%252F%252F10.6.1.20%253A8100%252F%253A203%253A30%250Ar%2540http%253A%252F%252F10.6.1.20%253A8100%252Flib%252Fionic%252Fjs%252Fionic.bundle.min.js%253A22%253A54725%250Ao%2540http%253A%252F%252F10.6.1.20%253A8100%252Flib%252Fionic%252Fjs%252Fionic.bundle.min.js%253A22%253A54616%0Ahttp%3A%2F%2F10.6.1.20%3A8100%2Flib%2Fionic%2Fjs%2Fionic.bundle.min.js%3A38%3A422%0Ahttp%3A%2F%2F10.6.1.20%3A8100%2Flib%2Fionic%2Fjs%2Fionic.bundle.min.js%3A67%3A322%0As%40http%3A%2F%2F10.6.1.20%3A8100%2Flib%2Fionic%2Fjs%2Fionic.bundle.min.js%3A39%3A306%0Ag%40http%3A%2F%2F10.6.1.20%3A8100%2Flib%2Fionic%2Fjs%2Fionic.bundle.min.js%3A66%3A430%0Ahttp%3A%2F%2F10.6.1.20%3A8100%2Flib%2Fionic%2Fjs%2Fionic.bundle.min.js%3A67%3A64%0As%40http%3A%2F%2F10.6.1.20%3A8100%2Flib%2Fionic%2Fjs%2Fionic.bundle.min.js%3A39%3A306%0Ag%40http%3A%2F%2F10.6.1.20%3A8100%2Flib%2Fionic%2Fjs%2Fionic.bundle.min.js%3A66%3A430%0Aab%40http%3A%2F%2F10.6.1.20%3A8100%2Flib%2Fionic%2Fjs%2Fionic.bundle.min.js%3A70%3A136%0Ad%40http%3A%2F%2F10.6.1.20%3A8100%2Flib%2Fionic%2Fjs%2Fionic.bundle.min.js%3A49%3A383%0Atc%40http%3A%2F%2F10.6.1.20%3A8100%2Flib%2Fionic%2Fjs%2Fionic.bundle.min.js%3A50%3A180%0Ahttp%3A%2F%2F10.6.1.20%3A8100%2F%3A203%3A30%0Ar%40http%3A%2F%2F10.6.1.20%3A8100%2Flib%2Fionic%2Fjs%2Fionic.bundle.min.js%3A22%3A54725%0Ao%40http%3A%2F%2F10.6.1.20%3A8100%2Flib%2Fionic%2Fjs%2Fionic.bundle.min.js%3A22%3A54616, http://10.6.1.20:8100/lib/ionic/js/ionic.bundle.min.js, Line: 67

I am loading cordova before angular, as well as boot strapping my app like so: (index.html)

 <script src="lib/ionic/js/ionic.bundle.min.js"></script>

    <!-- cordova script (this will be a 404 during development) -->
    <script src="cordova.js"></script>
    <script src="lib/ngCordova/dist/ng-cordova.min.js"></script>


    <!-- your app's js -->

    <script src="js/app.js"></script>

bootstrap:

 <!--  This is where is bootstrap angular - if I don't do this, then the window jumps around
    after the status bar comes on - because the window kicked in before phonegap got ready -->

    <script>
        window.ionic.Platform.ready(function () {
            console.log("******* PLATFORM READY ****");
            angular.bootstrap(document, ['zmApp']);
        });
    </script>

app.js:

// core app start stuff
angular.module('zmApp', [
                            'ionic',
                            'zmApp.controllers',
                            'cordovaHTTP'
                        ])

cordovaHTTP is installed:

cordova plugin list | grep HTTP
com.synconset.cordovaHTTP 0.1.4 "SSL Pinning"

Firstly, where are your controllers being included. Secondly, I found this on StackOverflow which may help you. The issue is almost exactly the same and there are a couple of solutions in the post: javascript - AngularJS 1.2 $injector:modulerr - Stack Overflow

Hope that helps,
~ Brad

Hi Brad,
Answering your 2nd point: Thanks for the link to the SO thread - I read through it. It seems to describe a systemic problem situation and that too migrating from an older version of angular - neither situation is applicable in my case. Other injectors work just fine - it is just cordovaHTTP that is not

In the past, Iā€™ve received injector errors when I forgot to include their .js file in index.html but in the case of cordovaHTTP there is no JS controller to manually add

Answering your first part - which controllers are you referring to?
My code is at https://github.com/pliablepixels/zmNinja

index.html loads my controllers here: https://github.com/pliablepixels/zmNinja/blob/master/www/index.html
cordova HTTP is injected into app here https://github.com/pliablepixels/zmNinja/blob/master/www/js/app.js (commented now as it does not work)

Edit: using one of the tips in that SO thread, I replaced ionic.min with ionic. The more descriptive error is:

ionic $ 0     996617   log      ******* PLATFORM READY ****
1     996628   error    Error: [$injector:modulerr] Failed to instantiate module zmApp due to:
[$injector:modulerr] Failed to instantiate module cordovaHTTP due to:
[$injector:nomod] Module 'cordovaHTTP' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.
http://errors.angularjs.org/1.3.13/$injector/nomod?p0=cordovaHTTP

But Iā€™m not quite sure what else I need to do for ionic/angular to find it

find . -name cordovaHTTP*
./platforms/android/assets/www/plugins/com.synconset.cordovaHTTP/www/cordovaHTTP.js
./platforms/ios/www/plugins/com.synconset.cordovaHTTP/www/cordovaHTTP.js
./plugins/com.synconset.cordovaHTTP/www/cordovaHTTP.js

Many thanks

Iā€™m a bit confused by this thread - you donā€™t need to do anything to use https other that use https in your request urls.

The error is since youā€™ve added cordovaHTTP as a dependency but havenā€™t included the javascript file in the index.html (at least from the code i can see).

However cordovaHTTP isnā€™t required so iā€™d just remove that, even if you included it you would have to re-write all your server side calls to use cordovaHTTP anyway so breaks your requirement of not wanting to make any significant changes to your code.

So basically just use https where you would have used http and you should be fine.

There is no magic to using https, your code can be the same whether http or https calls are made.
My service returns a $http object, in the controller I do stuff depending on success or failure.

service snippet:

   function myDataService($http) {

    /*jshint validthis:true */
    this.getSomeData = function() {
        return $http({
            url: 'https://my.api.com/some/endpoint',
            method: 'GET',
            headers: {
                'Accept': 'application/json'
            }
        });
    };
}

controller snippet:

vm.getTheData = function() {    
            myDataService.getSomeData()
                .success(function(resp) {
                    vm.error = false;
                    vm.data = resp.data;
                    vm.lastupdated = new Date().toISOString();
                })
                .error(function(err) {
                    vm.error = true;
                    console.log('error retrieving data', err);
                })
                .finally(function() {
                    console.log('finally - data');
                });
        };

Okay, Thank you! maybe Iā€™ve been incorrectly assuming I need cordovaHTTP then.

So per your advice , I am using standard http get and post, renaming the URL from http to https

Here is what I am seeing
a) Running in on my desktop (ionic serve -c) on safari works great - all https urls are resolved
b) Running it on iOS (8.3, 5S) does not work. The error I see is

2015-06-25 10:41:19.469 zmNinja[11393:4654460] NSURLConnection/CFURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9813)

On searching in SO, folks have suggested commenting out/redoing native code - do I really need to do that?

Does it work with ā€œhttpā€ on iOS?

Yes it does. I think I have an understanding of what is going on, but not how to solve it.

I ran it with an SSL cert checker and the problem it came up with was:
None of the common names in the certificate match the name that was entered (xxxxx). You may receive an error when accessing this site in a web browser

That is correct. To generate the self-signed certificate in apache on my server I did the following (ubuntu):

make-ssl-cert generate-default-snakeoil --force-overwrite
a2enmod ssl
a2ensite default-ssl

Now the problem is that it used my server hostname (camerapc)

I think what is happening is when I access the server from my mobile phone, I am using a ddns hostname.

I donā€™t quite know how to solve it, if this is the issue.

An update, that was not the problem.
I generated a certificate with the right common name and am using it - same error on iOS

Hmmā€¦ I have to brush up on my SSL but i think things might be working on your computer cause youā€™ve authorised the certificate locally and it trusts it but iOS doesnā€™t??

When working/trying out https locally I normally use ngrok (ngrok.com) and create a web tunnel from something.ngrok.com to localhost:xxxxx, localhost still uses http but ngrok creates a web interface which you can call with either http or https. Maybe try that?

At least then youā€™ll know itā€™s something to do with your certificate or something more fundamental about https on iOS.

Okay, so this was good learning. Documented so it may help others who are beginners like me:

(credits to many websites which I read - none of the below is original thinking from my side)

a) It is correct that you donā€™t need cordovaHTTP - standard $http works and all you need to do is change http to https (I wonder why people use cordovaHTTP then)

b) While generating a self-signed certificate (if you donā€™t have an option to use a paid certificate and the server is used for a small set of people), it is important that the self signed certificate you generate has the same common name as your server. For example, lets say you are deploying your solution in a server that maps to a hostname of ā€œhttps://myserver.ddns.netā€ make sure when generating the key you use a common name of ā€œmyserver.ddns.netā€. If you donā€™t do this, when you try and validate the cert, it will complain that the name you are using to access the URL does not match the common name within the cert. Specifically, if you use built in commands such as make-ssl-cert (available in Ubuntu), it uses the server hostname which may not be the same as your external url

A good way to generate and use the self-signed-cert (for Apache in this example):

(you can specify  any directory, I chose to store it in ssl/)
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/apache2/ssl/myserver.key -out /etc/apache2/ssl/myserver.crt

Next up, assuming you have already configured apache for SSL

vi /etc/apache2/sites-available/default-ssl.conf 

and update these lines with the location of your certs

SSLCertificateFile /etc/apache2/ssl/server.crt
SSLCertificateKeyFile /etc/apache2/ssl/server.key

c) Validate your server certs - there are many, but I found this site to be one of the best
https://www.ssllabs.com/ssltest/
You will potentially see two issues when you validate:

c.1) Trusted	No   NOT TRUSTED (Why?)
c.2) Chain issues	Contains anchor

The first one is expected. But the second one creates problems on mobile devices (it works fine on desktop with ionic serve -c)

To fix for mobile device:
a) email the certificate to your mobile device (/etc/apache2/ssl/myserver.crt) and install that certificate (DO NOT just go to your site with mobile safari - that just adds an exclusion for mobile safari - your app will still not work)
b) Install that cert from email - just open it and follow steps. I did the same for Android as well (this step was important for iOS, I just did it for Android too to make sure - never tested if android works without it)

Now you can access HTTPs on mobile devices with self-signed certs

Iā€™ve tested on:
a) iOS 5S 8.3
b) Android 4.4 --> both debug and release builds

Phew.

1 Like

Well, I solved the problem and wrote up a detailed howto ā€“ looks like Akismet thinks its spam and I need to wait for an admin to approve it :smile:

So it looks like my detailed post has still not been approved, so here is a condensed version:

For self-signed certificates to work reliably we need to:
a) while generating it make sure that the common name matches the server host DNS (or IP) where the server will be hosted
b) Install the certificate in the phones (as easy as emailing it to yourself and opening it in the phone and following install procedures)

You can avoid step b) if you also set up a root CA yourself that can act as a certifying chain

Tested on iOS 8.3 5S and Android 4.4 in debug and release mode

More details posted here: https://github.com/pliablepixels/zmNinja/blob/master/docs/SSL-Configuration.md

3 Likes