Native Code Security
Securing Native Code Interactions¶
Native channels in Flutter (via MethodChannel or EventChannel) enable communication between Flutter and native code, but they introduce security risks if not properly guarded. This section covers techniques to validate inputs, sanitize data, and prevent code injection through these channels.
Input Validation: Ensuring Data Integrity¶
Always validate inputs before processing them in native code. Flutter and native code should agree on expected data formats, types, and ranges.
Example: Validating JSON Inputs in Flutter¶
import 'dart:convert';
String? validateInput(String rawInput) {
try {
final Map<String, dynamic> data = jsonDecode(rawInput);
if (data['type'] != 'safe') {
throw Exception('Invalid input type');
}
return data['content'];
} catch (e) {
return null;
}
}
Native Code Validation (Android Kotlin)¶
fun validateInput(input: String): Boolean {
return input.matches(Regex("^[a-zA-Z0-9\\s\\._-]{1,255}$"))
}
Commands:
flutter run --release # Test validation in a real device
dart format . # Ensure code adheres to style guidelines
Data Sanitization: Preventing Malicious Payloads¶
Sanitize data to remove or escape special characters that could trigger injection attacks (e.g., SQLi, XSS).
Example: Escaping HTML in Flutter¶
import 'dart:convert';
import 'dart:html';
String sanitizeHtml(String input) {
final document = window.document;
final div = document.createElement('div') as HTMLElement;
div.text = input;
return div.textContent ?? '';
}
Native Code Sanitization (iOS Swift)¶
func sanitizeInput(_ input: String) -> String {
return input.replacingOccurrences(of: "<", with: "<")
.replacingOccurrences(of: ">", with: ">")
}
Commands:
Preventing Code Injection: Avoid Dynamic Execution¶
Never execute untrusted code dynamically (e.g., eval() or exec()). Use parameterized APIs or whitelisting instead.
Example: Whitelisting Allowed Commands¶
Set<String> allowedCommands = {'fetchData', 'logout'};
String? validateCommand(String command) {
return allowedCommands.contains(command) ? command : null;
}
Native Code: Parameterized SQL Queries (Android)¶
String query = "SELECT * FROM users WHERE id = ?";
SQLiteStatement stmt = db.compileStatement(query);
stmt.bindString(1, userId);
Commands:
Secure Data Transmission: Encrypting Channel Data¶
Use HTTPS for all external communication and encrypt sensitive data in transit. Avoid sending raw payloads over unsecured channels.
Example: Encrypting Data with AES in Flutter¶
import 'package:encrypt/encrypt.dart' as encrypt;
String encryptData(String plainText, String key) {
final key = encrypt.Key.fromUtf8(key);
final iv = encrypt.IV.fromUtf8('123456789012');
final encrypter = encrypt.Encrypter(encrypt.AES(key));
return encrypter.encrypt(plainText, iv: iv).base64;
}
Commands:
Diagram: Secure Native Channel Workflow¶
[Flutter UI] --> [Input Validation] --> [Data Sanitization] --> [Secure Encryption] --> [Native Code]
| | | |
v v v v
[Filtered Input] <--> [Escaped Payload] <--> [Encrypted Data] <--> [Whitelisted Command]
Key takeaways¶
- Validate inputs rigorously at both Flutter and native layers to reject malformed or malicious data.
- Sanitize data by escaping special characters and using platform-specific sanitization libraries.
- Avoid dynamic code execution; use whitelisting or parameterized APIs to prevent injection attacks.
- Encrypt all sensitive data in transit using AES or similar algorithms.
- Test security with dedicated test cases and ensure compliance with secure coding standards.