Lab 03 — Mobile Data Protection Policy
Difficulty: 3/5 | Runs locally: yes
Pairs with the Phase 04 WARMUP Chapter 9 (storage, Keystore, hardware-backed keys).
Why This Lab Exists (Purpose & Goal)
The Android app sandbox protects your data from other apps, but it does nothing about the data the app itself leaks — into logs, backups, screenshots, the clipboard, or indefinite local storage. The goal of this lab is to build the decision engine that chooses the right handling controls for a piece of data based on its classification and use, so that sensitive data never ends up on one of those leak surfaces.
The Concept, In the Weeds
The core skill is the storage decision, made in order of minimum exposure:
- Don't store it — the most secure data is data you don't keep on the device.
- Keep it server-side, fetched on demand with authorization (online-only actions).
- Encrypt it with a key in the Android Keystore (key material in the TEE/StrongBox, never in your process; optionally bound to user authentication).
- Plaintext in private storage — only for non-sensitive data.
But the decision is incomplete without the leak surfaces, because they bypass storage security entirely:
- Logs (
Logcat) — secrets logged in a debug build are readable; never log sensitive data. - Backups (
allowBackup/dataExtractionRules) — auto-backup can copy private data off device. - Screenshots / recents — the OS snapshots your UI; set
FLAG_SECUREon sensitive screens. - Clipboard — copied secrets are readable by other apps.
The policy this lab encodes: restricted data cannot use the clipboard, broad backup, or indefinite storage; high-risk actions remain online-only. The non-obvious lesson — "I encrypted it, so it's safe" is false if the same secret is logged, backed up, screenshotted, or copied. You must secure the whole lifecycle, not just the database.
Why This Matters for Protecting the Company
Mobile data leaks are a common and embarrassing breach class — credentials in logs harvested by other apps, PII in cloud backups, sensitive screens captured in the recents thumbnail. They violate privacy regulation (GDPR/HIPAA) and erode customer trust. When you can produce a data-protection policy that maps each datum to storage-class and log/backup/screenshot/clipboard/retention controls, you protect the company's data on devices it does not control — and you give the mobile team an unambiguous, testable spec instead of ad-hoc decisions.
Build It
Implement the policy engine: choose handling controls for synthetic mobile data by classification, offline need, export, backup, screenshot, clipboard, and retention. Restricted data cannot use clipboard, broad backup, or indefinite storage; high-risk actions remain online-only.
LAB_MODULE=solution pytest -q
# implement the resulting policy in the vulnerable/hardened Kotlin app variants
Secure Implementation Patterns
The policy engine — classification drives the leak-surface controls (mirrors solution.py):
def evaluate(record: dict) -> tuple[str, ...]:
issues = []
c = record.get("classification")
if c not in {"public", "internal", "restricted"}:
return ("UNKNOWN_CLASSIFICATION",) # fail closed on unknown class
if c == "restricted":
if record.get("clipboard"): issues.append("RESTRICTED_CLIPBOARD") # other apps read it
if record.get("screenshots"): issues.append("RESTRICTED_SCREENSHOTS") # recents thumbnail
if record.get("backup") != "excluded": issues.append("RESTRICTED_BACKUP") # cloud copy
if not record.get("keystore_wrapped"): issues.append("MISSING_KEYSTORE_PROTECTION")
if record.get("retention_hours", 0) > 24: issues.append("EXCESSIVE_OFFLINE_RETENTION")
if record.get("high_risk_action") and record.get("offline_allowed"):
issues.append("HIGH_RISK_ACTION_OFFLINE") # high-risk actions stay online-only
return tuple(sorted(issues))
The insight encoded here: encryption is necessary but not sufficient — even Keystore-wrapped data leaks if it reaches the clipboard, a screenshot, or a cloud backup. The policy gates every surface.
The Android implementation each rule maps to:
// screenshots / recents
window.setFlags(WindowManager.LayoutParams.FLAG_SECURE, FLAG_SECURE)
// backups: exclude sensitive paths (or disable) res/xml/data_extraction_rules.xml
// Keystore-wrapped key, optionally requiring user auth
val key = KeyGenParameterSpec.Builder("k", PURPOSE_ENCRYPT or PURPOSE_DECRYPT)
.setUserAuthenticationRequired(true).setIsStrongBoxBacked(true).build()
// logging: never Log.d() a secret
Production practices to carry forward:
- Storage decision order: don't store → server-held → Keystore-encrypted → plaintext (last resort). The most secure data is data not on the device.
- Hardware-backed keys (TEE/StrongBox) keep key material out of your process; bind to user auth for sensitive operations.
- Secure the whole lifecycle — creation, use, storage, backup, display, clipboard, transfer, deletion — not just the database.
- Add instrumentation tests proving synthetic secrets never appear in logs, backups, screenshots, the clipboard, or crash telemetry.
Validation — What You Should Be Able to Do Now
- For any datum, choose between not-stored, server-held, Keystore-encrypted, and plaintext — and justify it by classification and use.
- Enumerate the leak surfaces (logs, backups, screenshots, clipboard) that bypass storage encryption, and the control that closes each.
- Explain why hardware-backed Keystore keys (TEE/StrongBox, user-auth-bound) protect material your process never sees — and why that is still moot if the plaintext leaks elsewhere.
The Broader Perspective
This lab teaches data-lifecycle thinking: a secret is only as protected as its weakest exposure across its entire life — creation, use, storage, backup, display, transfer, and deletion. Encrypting the database is necessary but never sufficient. That lifecycle lens is the same one behind cloud KMS and envelope encryption (Phase 02/07 — "encrypted at rest doesn't stop an app-level attacker"), behind evidence handling (Phase 00), and behind AI-agent data labeling (Phase 11). Securing data means securing every surface it touches, by default — not just the one you were thinking about.
Interview Angle
- "Where do you store an auth token on Android?" — Prefer not storing it (online-only); else server-held; else Keystore-encrypted (key in TEE/StrongBox, optionally user-auth-bound). And secure the lifecycle — keep it out of logs, backups, screenshots, and the clipboard, or the encryption is moot.
Extension (Stretch)
Implement the policy in the vulnerable/hardened Kotlin variants and add instrumentation tests proving synthetic secrets never appear in logs, backups, screenshots, the clipboard, or crash telemetry.
References
- Phase 04 WARMUP Chapter 9; Android Keystore / data-protection documentation.
- OWASP MASVS (data storage and privacy); GDPR/HIPAA data-handling principles.