Capacitor SSL Pinning
Ionic Capacitor Plugin to perform SSL certificate checking/pinning.
This plugin validates the SHA256 fingerprint of a server's SSL certificate and compares it to a provided fingerprint.
On Android, the plugin also provides additional certificate information.
This software implements SSL (Secure Sockets Layer) pinning as a security measure. It is provided under the MIT License. The SSL pinning code included in this project is provided "as is" without any warranty, express or implied.
Important Notes
- Security Measure: SSL pinning enhances security by validating server certificates against known, trusted certificates or public keys. However, it does not guarantee absolute security.
- Implementation Responsibility: The effectiveness of SSL pinning depends on correct implementation and maintenance. Users are responsible for proper setup and regular updates to pinned certificates or keys.
- Maintenance Requirements: SSL pinning requires ongoing maintenance. Failure to update pinned certificates before they expire can result in app failure or loss of connectivity.
- No Warranty: The authors and copyright holders of this software provide it without warranty and do not guarantee it will meet your requirements or operate error-free.
- Limitation of Liability: The authors and copyright holders are not liable for claims, damages, or liabilities arising from the use or performance of this software.
- Testing and Verification: Users must thoroughly test SSL pinning in their specific environment.
- Compliance: Ensure your use of SSL pinning complies with all applicable laws, regulations, and platform policies.
- No Guarantee Against All Attacks: While SSL pinning can mitigate certain attacks, it cannot protect against all security threats.
- Potential Impact on Functionality: SSL pinning may interfere with development tools, debugging, or network inspection. Ensure you have a way to disable pinning during development and testing.
By using this SSL pinning code, you acknowledge reading this disclaimer and agreeing to its terms. Seek professional security advice for critical implementations and follow best practices for mobile and network security.
Notes
- On Fingerprints: Fingerprints can be expressed in different formats (e.g., with or without colons). This plugin normalizes fingerprints to lowercase and removes colons for comparison. While uppercase is preferred, colons are optional. Use the format recommended in the documentation.
- On Subject: The "subject" represents the hostname of the certificate. On Android, the plugin returns the certificate hostname; on iOS, it returns the provided URL.
- On Issuer: The "issuer" represents the certificate authority. Formats differ between iOS and Android, and results may not match exactly.


Installation
Using npm:
npm install capacitor-ssl-pinning
Using yarn:
yarn add capacitor-ssl-pinning
Sync native files:
npx cap sync
Obtain Fingerprint
Via Website
- Obtain the certificate using a browser. See: How to get a certificate.
- Open the certificate in a text editor and copy the public key to the clipboard.
- Visit SAML Tool.
- Paste the public key into the text area.
- Select
SHA-256
as the algorithm.
- Copy the fingerprint (with colons).
Via Command Line
openssl x509 -noout -fingerprint -sha256 -inform pem -in /path/to/cert.pem
Via Built-in CLI Tool
This package includes a CLI tool that can fetch and display SSL certificate information for any domain.
Install globally:
npm install -g capacitor-ssl-pinning
yarn global add capacitor-ssl-pinning
Or use it in your project:
npm install capacitor-ssl-pinning
yarn add capacitor-ssl-pinning
Usage:
npx ssl-fingerprint example.com
npx ssl-fingerprint example.com example.org example.net
ssl-fingerprint example.com
ssl-fingerprint example.com --out certs.json
ssl-fingerprint example.com example.org example.net --out certs.json
ssl-fingerprint example.com --out fingerprints.ts --format fingerprints
You can also add it as a script in your package.json:
{
"scripts": {
"generate-fingerprint": "ssl-fingerprint example.com",
"generate-all-fingerprints": "ssl-fingerprint example.com example.org example.net"
}
}
Then run it with:
npm run generate-fingerprint
npm run generate-all-fingerprints
The tool will display:
- Domain name
- Certificate subject
- Certificate issuer
- Valid from date
- Valid to date
- SHA256 fingerprint
Example output:
[
{
"domain": "example.com",
"subject": {
"C": "US",
"ST": "California",
"L": "Los Angeles",
"O": "Internet Corporation for Assigned Names and Numbers",
"CN": "www.example.org"
},
"issuer": {
"C": "US",
"O": "DigiCert Inc",
"CN": "DigiCert Global G2 TLS RSA SHA256 2020 CA1"
},
"validFrom": "Jan 30 00:00:00 2024 GMT",
"validTo": "Mar 1 23:59:59 2025 GMT",
"fingerprint": "EF:BA:26:D8:C1:CE:37:79:AC:77:63:0A:90:F8:21:63:A3:D6:89:2E:D6:AF:EE:40:86:72:CF:19:EB:A7:A3:62"
}
]
When using --format fingerprints
, the output will be in TypeScript format:
export const fingerprints = [
"EF:BA:26:D8:C1:CE:37:79:AC:77:63:0A:90:F8:21:63:A3:D6:89:2E:D6:AF:EE:40:86:72:CF:19:EB:A7:A3:62"
];
API
checkCertificate
checkCertificate(options: SSLCertificateCheckerOptions) => Promise<SSLCertificateCheckerResult>
SSLCertificateCheckerResult
export type SSLCertificateCheckerResult = {
subject?: string;
issuer?: string;
validFrom?: string;
validTo?: string;
expectedFingerprint?: string;
actualFingerprint?: string;
fingerprintMatched?: boolean;
error?: string;
};
SSLCertificateCheckerOptions
export type SSLCertificateCheckerOptions = {
url: string;
fingerprint: string;
};
Usage
Example:
SSLCertificateChecker.checkCertificate({
url: 'https://example.com',
fingerprint:
'50:4B:A1:B5:48:96:71:F3:9F:87:7E:0A:09:FD:3E:1B:C0:4F:AA:9F:FC:83:3E:A9:3A:00:78:88:F8:BA:60:26',
}).then(res => {
console.log(res.fingerprintMatched);
});
Example Interceptor
import { Injectable } from '@angular/core';
import {
HttpRequest,
HttpHandler,
HttpEvent,
HttpInterceptor,
} from '@angular/common/http';
import { from, Observable, switchMap, throwError } from 'rxjs';
import { SSLCertificateChecker } from 'capacitor-ssl-pinning';
import { environment } from 'src/environments/environment';
import { Capacitor } from '@capacitor/core';
@Injectable()
export class SslPinningInterceptor implements HttpInterceptor {
intercept(
request: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
if (Capacitor.getPlatform() === 'web') {
return next.handle(request);
}
return from(
SSLCertificateChecker.checkCertificate({
url: environment.baseUrlBase,
fingerprint: environment.fingerprint,
})
).pipe(
switchMap((res) => {
if (res.fingerprintMatched) {
return next.handle(request);
}
return throwError(() => new Error('Fingerprint not matched'));
})
);
}
}