Secure IPC
TLS-Based Secure Communication¶
TLS (Transport Layer Security) is the standard for encrypting data in transit. It provides end-to-end encryption, integrity, and authentication, making it ideal for most use cases.
Implementation Steps¶
- Use HTTPS for Remote APIs:
Flutter’shttppackage supports HTTPS out of the box. Always use HTTPS endpoints for remote communication, and enable certificate pinning to prevent MITM attacks.
import 'package:http/http.dart' as http;
import 'dart:convert';
Future<void> sendSecureRequest() async {
final response = await http.post(
Uri.parse('https://api.example.com/secure-endpoint'),
headers: {'Content-Type': 'application/json'},
body: jsonEncode({'data': 'sensitive'}),
);
print(response.body);
}
- TLS Server for Native Modules:
For direct communication between Flutter and native code (e.g., via sockets), implement a TLS server in native code. For Android, useSSLServerSocketFactoryfromjavax.net.sslto create a secure server socket. For iOS, useURLSessionwith TLS configuration.
Android (Kotlin):
import javax.net.ssl.*
import java.security.KeyStore
import java.security.cert.CertificateFactory
import java.security.cert.X509Certificate
import java.net.ServerSocket
fun startTlsServer() {
val keyStore = KeyStore.getInstance(KeyStore.getDefaultType())
val certificateFactory = CertificateFactory.getInstance("X.509")
val certificate = certificateFactory.generateCertificate(java.io.FileInputStream("server.crt"))
keyStore.setCertificateEntry("server", certificate)
val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultType())
trustManagerFactory.init(keyStore)
val sslContext = SSLContext.getInstance("TLS")
sslContext.init(null, trustManagerFactory.trustManagers, null)
val sslServerSocketFactory = sslContext.serverSocketFactory
val serverSocket = ServerSocket(8080).apply {
sslServerSocketFactory.createServerSocket(this).use { socket ->
// Handle client connections
}
}
}
iOS (Swift):
import Foundation
import Alamofire
let session = URLSession(configuration: .default, delegate: nil, delegateQueue: nil)
let request = URLRequest(url: URL(string: "https://api.example.com/secure-endpoint")!)
let task = session.dataTask(with: request) { data, response, error in
// Handle response
}
task.resume()
- Certificate Pinning:
Pin the server’s certificate to avoid trusting untrusted CAs. Useflutter_secure_storagefor Flutter and native trust stores for Android/iOS.
Flutter (Dart):
import 'package:flutter_secure_storage/flutter_secure_storage.dart'
final storage = FlutterSecureStorage();
await storage.write(key: 'server_cert', value: base64Cert);
Android (Java):
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null, null);
ks.setCertificateEntry("server", certificate);
tmf.init(ks);
iOS (Swift):
let trust = SecTrustCreateWithCertificates(certificateData as CFData, nil, nil)
var trustResult: SecTrustResultType = .invalid
SecTrustEvaluate(trust!, &trustResult)
if trustResult == .proceed {
// Proceed with connection
}
Custom Protocol Implementation¶
Custom protocols are useful for low-level communication or when TLS is not feasible (e.g., peer-to-peer or legacy systems). They require careful design to ensure encryption, authentication, and integrity.
Key Components¶
- Encryption: Use AES-256 in GCM mode for symmetric encryption. Flutter’s
pointycastlelibrary supports AES. - Authentication: Add HMAC signatures to verify data integrity.
- Key Exchange: Use Diffie-Hellman (DH) or pre-shared keys (PSK) for secure key exchange.
Example: AES-256 with HMAC¶
Flutter (Dart):
import 'package:pointycastle/export.dart';
import 'package:crypto/crypto.dart';
String encryptData(String plainText, String key) {
final keyBytes = key.codeUnits;
final iv = IVParameter(IVParameter.generate(16));
final cipher = AESBlockCipher(
KeyParameter(keyBytes),
iv,
);
final encrypted = List<int>.filled(16, 0);
cipher.processBlock(plainText.codeUnits, 0, encrypted, 0);
return base64Encode(encrypted);
}
Native (Android Kotlin):
val cipher = Cipher.getInstance("AES/GCM/NoPadding")
val keySpec = SecretKeySpec(key.toByteArray(), "AES")
cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv)
val encrypted = cipher.doFinal(data.toByteArray())
Best Practices for Secure IPC¶
- Prioritize TLS: Use TLS for most IPC scenarios due to its maturity and built-in protections against common attacks.
- Validate Inputs: Sanitize all data to prevent injection attacks, even when encrypted.
- Secure Key Management: Store cryptographic keys in secure storage (e.g., Android’s Keystore, iOS’s Keychain) and avoid hardcoding them.
- Use Forward Secrecy: For custom protocols, implement ephemeral key exchange (e.g., DH) to protect past communications.
- Monitor for Errors: Handle exceptions gracefully and avoid exposing sensitive information in logs or error messages.
Key takeaways¶
- TLS is the default choice for secure IPC due to its robust encryption and authentication features.
- Custom protocols require careful design, including encryption, HMAC, and secure key exchange.
- Always validate inputs and use secure storage for cryptographic keys.
- Certificate pinning is critical for TLS-based communication to prevent MITM attacks.
- Avoid plaintext data in all IPC channels; encrypt payloads before transmission.