Mobile Security Shield (OtaSecurityShield)
The lib/src/security/ota_security_shield.dart module protects your mobile application against three major attack vectors before any network request or OTA patch application occurs:
- APK Anti-Repackaging (cryptographic SHA-256 fingerprint verification of the installed APK signing certificate).
- Compromised Device Detection (root detection on Android and jailbreak detection on iOS).
- TLS Certificate Pinning SHA-256 (validation of raw DER bytes from the server X.509 certificate).
1. Configuring Policy (OtaSecurityPolicy)
The security policy is defined using the OtaSecurityPolicy class and supplied to TkOtaPush.init(...):
final ota = TkOtaPush.init(
appReleaseVersion: '1.0.0+3',
securityPolicy: const OtaSecurityPolicy(
// 1. Authorized SHA-256 fingerprints of the official APK signing certificate
expectedApkSignaturesSha256: {
'A1:B2:C3:D4:E5:F6:01:02:03:04:05:06:07:08:09:10:11:12:13:14:15:16:17:18:19:20:21:22:23:24:25:26',
},
// 2. Block rooted or jailbroken devices
blockRootedOrJailbrokenDevices: true,
// 3. SHA-256 fingerprints of the OTA server TLS certificates (X.509 DER)
pinnedServerCertSha256Fingerprints: {
'42d889f8f4b6bf9d3abb767d3b5f215e0009e4d26cb7b958497e8b291e1b96dc',
},
),
onSecurityViolation: (OtaSecurityVerdict verdict) async {
debugPrint('Security violation (${verdict.violationType}): ${verdict.reason}');
},
);
Normalizing SHA-256 Fingerprints
The helper method OtaSecurityPolicy.normalizeSha256(String fingerprint) automatically strips colons (:), dashes (-), and whitespace, converting the string to lowercase:
'A1:B2:C3...'and'a1b2c3...'are handled identically.
2. APK Anti-Repackaging vs Offline Peer-to-Peer Sharing (Xender / ShareIt)
Across many emerging markets, users frequently share the raw .apk file between devices via offline peer-to-peer utilities (Xender, ShareIt, Bluetooth).
- Official APK shared via Xender: the APK package is unmodified; its cryptographic signing certificate matches the publisher's official keystore.
evaluatePolicyvalidates the fingerprint and 100% authorizes OTA updates. - Pirated APK decompiled and resigned: an attacker tampering with APK bytecode or assets must resign the bundle using their own private key. The observed SHA-256 fingerprint differs from
expectedApkSignaturesSha256: the SDK immediately blocks all OTA operations withOtaSecurityViolationType.apkSignatureMismatch.
Feeding Native APK Signatures to DefaultOtaDeviceIntegrityInspector
By default, DefaultOtaDeviceIntegrityInspector.readInstalledApkSignatureSha256():
- Calls the
apkSignatureProvidercallback if provided to the constructor. - Otherwise, falls back to the
Platform.environment['OTA_APK_SIGNATURE_SHA256']variable.
To bridge Android native certificate inspection (PackageManager.GET_SIGNING_CERTIFICATES via a MethodChannel):
const platformChannel = MethodChannel('com.myapp/security');
final inspector = DefaultOtaDeviceIntegrityInspector(
apkSignatureProvider: () async {
return await platformChannel.invokeMethod<String>('getApkSignatureSha256');
},
);
final ota = TkOtaPush.init(
appReleaseVersion: '1.0.0+3',
deviceIntegrityInspector: inspector,
securityPolicy: const OtaSecurityPolicy(
expectedApkSignaturesSha256: {'6b6929c8ff345cf008496328d7bff081a8ccfb89498bf9916ed668be3c3dedcf'},
),
);
3. Root Detection (Android) and Jailbreak Detection (iOS)
When blockRootedOrJailbrokenDevices: true, DefaultOtaDeviceIntegrityInspector.isDeviceRootedOrJailbroken() inspects Android and iOS filesystems (Platform.isAndroid || Platform.isIOS) for suspicious paths:
| Platform | Inspected Paths (_defaultSuspiciousPaths) |
|---|---|
| Android (Root) | /system/app/Superuser.apk, /sbin/su, /system/bin/su, /system/xbin/su, /data/local/xbin/su, /data/local/bin/su, /system/sd/xbin/su, /sbin/magisk |
| iOS (Jailbreak) | /Applications/Cydia.app, /Library/MobileSubstrate/MobileSubstrate.dylib, /private/var/lib/apt, /private/var/stash |
You can supply your own path list via customSuspiciousPaths in DefaultOtaDeviceIntegrityInspector, or implement the OtaDeviceIntegrityInspector abstract class directly.
4. TLS Certificate Pinning SHA-256 (OtaCertificatePinner & OtaPinnedHttpOverrides)
To safeguard asset downloads and Dart HTTPS network traffic against Man-in-the-Middle (MitM) attacks through rogue root certificates, the SDK exposes OtaCertificatePinner and OtaPinnedHttpOverrides.
How OtaCertificatePinner Works
OtaCertificatePinner.computeDerSha256Hex(List<int> derBytes)calculates the lowercase SHA-256 hexadecimal digest of raw DER bytes (cert.der) from the server's X.509 certificate.- When
pinnedSha256Fingerprintsis empty,verifyCertificateDerreturnstrue. - When
enforcedHostsis populated (e.g.,{'ota.saramoney.com'}), pinning is only enforced against those hosts; if left empty, pinning applies globally.
Global Setup with HttpOverrides.global
import 'dart:io';
import 'package:tk_ota_push/tk_ota_push.dart';
void configureTlsPinning() {
final pinner = OtaCertificatePinner(
pinnedSha256Fingerprints: {
'42d889f8f4b6bf9d3abb767d3b5f215e0009e4d26cb7b958497e8b291e1b96dc',
},
enforcedHosts: {'ota.saramoney.internal'},
);
HttpOverrides.global = OtaPinnedHttpOverrides(pinner);
}
5. Security Failure Behaviors (OtaSecurityVerdict)
During calls to ota.syncWithRemoteConfig(...), security verification executes at Step 0b, prior to querying RemoteConfigGatekeeper or the network:
Violation Type (OtaSecurityViolationType) | Cause | SDK Behavior |
|---|---|---|
apkSignatureMismatch | APK SHA-256 signature missing or not listed in expectedApkSignaturesSha256. | 1. Calls onSecurityViolation(verdict) if configured.2. Returns OtaSyncOutcome with executionMode: OtaUpdateExecutionMode.blockedBySecurityShield and networkCallPerformed: false. |
deviceRootedOrJailbroken | blockRootedOrJailbrokenDevices == true and root/jailbreak binary/directory found. | 1. Calls onSecurityViolation(verdict) if configured.2. Returns OtaSyncOutcome with executionMode: OtaUpdateExecutionMode.blockedBySecurityShield and networkCallPerformed: false. |
tlsCertificatePinningMismatch | Server X.509 certificate rejected during TLS handshake. | HTTPS connection fails immediately before data exchange occurs. |