Irbisa · Cheatsheet
Security
Secure storage, certificate pinning, obfuscation, OWASP mobile top 10
What are the key security practices for a Flutter app, and how do they map to the OWASP Mobile Top 10?
How do you securely store tokens and other sensitive data on the device?
import 'package:flutter_secure_storage/flutter_secure_storage.dart'; class TokenStore { TokenStore([this._storage = const FlutterSecureStorage()]); final FlutterSecureStorage _storage; String? _access; // memory only: gone when the process dies…Review this sign-in code: what security problems do you see, and how would you fix each one?
Future<void> onSignedIn(String accessToken, String refreshToken) async { final prefs = await SharedPreferences.getInstance(); await prefs.setString('access_token', accessToken); await prefs.setString('refresh_token', refreshToken); debugPrint('signed in, token=$accessToken'); final requestKey = Random().nextInt(1 << 32).toString(); // later used to sign requests await prefs.setString('request_key', requestKey);} Future<void> signOut() async { final prefs = await SharedPreferences.getInstance(); await prefs.remove('access_token');}A third-party service gives you an API key to put in the app. Can a secret live in the binary, and where does it belong?
// right: Publishable key (compiled in, restricted server-side, safe to ship)class Config { static const mapsKey = String.fromEnvironment('MAPS_KEY'); static const apiBase = String.fromEnvironment( 'API_BASE', defaultValue: 'https://api.example.com', );…What are App Transport Security and Network Security Config, and when do you have to touch them in a Flutter app?
<!-- iOS: ios/Runner/Info.plist - plaintext for one legacy host only --><key>NSAppTransportSecurity</key><dict> <key>NSExceptionDomains</key> <dict> <key>legacy-sensor.example.com</key>…How does code obfuscation work in Flutter, and how do you symbolicate crashes after enabling it?
# 1) Build a release with obfuscation + split debug infoflutter build apk --release \ --obfuscate \ --split-debug-info=build/symbols/v1_2_3 flutter build ipa --release \…How do you avoid leaking sensitive data through logs, screenshots, and clipboard?
import 'package:flutter/material.dart'; // App switcher: cover the UI while inactive, since iOS has no FLAG_SECURE.// Use as MaterialApp(builder: (_, child) => PrivacyCurtain(child: child!)).// Android: window.setFlags(FLAG_SECURE, FLAG_SECURE) in MainActivity instead.class PrivacyCurtain extends StatefulWidget {…Your app decodes the JWT, reads a
roleclaim ofadminand shows the admin tab, and the server does not re-check the role. Why is that a finding in a pentest report?// wrong: The tab is hidden; the endpoint is wide openfinal claims = JwtDecoder.decode(accessToken);if (claims['role'] == 'admin') { tabs.add(const AdminTab()); // repackaged build: force this branch, call the API}…A search box feeds its text straight into a
sqfliterawQuery, and a download saves under the filename the API returned; what do you fix first?import 'package:path/path.dart' as p;import 'package:sqflite/sqflite.dart'; // wrong: One apostrophe changes the statement; a crafted string changes the appFuture<List<Map<String, Object?>>> searchBad(Database db, String q, String sort) => db.rawQuery("SELECT * FROM notes WHERE title LIKE '%$q%' ORDER BY $sort");…local_authreturnstrueafter a Face ID prompt. What has that actually proven, and how do you turn it into real protection?What are the security pitfalls of using WebView in a Flutter app?
import 'package:webview_flutter/webview_flutter.dart'; // right: Constrained WebView (explicit allowlist, no JS bridge unless needed)class HelpCenterPage extends StatefulWidget { const HelpCenterPage({super.key}); @override State<HelpCenterPage> createState() => _HelpCenterPageState();…Why is a deep link untrusted input, and what stops another app from stealing yours?
// go_router: one guarded entry point for every incoming link// session: a ChangeNotifier that knows whether the user is signed infinal router = GoRouter( refreshListenable: session, redirect: (context, state) { final loggedIn = session.isSignedIn;…Find the bug: this interceptor should add the token only for our API, yet the token turns up in the logs of a server we do not own.
const apiBase = 'https://api.example.com'; class AuthInterceptor extends Interceptor { AuthInterceptor(this.tokens); final TokenStore tokens; @override void onRequest(RequestOptions options, RequestInterceptorHandler handler) { // only our own API gets the token if (options.uri.toString().startsWith(apiBase)) { options.headers['Authorization'] = 'Bearer ${tokens.access}'; } handler.next(options); }}A teammate wants to add a pub package with 30 likes to handle payments. How do you decide, and how do you keep the dependency tree safe over time?
Users are signed out after moving to a new phone, and a few Android launches throw a decryption error reading the token. What happened?
import 'package:flutter/services.dart';import 'package:flutter_secure_storage/flutter_secure_storage.dart';import 'package:shared_preferences/shared_preferences.dart'; const _storage = FlutterSecureStorage( iOptions: IOSOptions(…What is SSL/certificate pinning and how do you implement it in Flutter?
import 'dart:io';import 'package:dio/dio.dart';import 'package:dio/io.dart';import 'package:flutter/services.dart'; /// Trusts ONLY the CA bundled with the app: any other chain, including a…This client is meant to pin the API certificate. Does it stop a proxy whose CA the device trusts, and what would you change?
HttpClient pinnedClient() { final client = HttpClient(); client.badCertificateCallback = (cert, host, port) { final pin = base64Encode(sha256.convert(cert.der).bytes); return pin == kApiCertPin; }; return client;}How does OAuth 2.0 with PKCE work for mobile apps and why is it required?
import 'dart:convert';import 'dart:math';import 'package:crypto/crypto.dart';import 'package:flutter_appauth/flutter_appauth.dart'; // What PKCE adds, by hand: a random verifier and its S256 challenge…How do you design access- and refresh-token rotation, and how does reuse detection catch a stolen refresh token?
Find the bug: after an hour in the background, opening the app often signs the user out, though the refresh token is still valid.
void addAuth(Dio dio, TokenStore tokens) { dio.interceptors.add(InterceptorsWrapper(onError: (err, handler) async { final req = err.requestOptions; if (err.response?.statusCode != 401 || req.extra['retried'] == true) { return handler.next(err); } try { final pair = await tokens.refresh(); // POST /auth/refresh, the server rotates the pair req..extra['retried'] = true..headers['Authorization'] = 'Bearer ${pair.access}'; handler.resolve(await dio.fetch(req)); } on DioException catch (e) { handler.reject(e); } }));}How do you detect a rooted or jailbroken device, and why can a tester with Frida still defeat your check?
A teammate encrypts the offline document cache with AES, using a key derived from the user's email and a constant IV copied from a tutorial. What breaks?
import 'dart:convert';import 'dart:math';import 'dart:typed_data';import 'package:cryptography/cryptography.dart';import 'package:flutter_secure_storage/flutter_secure_storage.dart';…The token store is encrypted, yet a forensics report pulled chat attachments and cached images off a locked test phone. How did they get out?
import 'dart:io';import 'package:flutter_cache_manager/flutter_cache_manager.dart';import 'package:path_provider/path_provider.dart';import 'package:webview_flutter/webview_flutter.dart'; /// Derived data belongs in Caches/tmp: not backed up, and the OS may reclaim it.…A modified build of your app unlocks the premium tier without paying, and the in-app purchase code looks correct. Where is the trust boundary wrong?
import 'package:dio/dio.dart';import 'package:in_app_purchase/in_app_purchase.dart'; class Purchases { Purchases(this._iap, this._api, this._entitlements); final InAppPurchase _iap;…