Implementing SSL Pinning for Enhanced Security in Flutter Applications
What is SSL Pinning?
SSL Pinning revolves around the fundamental notion of verifying the certificate during the application’s API request. To thwart the perils of the Man In The Middle Attack (MITM), the esteemed OWASP highly endorses the adoption of SSL Pinning.
When employing HTTPS, the server generates a certificate and transmits it to the application. Nonetheless, the application readily accepts any certificate bestowed upon it, thereby rendering itself susceptible to a malicious man-in-the-middle attack (MITM). This form of attack entails an adversary intercepting the communication between the client and the server, introducing illicit certificates that pave the way for unauthorized access to sensitive user data, thereby compromising their privacy. As such, this scenario poses a significant security risk.
SSL Pinning establishes a reliable SSL certificate connection between the server and the client, instilling a sense of trust. Consequently, an extra layer of validation is implemented to verify if the certificate stored within the application corresponds to the one utilized by the server. In the event of a mismatch, the application possesses the capability to outrightly reject the certificate, safeguarding against potential security breaches.
Limitation
Due to the time-limited nature of SSL certificates, they necessitate regular renewal to ensure their validity. Consequently, each time a new certificate is issued, regardless of whether there are any modifications to our application, it becomes imperative to update the app accordingly. This practice ensures that the app remains synchronized with the latest certificate, thereby maintaining a secure and uninterrupted connection.
Get perm cert file
Here is the example in Chrome, click this button, then select “Connection is Secure” > “Certificate is Valid” > Details > Export
This is an example how I get a cert file on themoviedb.org
Then save the cer file to your project
- assets/cert/themoviedb.cer
don’t forget to register it to pubspec.yml
Create class for load cer file
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
abstract class CertReader {
static ByteData? cert;
static Future<void> initialize() async {
cert = await rootBundle.load('assets/cert/themoviedb.cer');
}
static ByteData? getCert() {
return cert;
}
}
Call this class on your main, make sure it’s called before you create http instance
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await ConfigReader.initialize(env);
}
Then you can call cert to your SecurityContext. By configuring the SecurityContext with our specific certificate, we establish a mechanism wherein the SecurityContext no longer relies on the operating system’s default certificate. Instead, it loads our designated certificate file and places trust solely in our own certificate.
This approach allows us to exercise greater control over the trust and validation process, enabling us to prioritize our own certificate over the system’s certificates.
SecurityContext securityContext = SecurityContext(withTrustedRoots: false);
securityContext.setTrustedCertificatesBytes(ConfigReader.getCert().buffer.asInt8List());
HttpClient client = HttpClient(context: await securityContext);
client.badCertificateCallback =
(X509Certificate cert, String host, int port) => false;
IOClient ioClient = IOClient(client);
If you are using Getx GetConnect, you can set cert in the list of TrustedCertificate, make sure these codes are placed before you call httpClient
ByteData? cert = ConfigReader.getCert();
List<int> trustedCert = [];
if (cert != null) {
trustedCert = cert.buffer.asInt8List();
trustedCertificates = [TrustedCertificate(trustedCert)];
}
httpClient.baseUrl = "https://api.themovie.db/";
httpClient.timeout = const Duration(minutes: 5);
And if you are using Dio, you can set the cert file using this
Dio dio = Dio();
ByteData bytes = ConfigReader.getCert()!;
(dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
(client) {
SecurityContext sc = SecurityContext();
sc.setTrustedCertificatesBytes(bytes.buffer.asUint8List());
HttpClient httpClient = HttpClient(context: sc);
return httpClient;
};
Summary
SSL pinning serves as an effective method to enhance the security of communication between mobile devices and servers. It addresses the vulnerability present in the default behavior of apps, where they accept any certificate received via HTTPS, thereby exposing themselves to potential man-in-the-middle attacks.
By implementing SSL pinning, a reliable SSL certificate connection is established between the server and the client. This introduces an extra layer of validation to ensure that the certificate stored within the application matches the one employed by the server.
Reference:
https://dwirandyh.medium.com/securing-your-flutter-app-by-adding-ssl-pinning-474722e38518