checklist
Keep Dependencies Updated
Code Obfuscation and Minification
Secure API Keys and Sensitive Data
Secure ApI authentication
Secure API Access to Only Google Play Store Apps
Implement Data Encryption
Validate and Sanitize All User Inputs
Certificate Pinning and Network Security
Regular Vulnerability Testing & Logging
Secure Storage and Access Control
Protect Against Reverse Engineering and Code Tampering
Securing the Flutter Base URL with Environment Variables and Dependencies
Keep Dependencies Updated
Regularly update all Flutter/Dart packages and SDKs.
Use tools like pub outdated to audit dependencies and stay protected from newly discovered vulnerabilities.
Remove unused or deprecated packages to reduce attack surface.
Code Obfuscation and Minification
Obfuscate Dart code using flutter build apk --obfuscate --split-debug-info=build/symbols to make reverse engineering extremely difficult.
Minify your code to strip out unnecessary metadata that can be exploited by attackers.
Securing API Authentication
Securing API authentication is crucial for protecting data and services from unauthorized access. Strong authentication mechanisms ensure that only verified users or clients can interact with sensitive endpoints. Methods such as bearer tokens, short-lived access tokens with refresh tokens, mutual TLS (mTLS), HMAC signatures, and device attestation add layers of defense. Bearer tokens—widely used in mobile and web apps—allow stateless access control, while advanced schemes like token rotation and device attestation further reduce risks by limiting token validity and ensuring requests originate from untampered, authorized clients. Selecting and properly implementing these authentication approaches help safeguard APIs against common threats such as key theft, replay attacks, and credential abuse.
Securing API Access to Only Google Play Store Apps
Restricting API access so that only genuine, Google Play Store-installed apps can connect requires more than simple checks like custom headers or API keys, which can be easily bypassed if the app is reverse engineered. The most effective method is to integrate mobile attestation services—such as the Google Play Integrity API—which provide attestation tokens that validate an app's authenticity, source, and device integrity. When a request is made, the app sends an attestation token to the backend, which verifies it to confirm the call originates from an untampered app installed from the Play Store on a real device. This approach blocks most unauthorized access—even from cloned or modified apps and emulator environments—ensuring your API is only accessible to legitimate Android clients. For non-sensitive use cases, basic measures such as app-level API keys, custom headers, and rate limiting add friction but do not provide complete security.
Secure API Keys and Sensitive Data
Never store API keys or secrets in plain code. Use environment variables (like with flutter_dotenv) or secure server-side storage and retrieval.
Store sensitive data on-device using flutter_secure_storage, which encrypts data at rest.
Implement Data Encryption
Always transmit data over HTTPS, never HTTP, to encrypt it in transit.
Use strong, up-to-date TLS protocols (TLS 1.2 or 1.3).
Encrypt all data stored on the device and sensitive files with NIST-approved algorithms.
Validate and Sanitize All User Inputs
Perform input validation on both client and server sides to prevent injection attacks (e.g., SQL Injection, XSS).
Avoid exposing app logic or stack traces in error messages.
Certificate Pinning and Network Security
Implement SSL/TLS certificate pinning with plugins like http_certificate_pinning to prevent man-in-the-middle attacks.
Restrict network traffic to only required servers.
Regular Vulnerability Testing & Logging
Conduct regular automated vulnerability assessments (like with static/dynamic analysis tools) and manual penetration tests.
Use monitoring tools like Firebase Crashlytics or Sentry to watch for suspicious activity or errors in production.
Secure Storage and Access Control
Avoid storing sensitive data in plain files or shared preferences. Use secure keystores and encrypted storage.
Set strict file permissions to restrict access to app-specific data.
Protect Against Reverse Engineering and Code Tampering
Detect jailbreak or root status using plugins (like flutter_jailbreak_detection) to halt execution on compromised devices.
Regularly audit for code tampering or unauthorized modifications using runtime self-protection (RASP) technique
Securing the Flutter Base URL with Environment Variables and Dependencies
In Flutter app development, securing your frontend’s base URL—used for making API requests—is important for both security and maintainability. Rather than hardcoding the base URL directly in your code, you should leverage environment variables or specialized dependencies to keep this sensitive value out of source files and make it adaptable for different build configurations (development, staging, production). The most popular way to do this in Flutter is by using the flutter_dotenv package, which allows you to store environment-specific data in a .env file. This file is loaded at runtime and its contents are accessed securely within your app code, preventing easy discovery or static analysis in version control or code sharing.
To use this method, add the flutter_dotenv dependency to your pubspec.yaml, store your base URL (e.g., API_BASE_URL=https://api.example.com) in a .env file, and load it at app startup. You can then reference the base URL through environment lookups, keeping configuration separated from your main Dart code. This approach helps prevent accidental URL exposure, makes it simple to switch endpoints for different app builds, and contributes to better overall app security and flexibility. For advanced needs, consider encrypting the .env file, restricting its permissions, or using build-time variables with tools like flutter_config or platform-specific build scripts to further limit unauthorized access to sensitive endpoints.
- Code Obfuscation
- Background snapshots protection
- Local Authentication
- Secure Storage
- SSL Pinning
- Rooting or Jailbreaking protection
- Employing strong encryption 8 .Handle sensitive data with care 9 .Some More Important Facts
Code Obfuscation
Referene1
Referene2
Referene3
Referene4
Referene5
Code obfuscation is the process of modifying an app’s binary to make it harder for humans to understand. Reverse engineering your app can expose API keys, classes, function names, and all of your strings. This information can be crucial to your business logic and might give the attacker access to sensitive user data. Obfuscation hides these in your compiled Dart code, making it difficult for an attacker to reverse engineer your proprietary app.
Thankfully Flutter makes it very easy to obfuscate applications. To obfuscate your app, build a release version using the --obfuscate flag, combined with the --split-debug-info flag.
For APK:
Without splitting:
flutter build apk --obfuscate --split-debug-info=/<directory>
Splitting:
flutter build apk --target-platform android-arm,android-arm64,android-x64 --split-per-abi --obfuscate --split-debug-info=/<directory>
Background snapshots protection
Referene1
Referene2
Referene3
Referene4
When your app is in the background, a snapshot of the last state of your app is automatically shown in the task-switcher. Though useful which switching between apps, it’s undesirable to show sensitive user data such as bank account details. Seen this feature in action before? Perhaps the picture below will ring a bell —
method 1
import 'package:flutter_windowmanager/flutter_windowmanager.dart';
await FlutterWindowManager.addFlags(FlutterWindowManager.FLAG_SECURE);
//enables secure mode for app, disables screenshot, screen recording
Full Code
import 'package:flutter/material.dart';
import 'package:flutter_windowmanager/flutter_windowmanager.dart';
void main() {
runApp(
MaterialApp(
home: MyApp(),
)
);
}
class MyApp extends StatefulWidget{
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
void initState() {
Future.delayed(Duration.zero, () async { //to run async code in initState
await FlutterWindowManager.addFlags(FlutterWindowManager.FLAG_SECURE);
//enables secure mode for app, disables screenshot, screen recording
});
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
//your app content here
)
);
}
}
Method2
Future<void> secureScreen() async {
await FlutterWindowManager.addFlags(FlutterWindowManager.FLAG_SECURE);
}
@override
void initState() {
secureScreen();
super.initState();
}
Method3
dependencies:
flutter:
sdk: flutter
flutter_windowmanager: ^0.2.0
import 'package:flutter_windowmanager/flutter_windowmanager.dart';
Method5
Local Authentication
Reference
Local authentication refers to an on-device authentication for the user. This is beneficial if your application has subscriptions or payment features, as it provides an extra layer of authentication after the screen lock.
For this, we will use biometric authentication on iOS (Touch ID or lock code) and the fingerprint APIs on Android (introduced in Android 6.0). The following plugin implements local authentication for flutter apps.
- Local Authentication
- Required Plugin
- Checking for biometric availability
- Checking biometric type
- Authentication using biometric
- Designing a simple App
Secure Storage
Handle sensitive data with care
Reference
The list of sensitive data is very broad — it encompasses anything that belongs to a user, for instance, passwords, tokens, identifiers, transaction histories.
Here is the list of data categories that OWASP treats as sensitive:
Usernames,
Authentication tokens,
Passwords,
Cookies,
Location data,
UDID/IMEI, Device Name,
Network Connection Name,
Personal Information (e.g., date of birth, address, Social, credit card data),
Application Data,
Stored application logs (e.g., for an Android App ADB logcat tool),
Debug information,
Cached application messages,
Transaction histories.
Here you can find more insights on insecure data storage.
Since user data is highly sensitive, you cannot store it like common preferences. There are various ways to store data locally in Flutter. However, our safest bet would be to use secure native storage such as IOS Keychain Services and Android KeyStore System.
Even though these two systems work in slightly different ways, they both offer a solution for storing small bits of data in a container that makes it much harder to extract data. There is already a plugin for secure storage in Flutter that will save the development team lots of time while properly saving sensitive data.
Some More Important Facts
USE CASE OF CODE OBFUSCATION and MINIFICATION
What Are Code Obfuscation and Minification?
Code obfuscation scrambles the code structure, renaming classes, methods, and variables to meaningless names, making it harder for attackers to understand and reverse-engineer your application.
Minification removes unnecessary characters (like whitespace and comments) and reduces code size, which helps with performance and complicates reverse engineering.
When to Use Code Obfuscation and Minification
Release Builds: Always apply obfuscation and minification for production/release versions of your app, especially before publishing to app stores. Debug builds should not be obfuscated to allow easier diagnosis of problems and better stack traces.
Distribution Outside Trusted Channels: If you distribute APKs outside official app stores, obfuscation helps reduce the risk of reverse engineering.
Apps Handling Sensitive Logic: Use them in applications that handle sensitive business logic, proprietary algorithms, or store/handle credentials or business secrets.
Compliance Requirements: If your app must satisfy certain compliance or regulatory requirements demanding code protection, obfuscation and minification should be mandatory.
Why Are They Important?
Prevents Reverse Engineering: Obfuscation makes it far more difficult for attackers to decompile your app and extract intellectual property, proprietary logic, or sensitive information.
Protects Intellectual Property: It shields unique algorithms, security mechanisms, and business logic from competitors and cybercriminals.
Thwarts Common Attacks: Aids in preventing tampering, piracy, code injection, or repackaging attacks.
Reduces Attack Surface: Minified code has fewer clues for attackers to identify vulnerabilities or exploit entry points.
Compliance With Best Practices: Many security audit tools and guidelines (such as those for financial and healthcare apps) recommend or require code obfuscation as part of the release process.
When to apply
Use the following command when building your app for release (Android or iOS):
Use Cases of Secure API Keys and Sensitive Data
When to Use Secure API Keys and Protect Sensitive Data
Whenever your app communicates with APIs that require authentication: If your Flutter app interacts with external services—such as cloud storage, maps, payment providers, push notifications, or private backends—you typically need to use API keys or tokens.
Whenever handling private user data or enterprise information: Any data that could cause harm or privacy violations if exposed, including user credentials, access tokens, or configuration secrets, should be handled with extra security.
For any environment with billing, quota, or abuse potential: Many APIs tie their usage to a paid account, so exposed keys can result in financial loss due to abuse or excessive requests.
During release or production builds: Security is especially critical when your app is distributed publicly, as attackers can reverse-engineer apps to extract hard-coded or poorly protected credentials.
Why is It Important?
Prevent Unauthorized Access
Attackers can use leaked API keys to impersonate your app, send malicious requests, or consume your paid resources—potentially incurring significant costs or triggering denial-of-service.
Exposed credentials may grant direct access to sensitive backend data or features, leading to breaches.
Safeguard User Privacy and Trust
User data accessed through exposed APIs can be stolen, manipulated, or leaked, resulting in privacy violations, compliance breaches, and loss of user trust.
Security issues may cause reputational damage and a drop in user retention.
Regulatory and Compliance Requirements
Many regions require strict handling of sensitive keys and secrets—especially if your app handles financial, healthcare, or personal information. Non-compliance can result in legal and financial penalties.
Limit Scope of Damage
Well-managed API keys (with proper permission scoping, rotation, and monitoring) reduce the risk if a breach does occur, keeping the potential damage contained.
Real-World Risks and Consequences
There are ongoing reports of severe breaches caused by accidentally exposed, hard-coded, or inadequately protected API keys—including app impersonation, data theft, financial fraud, and downtime from lost control over cloud resources
How to Implement Secure Handling
Never Hard-Code Secrets in Source Code
Do not include API keys, secrets, or tokens directly in your Dart code or configuration files checked into version control.
Use Environment Variables or External Files
Store secrets in files not included in your repository (e.g., .env) and load them at runtime using packages like flutter_dotenv:
import 'package:flutter_dotenv/flutter_dotenv.dart';
Future<void> main() async {
await dotenv.load(fileName: ".env");
String? apiKey = dotenv.env['API_KEY'];
}
Use Secure On-Device Storage
For values that must remain on the device, use flutter_secure_storage, which encrypts data using platform-specific secure storage (Android Keystore, iOS Keychain):
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
final storage = FlutterSecureStorage();
await storage.write(key: 'api_token', value: 'your_secret');
String? token = await storage.read(key: 'api_token');
Secure ApI authentication
Bearer Token Authentication
Token Rotation: Short-Lived Access Tokens + Refresh Tokens
Mutual TLS (mTLS)
HMAC (Hash-Based Message Authentication Code) Signatures
API Keys (with Restrictions)
OAuth 2.0 Authorization (w/ PKCE or Device Flow)
One-Time Passwords (OTP)
CAPTCHAs or Proof-of-Work
Bearer token authentication is a widely used method for securing APIs. It works by issuing an access token to the client after authentication (such as login). The client then includes this token in the Authorization header of every request to protected endpoints.
How It Works
After successful login, the server generates an access token (usually a JWT or random string).
The client stores this token (e.g., in memory or secure storage).
Each API call includes the token:
Authorization: Bearer <access_token>
The server validates the token:
If valid, the request is processed.
If missing or invalid, it returns 401 Unauthorized.
Advantages
Stateless: The server only needs to verify the token—no server-side session required.
Simple integration for both web and mobile apps.
Easy to revoke or expire tokens if needed.
Considerations
If the token is stolen, anyone with it can access the API until it expires.
Tokens should have a reasonable expiration time (for example, 15 minutes to a few hours)
Token Rotation: Short-Lived Access Tokens + Refresh Tokens
This method enhances security by using two tokens:
Access Token: Short-lived (e.g., 15 minutes), used for API requests.
Refresh Token: Long-lived, securely stored (recommended as an HTTPOnly cookie). Used to obtain new access tokens without re-authenticating.
How It Works
Login:
The server issues both an access token (expires quickly) and a refresh token (expires after weeks/months, stored in an HTTPOnly cookie).
Making Requests:
The client uses the short-lived access token in the Authorization header for each API call.
Token Expiry Handling:
When the access token expires, the client automatically uses the refresh token to request a new access token (often at a dedicated /refresh-token endpoint).
The refresh token is sent as an HTTPOnly cookie—unreadable by JavaScript and less prone to XSS attacks.
Token Rotation:
Every time the refresh token is used, the server rotates (issues a new refresh token) and invalidates the previous one.
If a stolen refresh token is used, rotation allows earlier identification and invalidation of compromised tokens.
Secure API Access to Only Google Play Store Apps
Restricting API access to only Google Play Store-installed apps significantly strengthens the protection of backend services and user data. This approach ensures that only authentic, non-tampered app versions—distributed via the Play Store—can interact with APIs, deterring unauthorized usage, fraud, and reverse engineering. Below are key use cases across various industries:
Mobile Banking and Financial Apps
Preventing Fraud: Ensures that only official banking apps can access sensitive account and payment APIs, blocking fake or repackaged clients and reducing risks of credential theft and identity fraud.
Compliance: Supports regulatory requirements by guaranteeing trusted app-to-server communication.
Subscription Media & Streaming Services
Content Protection: Restricts access to premium content APIs (e.g., HD video, music) so only official Play Store apps can fetch or stream, preventing piracy, URL scraping, and bulk downloads.
Subscription Management: Ensures only legitimate users’ devices can verify and renew subscriptions.
Ride-Sharing, Mobility, and Delivery Platforms
Fair Use: Secures driver and customer APIs against tampered apps that might spoof location, fares, or ride requests.
Fraud Prevention: Stops bots, automation, or cloned apps from exploiting promo codes or artificially manipulating bookings.
Digital Health and Telemedicine Apps
Privacy and Data Security: Makes certain that only the genuine healthcare or telehealth app can access patient data, preventing unauthorized third-party access or data leak.
Online Marketplaces & E-Commerce
Order and Payment Integrity: Protects endpoints for placing orders, payments, or viewing personal order history, minimizing risk of scraper bots and fraudulent orders from fake apps.
Promotional Offer Control: Blocks automated abuse of promo codes or discount endpoints.
Social and Messaging Platforms
Identity Protection: Ensures that only the genuine app interfaces with APIs for login, messaging, or friend management, preventing third-party impersonation and phishing.
Enterprise and Internal Apps
Confidentiality: Restricts sensitive internal APIs or mobile dashboards to only company-controlled apps distributed via Play Store (possibly via private/internal releases), minimizing leaks if a device is lost or an APK is extracted.
Games and Competitive eSports
Fair Play Enforcement: Ensures only legitimate apps access leaderboard, matchmaking, or in-game economy APIs, reducing cheating/modding risks common with modified or unofficial clients.
Microtransaction Protection: Secures endpoints that handle in-game purchases against bot abuse or fraudulent requests.
Rewards and Loyalty Programs
Reward Integrity: Prevents automated bots or fake apps from mass-claiming rewards, points, or coupons, upholding trust in digital loyalty systems.
Setup on Google Play Console and Cloud
Enable the Play Integrity API for your app in the Google Play Console.
Link your app to a Google Cloud project where the API usage will be tracked.
Download your service account credentials (play-integrity.json) for server-side verification
Android App Integration
Add the Play Integrity API dependency to your Android project.
In the app, request an integrity token whenever the user performs a sensitive action (e.g., login, payment, data access).
Generate a secure random nonce.
Call the Play Integrity API to receive a token
val token = integrityManager.requestIntegrityToken(request)
Send the Token via X-PLAY-INTEGRITY Header
Each sensitive API request to your backend should add the Play Integrity token as the X-PLAY-INTEGRITY header.
Example:
POST /api/your-endpoint HTTP/1.1
Host: your-backend.com
Authorization: Bearer {jwt-or-api-token}
X-PLAY-INTEGRITY: {integrity_token_here}
Backend Verification
On the server, extract the X-PLAY-INTEGRITY header.
Use your backend's Google service account credentials to call Google's verification API (decodeIntegrityToken) and obtain the decoded verdict.
Validate:
The token is authentic and untampered.
The app recognition verdict is PLAY_RECOGNIZED.
The app and device match your expected values.
Implementing Data Encryption in Flutter
Protecting User Credentials and Tokens
User Passwords: Encrypting stored passwords and authentication tokens ensures that, even if storage is compromised, an attacker cannot retrieve plaintext credentials.
Session Tokens: Prevents token replay or misuse by keeping tokens secure, especially on mobile devices where storage may be less protected.
Securing Financial Transactions
Payment Data: Ensures that sensitive payment information (e.g., credit card numbers, bank details) is encrypted both at rest and in transit.
Mobile Wallets: Encrypts card information and transaction history to protect against unauthorized access if the device is lost, stolen, or compromised.
Confidential Messaging and Communications
Chat Applications: Encrypts messages end-to-end, meaning only the sender and recipient can read their contents, protecting against interception or eavesdropping.
Voice and Video Calls: Uses encryption to secure call content from being monitored or recorded by third parties.
Secure Storage of Personal Information
Healthcare and Medical Records: Protects electronic health records, personal identifiers, and medical histories, helping comply with data privacy regulations.
Identity and Contact Information: Keeps addresses, phone numbers, and ID documents secure from data breaches.
Safeguarding Enterprise and Corporate Data
Business Apps: Encrypts plans, strategies, and confidential company information stored on employee devices.
Document Management Systems: Secures sensitive files, contracts, and intellectual property from unauthorized access.
Regulatory Compliance
GDPR, HIPAA, PCI DSS: Many global regulations require encryption of customer and business data to ensure privacy and avoid penalties for breaches.
Secure API Communications
API Traffic: Ensures that data exchanged between clients (apps) and servers is encrypted, preventing interception by attackers during transmission and protecting backend APIs from data leakage.
Device Theft or Loss Protection
Mobile and IoT Devices: Encrypts local app data, making it unrecoverable for anyone without proper credentials if a device is lost or stolen.
Cloud Data Security
Cloud Storage: Encrypts files and databases stored in cloud infrastructure, so even if storage is accessed improperly, the contents remain unreadable without keys.
Securing sensitive data in your Flutter app is essential to protect user information and prevent unauthorized access. Below are practical methods to implement data encryption in Flutter, leveraging best practices and reliable open-source packages.
Using the encrypt Package (AES Example)
AES (Advanced Encryption Standard) is a widely used symmetric encryption algorithm that ensures data confidentiality.
Installation
Add to your pubspec.yaml:
dependencies:
encrypt: ^5.0.1
Example: AES Encryption & Decryption
import 'package:encrypt/encrypt.dart';
final key = Key.fromUtf8('16charslongkey!!'); // For AES-128 use 16 chars
final iv = IV.fromLength(16);
final encrypter = Encrypter(AES(key, mode: AESMode.cbc));
String encryptText(String text) {
final encrypted = encrypter.encrypt(text, iv: iv);
return encrypted.base64;
}
String decryptText(String encryptedText) {
final decrypted = encrypter.decrypt64(encryptedText, iv: iv);
return decrypted;
}
Recommendation: Always use a securely generated random key and IV for better security.
Securely Storing Encrypted Data
For storing tokens, credentials, or any sensitive information on the device, combine encryption with platform-level secure storage.
Using flutter_secure_storage
Automatically encrypts data at rest.
Uses iOS Keychain and Android Keystore.
Installation
Add to pubspec.yaml:
dependencies:
flutter_secure_storage: ^8.0.0
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
final storage = FlutterSecureStorage();
// Write securely
await storage.write(key: 'api_token', value: 'your_encrypted_token');
// Read securely
final token = await storage.read(key: 'api_token');
// Delete securely
await storage.delete(key: 'api_token');
Data is encrypted and available only to your app.
Full Example: Encrypt, Then Store Securely
Combine both packages for layered security:
import 'package:encrypt/encrypt.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
final key = Key.fromUtf8('16charslongkey!!');
final iv = IV.fromLength(16);
final encrypter = Encrypter(AES(key, mode: AESMode.cbc));
final storage = FlutterSecureStorage();
Future<void> saveSecureData(String plainText) async {
final encrypted = encrypter.encrypt(plainText, iv: iv).base64;
await storage.write(key: 'secure_data', value: encrypted);
}
Future<String?> getSecureData() async {
final encrypted = await storage.read(key: 'secure_data');
if (encrypted == null) return null;
return encrypter.decrypt64(encrypted, iv: iv);
}
Certificate Pinning and Network Security
Certificate pinning and network security settings are critical for protecting mobile apps from man-in-the-middle (MitM) attacks and ensuring encrypted, trusted communication between the client and server. Below are concrete methods and best practices for implementing these security features in Flutter apps.
What is Certificate Pinning?
Certificate pinning ensures your app only trusts specific server certificates or public keys, rather than any certificate trusted by the device’s system. This blocks attackers from using forged or compromised certificates, even if a malicious certificate authority (CA) is involved.
How to Implement Certificate Pinning in Flutter
a. Using http and http/io_client (with Manual Pinning)
Step-by-Step Guide
Obtain Server Certificate or Public Key
Download your server's certificate (PEM format) or extract its SHA256 public key hash.
Store the Pin in Your App
Hard-code only the pin (never the entire certificate).
Create a SecurityContext and Override HTTP Client
import 'dart:io';
import 'package:http/io_client.dart';
final String pinnedCertSha256 = 'YOUR_CERTIFICATE_SHA256_HASH';
HttpClient createPinnedHttpClient() {
final client = HttpClient();
client.badCertificateCallback = (X509Certificate cert, String host, int port) {
// Pin SHA256 hash of the public key:
final certSha256 = sha256.convert(cert.der).toString();
return certSha256 == pinnedCertSha256;
};
return client;
}
final ioClient = IOClient(createPinnedHttpClient());
Use the Custom IOClient for Network Requests
final response = await ioClient.get(Uri.parse('https://your-secure-api.com/data'));
Use crypto package’s sha256 hashes for comparison, and keep your pins updated if certificates are rotated!
Using Third-Party Packages
ssl_pinning_plugin and dio support built-in certificate pinning for easier integration.
With dio, specify the SHA256 pins in the onHttpClientCreate callback.
import 'package:dio/dio.dart';
import 'dart:io';
import 'package:crypto/crypto.dart';
Dio dio() {
final dio = Dio();
dio.httpClientAdapter = DefaultHttpClientAdapter()
..onHttpClientCreate = (HttpClient client) {
client.badCertificateCallback = (cert, host, port) {
final certSha256 = sha256.convert(cert.der).toString();
// compare certSha256 with your pinned hash
return certSha256 == '<YOUR_PIN>';
};
return client;
};
return dio;
}
Configuring Network Security in Flutter
a. Use HTTPS Endpoints Only
Never send sensitive data over plain HTTP.
Redirect all HTTP requests to HTTPS.
b. Android Network Security Config
On Android, you can restrict cleartext traffic (unencrypted HTTP) using network_security_config.xml:
<!-- res/xml/network_security_config.xml -->
<network-security-config>
<base-config cleartextTrafficPermitted="false" />
</network-security-config>
Update your manifest:
<application
android:networkSecurityConfig="@xml/network_security_config"
...>
</application>
Securing the Flutter Base URL with Environment Variables and Dependencies
import 'package:flutter_dotenv/flutter_dotenv.dart';
pubspec.yml
flutter_dotenv: ^5.2.1
create env file in root directory folder
BASE_URL_101=https://motoshare.in # India
BASE_URL_3=https://motoshare.us # United States
BASE_URL_5=https://motoshare.ca # Canada
BASE_URL_6=https://motoshare.co # Colombia
BASE_URL_7=https://motoshare.jp # Japan
BASE_URL_8=https://motoshareafrica.com # South Africa
BASE_URL_9=https://motoshare.asia # Asia/Indonesia
BASE_URL_10=https://motoshare.mx # Mexico
BASE_URL_11=https://motoshare.id # Indonesia
BASE_URL_12=https://motoshare.com.cn # China
BASE_URL_13=https://motosharegulf.com # Gulf
BASE_URL_DEFAULT=https://motoshare.in # Default
env Not Declared in pubspec.yaml
Flutter won’t package any asset, including .env, unless you specify it in your pubspec.yaml file.
Check that your pubspec.yaml file includes:
text
flutter:
assets:
- .env
=================
uses-material-design: true
assets:
- .env
- assets/google_logo.png
- assets/facebook_logo.png
- assets/gobikes.png
- assets/icon/logo.png
- assets/icon/default.png
- assets/icon/logo5.jpg
in main.dart file mention
import 'package:flutter_dotenv/flutter_dotenv.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await dotenv.load(fileName: ".env");
final prefs = await SharedPreferences.getInstance();
// Fetch the saved baseUrl from SharedPreferences
String initialBaseUrl = prefs.getString('baseUrl') ?? 'https://motoshare.in'; // Default URL
runApp(DynamicAppWrapper(initialBaseUrl: initialBaseUrl));
}
get base url from env in function
String getBaseUrlForCountry(String countryId) {
// Compose the key as in your .env file
String key = 'BASE_URL_$countryId';
// Return from .env, or fall back to DEFAULT
return dotenv.env[key] ?? dotenv.env['BASE_URL_DEFAULT']!;
}
final selectedBaseUrl = getBaseUrlForCountry(_selectedCountryId);
not expose base url
String defaultBaseUrl = dotenv.env['BASE_URL_DEFAULT'] ?? '';
String initialBaseUrl = prefs.getString('baseUrl') ?? defaultBaseUrl;
give dynamic url
String baseUrl= '';
final prefs = await SharedPreferences.getInstance();
String defaultBaseUrl = dotenv.env['BASE_URL_DEFAULT'] ?? '';
String baseUrls = prefs.getString('baseUrl') ?? defaultBaseUrl; // Default URL
Top comments (0)