Skip to content

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: "&lt;")
               .replacingOccurrences(of: ">", with: "&gt;")
}

Commands:

flutter clean && flutter pub get  # Refresh dependencies


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:

flutter test lib/secure_channel_test.dart  # Run security-focused tests


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:

flutter pub add encrypt  # Add encryption library


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.