110 lines
4.9 KiB
Cheetah
110 lines
4.9 KiB
Cheetah
---
|
|
description: "Security standards for {{PROJECT_NAME}} — ALWAYS APPLIED on every file write"
|
|
alwaysApply: true
|
|
---
|
|
|
|
# Security Standards — {{PROJECT_NAME}}
|
|
> **Pillar 5**: Security is an always-on rule, not just a reactive agent.
|
|
> These rules apply to EVERY file write, regardless of feature or context.
|
|
|
|
## Credential & secret management
|
|
- **NEVER** hardcode API keys, tokens, or secrets in source code
|
|
- **NEVER** commit `.env` files — use `.gitignore` and document required vars in `.env.example`
|
|
- API keys belong in: flavored `--dart-define` build args, or a secrets manager (e.g. AWS Secrets)
|
|
- Use `flutter_secure_storage` for tokens/credentials — **NEVER** `SharedPreferences` for sensitive data
|
|
- Obfuscation: enable `--obfuscate --split-debug-info=build/debug-symbols/` for release builds
|
|
|
|
## Authentication & sessions
|
|
- JWT/session tokens: stored in `flutter_secure_storage`, never in `SharedPreferences` or local DB
|
|
- Implement token refresh with retry logic — never let a 401 show a raw error to the user
|
|
- Certificate pinning: required for production builds on {{AUTH}} — use `dio_pinning_interceptor`
|
|
- Biometric re-auth: require for any transaction > defined threshold
|
|
|
|
## Data & privacy
|
|
- **NEVER** log PII (names, emails, phone numbers, addresses) to console or crash reporters
|
|
- Sanitize all user inputs before sending to backend
|
|
- Use `SensitiveWidget` wrapper to exclude screens from screenshots / app switcher thumbnails
|
|
- Comply with platform privacy requirements: iOS `NSPrivacyAccessedAPITypes`, Android permissions
|
|
|
|
## Network security
|
|
- All API calls use HTTPS — no http:// in production
|
|
- Validate SSL certificates — never bypass with `badCertificateCallback: (_,_,_) => true`
|
|
- Add a timeout to every HTTP call: `connectTimeout: Duration(seconds: 10)`
|
|
- Rate-limit sensitive endpoints: auth, OTP, password reset
|
|
|
|
## Dependency security
|
|
- Run `dart pub outdated` monthly — flag packages with known CVEs
|
|
- Never use a package with <100 pub points without explicit tech lead approval
|
|
- Pin critical security packages to exact versions in `pubspec.yaml`
|
|
|
|
## Secure coding patterns
|
|
```dart
|
|
// ✅ Correct: secure token storage
|
|
final storage = FlutterSecureStorage();
|
|
await storage.write(key: 'access_token', value: token);
|
|
|
|
// ❌ Wrong: SharedPreferences for sensitive data
|
|
final prefs = await SharedPreferences.getInstance();
|
|
prefs.setString('access_token', token); // NEVER do this
|
|
|
|
// ✅ Correct: PII-safe logging
|
|
logger.info('User authenticated: userId=${user.id}'); // ok — id, not email
|
|
logger.debug('Payment processed: orderId=$orderId'); // ok — no card data
|
|
|
|
// ❌ Wrong: PII in logs
|
|
logger.info('Login: email=${user.email}, phone=${user.phone}'); // NEVER
|
|
|
|
// ✅ Correct: --dart-define for secrets (build arg, not in code)
|
|
// flutter build apk --dart-define=API_KEY=$API_KEY
|
|
const apiKey = String.fromEnvironment('API_KEY'); // acceptable
|
|
|
|
// ✅ Correct: certificate pinning with Dio
|
|
(dio.httpClientAdapter as IOHttpClientAdapter).createHttpClient = () {
|
|
final client = HttpClient();
|
|
client.badCertificateCallback = (cert, host, port) => false; // strict
|
|
return client;
|
|
};
|
|
```
|
|
|
|
## Deep linking & intent security
|
|
- Validate all incoming deep link parameters — never trust raw URL params
|
|
- Use `app_links` package for verified deep link handling
|
|
- Restrict URL schemes to known patterns — reject unknown schemes
|
|
- For OAuth callbacks: validate `state` parameter to prevent CSRF
|
|
|
|
## Storage security
|
|
- Encrypt locally cached sensitive data using `hive` with `HiveAesCipher`
|
|
- Clear sensitive data from memory after use (set to null, trigger GC)
|
|
- Do NOT cache auth tokens in network layer (no `dio_cache_interceptor` for auth endpoints)
|
|
- Use `SecureRandom` for nonce/token generation — never `Random()`
|
|
|
|
## Code obfuscation & binary protection
|
|
```yaml
|
|
# android/app/build.gradle — release config
|
|
buildTypes {
|
|
release {
|
|
minifyEnabled true
|
|
shrinkResources true
|
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
|
}
|
|
}
|
|
```
|
|
```bash
|
|
# Flutter release build with obfuscation
|
|
flutter build apk --release --obfuscate --split-debug-info=build/debug-symbols/
|
|
flutter build ipa --release --obfuscate --split-debug-info=build/debug-symbols/
|
|
```
|
|
|
|
## Release checklist
|
|
Before every production release, verify:
|
|
- [ ] No hardcoded secrets (`grep -r "api_key\|secret\|password\|token" lib/`)
|
|
- [ ] Debug flags disabled (`kDebugMode` guards on all debug-only paths)
|
|
- [ ] Obfuscation enabled in release build config
|
|
- [ ] Certificate pinning active and tested on both platforms
|
|
- [ ] Crash reporter PII filters configured (Sentry `beforeSend`, Firebase `setConsentType`)
|
|
- [ ] `flutter_secure_storage` used for all tokens — no `SharedPreferences` for sensitive keys
|
|
- [ ] Network calls all HTTPS — scan for `http://` in lib/
|
|
- [ ] Dependencies audited: `dart pub outdated --json | jq '.packages[] | select(.isDiscontinued)'`
|
|
- [ ] Deep link parameters validated
|
|
- [ ] App transport security / network security config reviewed
|