SSL Pinning in Ionic Cordova based Applications
Let say I own example.com and have a subdomain where an API is hosted, as such: api.example.com. I wish to use the API over SSL, So an SSL Certificate is created for the subdomain. After the certificate has been acquired, I installed the necessary certificates on my web server.
I wish for my client application to connect to the API. To mitigate against man-in-the-middle style attacks, This risk mitigated by browsers automatically by checking the SSL certificate fingerprints. But in Hybrid application, This risk is not ensured by the HTTP client libraries. so I wish to use SSL pinning in cordova applications too, so that the client will only communicate with my API server directly, not someone spoofing it like as in proxy network.
What is an MITM attack?
In cryptography and computer security, a man-in-the-middle attack (MITM) is an attack where the attacker secretly relays and possibly alters the communication between two parties who believe they are directly communicating with each other. Read
Thanks to a cordova plugin which actually matching the fingerprints of the server at runtime for every request and will give the response as “CONNECTION_NOT_SECURE” or “CONNECTION_SECURE”.
Reference Link:
https://github.com/EddyVerbruggen/SSLCertificateChecker-PhoneGap-Plugin
Let’s Integrate in Ionic Application
I assumed that you already have an Ionic application which communicates to the server using the APIs. Also you server has already integrated the necessary SSL certificates. and SSL certificates are signed with Some Authorities like Comodo, DigiCert or many more but it should not be self signed. Go to the root directory of ionic Application. make sure the project is in stable state before integration. run the below command. it will install necessary dependencies.
npm install
After this command. Install the SSL checker plugin.
ionic cordova plugin add cordova-plugin-sslcertificatechecker
Now the plugin is integrated our project. Add the platform Android / IOS. Skip this step if have already added the platform.
ionic cordova platform add android / ios
Extract the Fingerprints
Fingerprints of the server can easily be extracted using the Web browser, Follow the steps below.
- Open your server in your web browser.
- Before the Web URL box. Their is a lock Symbol which is representing the Secure server.
- Click on this lock button. it will show the menu to see the Certificates details like this.e.g https://stackoverflow.com
4. Click on “more information”. it will open the new window. Now go to “Security” tab on this new window. it will have an option to view certificate.
5. Clicking on “view certificate” button. it will show the details. as shown in the image below.
6. Copy the Fingerprints. as highlighted in this image below. make sure you copy the SHA-256 fingerprint. because our SSLChecker plugin will match the SHA-256 Algorithm fingerprints.
7. Now Replace all the “:” characters in the fingerprints text with “ ”space characters and save this fingerprint in your project constant file. you can see the example below.
Use the sslCertificateChecker Plugin in Ionic Project
The best place to check the Secure connection to define the function inside your request interceptor. so that for every request it check automatically. and take appropriate decision based upon condition. e.g as below.
import { Injectable, Injector } from '@angular/core';
import {
HttpEvent,
HttpHandler,
HttpInterceptor,
HttpRequest
} from '@angular/common/http';
import { Network } from '@ionic-native/network';
import { Observable } from 'rxjs/Rx';
import { CONFIG_CONSTANTS } from '../../common/constant/app-config';
import { MESSAGE_CONSTANTS } from '../../common/constant/message';declare var window: any;@Injectable()
export class RequestInterceptor implements HttpInterceptor {
helperFunction: HelperFunctions;constructor(private network: Network, private injector: Injector) { }intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {this.helperFunction = this.injector.get(HelperFunctions);let setHeader = {
'ContentType': 'application/json',
'Accept': 'application/json',
'DEVICETYPE': 'MOBILE',
'X-Requested-With': 'XMLHttpRequest',
'Content-Type': 'application/json',
'dataType': 'json'
};let Host = CONFIG_CONSTANTS.BASE_URL;if (this.network.type === 'none') {
this.helperFunction.showAlert(MESSAGE_CONSTANTS.CONNECTION_NOT_WORKING);
return next.handle(request);
}return this.checkSecurity(`${Host}${request.url}`, request).flatMap((modifiedReq) => {
let newReq = null;
if (modifiedReq['message'] === 'CONNECTION_SECURE') {
newReq = request.clone({
url: `${Host}${request.url}`,
setHeaders: setHeader
});
}
return next.handle(newReq);
});
}checkSecurity(URL, request) {
return new Observable((observer) => {
window.plugins.sslCertificateChecker.check(
(message) => {
return observer.next({req: request, message: message});
},
(message) => {
return observer.error({req: request, message: message});
},
URL,
CONFIG_CONSTANTS.FINGERPRINT);
});
}
}
In this code above. In the starting, I imported the necessary dependent libraries and constants. then implement the interceptor function. Here note that this interceptor function
will return Observables. then i inject the helperFunction service which will show the message whatever passed it to their function you can notify the user in different ways like toast, dialog. then i defined custom headers for my server. you may have different.
After that this code is checking the network connectivity. if the application is not connected to the Internet then it show the dialog message to user otherwise will proceed.
After that called a asynchronous function “checkSecurity” which is using the plugin to check connection status and will return the message in observable.
This function is receiving two parameters server URL and interceptor request handler as “request”. it is called the sslCertificateChecker plugin check function and passing it success callback function, fail callback function, server URL and fingerprints. Inside the callbacks just return the message to new observable which return it to caller function.
After that FlatMap will return modified request Observable. Here,
FlatMap — creates an observable immediately for any source item, all previous observables are kept alive and collects all individual observable and returns all observables in a single array without caring the order of observable, works asynchronously.
Now it modified the request if the connection is secure and passing the request to next handler.
Now you run the application and check it! is it working fine. I know implementing this procedure will have little impact on performance but will ensure security and avoid MITM. I hope this tutorial will help you to implement SSL pinning.
In last, Learning is the key to success. If you find any improvement in this article. please let me know and help others. Thanks.