# Chapter 16 Labs: Data and Application Security

This lab pack covers Chapter 16 of *Applied Cybersecurity: Foundations to Mastery*.
The chapter defends the application layer from web and API vulnerabilities (OWASP Top
10:2025, OWASP API Security Top 10:2023) through to mobile device security, database
least privilege, data classification, DLP, and privacy-enhancing technologies.

Five hands-on labs use deliberately vulnerable targets (Juice Shop, crAPI, DVGA),
a mobile static-analysis platform (MobSF), and offline Python tools for the data
and privacy engineering exercises. All targets are purpose-built for training; no
real user data is used in any lab.

---

## Prerequisites

- Docker Engine 24+ and Docker Compose v2.20+ on the host
- ~5 GB free disk space (images pulled on first `up`)
- For Lab 16.3 dynamic extension only: a rooted Android device or emulator with
  Frida installed (host setup; see Lab 16.3 section below)
- For Lab 16.5: internet access on first run for `pip install diffprivlib==0.6.6`
  (the `lab5-tools` container pulls it; subsequent runs use the pip cache)

---

## Quick Start

```bash
# Start every lab service
docker compose up -d

# Or start a single lab
docker compose --profile lab1 up -d   # Juice Shop only
docker compose --profile lab2 up -d   # crAPI + DVGA
docker compose --profile lab3 up -d   # MobSF
docker compose --profile lab4 up -d   # DLP tools
docker compose --profile lab5 up -d   # DP tools
```

Service ports when all running:

| Service     | URL                           | Lab   |
|-------------|-------------------------------|-------|
| Juice Shop  | http://localhost:3000         | 16.1  |
| crAPI web   | http://localhost:8888         | 16.2  |
| crAPI mail  | http://localhost:8025         | 16.2  |
| DVGA        | http://localhost:5013/graphql | 16.2  |
| MobSF       | http://localhost:8000         | 16.3  |

---

## Safety and Authorisation Note

**Run every offensive technique only against the local containers provided here,
or against a system you own and have explicit written authorisation to test.**
Probing live or third-party APIs, scanning systems you do not own, or walking
object identifiers without written authorisation is unlawful under the EU
Computer Misuse Directive 2013/40/EU and equivalent national laws (see Chapter 6
on authorisation and scope). The skill is identical; the authorisation is
everything.

---

## Lab 16.1 - OWASP Juice Shop: Map the Challenge Set to the Top 10

**Objective:** Navigate Juice Shop's challenge set, solving Access Control (A01),
Injection (A05), and Cryptographic/Configuration (A04/A02) challenges, then map
each win to its OWASP Top 10:2025 category and CWE.

### Setup

```bash
docker compose --profile lab1 up -d
# Browse to http://localhost:3000
```

Image: `bkimminich/juice-shop:latest` (access-date-current build: v19.2.1).

### Walkthrough

1. **Authorisation guard-rail (read before anything else).** Run this lab only
   against your local Juice Shop container. Juice Shop is designed to be attacked;
   the wider internet is not.

2. **Find the Score Board.** Juice Shop hides its challenge list behind a hidden
   route. Discovering it - a forced-browsing exercise - is itself the first
   challenge and teaches A01 (Broken Access Control) at its simplest. Hint: look
   at the JavaScript bundle for route names.

3. **Work the A01 (Access Control) challenges.** Attempt the Broken Access
   Control set from the Score Board:
   - View another user's basket by modifying the basket ID in the API request.
   - Access the administration panel as a normal user.
   - Manipulate a direct object reference to reach a resource you do not own.
   These are IDOR and missing-authorisation failures.

4. **Work A05 (Injection) challenges.** Bypass the login form with a SQL
   injection payload in the email field (try `' OR 1=1 --`). Trigger a reflected
   or DOM-based XSS payload. Note how a parameterised query closes the SQL
   injection door.

5. **Work A04/A02 challenges.** Find sensitive data exposed through weak
   protection or misconfiguration: exposed backup files, predictable tokens,
   leaked credentials in responses.

6. **Build the mapping table.** For each solved challenge record:
   - Challenge name
   - OWASP Top 10:2025 category (A01-A10)
   - Underlying CWE number
   - One-line fix

   The Score Board tags each challenge by category; your job is to translate
   the tag into the assessment language of section 16.2.4.

### Expected Output

A completed mapping table: challenge name, A0x:2025 category, CWE, and one-line
fix for each solved challenge.

### Verify Completion

- Score Board shows at least one challenge solved in each of: Access Control,
  Injection, Cryptographic Failures (or Security Misconfiguration).
- Your mapping table has a non-empty "fix" column for every row.

### Cleanup

```bash
docker compose --profile lab1 down
```

---

## Lab 16.2 - API Hacking: crAPI (REST) and DVGA (GraphQL)

**Objective:** Demonstrate BOLA (API1:2023), BFLA (API5:2023), BOPLA (API3:2023)
against crAPI (REST), then map the GraphQL attack surface of DVGA using
introspection and craft a depth/complexity DoS query plus a batching attack.

### Setup

```bash
docker compose --profile lab2 up -d
# crAPI web: http://localhost:8888
# crAPI mailhog (email confirmation): http://localhost:8025
# DVGA GraphQL: http://localhost:5013/graphql
```

Allow 30-60 seconds for crAPI's services to finish initialising (Postgres and
Mongo need to seed). If the crAPI web UI shows errors, wait and refresh.

Images used:
- `crapi/web:latest` and `crapi/api:latest` - OWASP crAPI (https://github.com/OWASP/crAPI)
- `dolevf/dvga:latest` - DVGA (https://github.com/dolevf/Damn-Vulnerable-GraphQL-Application)

### Walkthrough

**Authorisation guard-rail (read first, every time).** Run these only against the
local containers started above. Probing live or third-party APIs without written
authorisation is unlawful. Scope is not optional.

**Part A - REST: BOLA in crAPI**

1. Register two user accounts via http://localhost:8888. Confirm both via the
   MailHog UI at http://localhost:8025.
2. Log in as user A. Using a proxy (Burp Suite or OWASP ZAP), capture a GET
   request that fetches one of user A's resources - a vehicle or an order - and
   note the object identifier in the URL or response.
3. Replay the same request, substituting user B's object identifier (you may need
   to enumerate by incrementing an integer ID, or obtain B's ID from their
   profile).
4. If user B's data is returned, you have demonstrated **API1:2023 BOLA**: the
   endpoint authenticated you but never checked ownership.
5. Fix mapping: enforce an owner check server-side on every data-returning
   endpoint (`SELECT ... WHERE owner_id = $authenticated_user_id`).

**Part B - REST: BFLA and BOPLA in crAPI**

1. As a normal user, locate admin-only functions (look for routes under `/admin/`
   or check the JavaScript for hidden paths). Attempt to call them. Successful
   access is **API5:2023 BFLA** (you invoked a function above your privilege).
2. In a profile update or vehicle registration request, add a JSON property you
   should not control (for example `"is_admin": true` or `"balance": 99999`).
   If the server binds the property, you have demonstrated **API3:2023 BOPLA**
   (mass assignment).
3. Fix mapping: BFLA - gate every admin route with a role check in middleware.
   BOPLA - use an allow-list of accepted properties; never bind the whole
   request body to the model.

**Part C - GraphQL: Introspection and schema disclosure on DVGA**

1. Open a GraphQL client (GraphQL Playground via http://localhost:5013, or any
   HTTP tool) against the DVGA endpoint at http://localhost:5013/graphql.
2. Send the introspection query:
   ```
   { __schema { types { name fields { name } } } }
   ```
3. The full schema returned - every type, field, and mutation - is the finding.
   Introspection is enabled, handing an attacker a free map of the entire API.
4. Fix: disable introspection in production (or restrict it to authenticated
   internal callers only).

**Part D - GraphQL: Depth/complexity DoS and batching bypass**

1. Craft a deeply nested query to demonstrate the depth-DoS surface (API4:2023
   Unrestricted Resource Consumption). Example structure:
   ```
   { user { posts { comments { author { posts { comments { author { name } } } } } } } }
   ```
   A server with no depth limit will attempt to resolve this.
2. Send a batch of aliased operations in one HTTP request to show how per-request
   rate-limiting is bypassed:
   ```
   { a1: systemUpdate(clientMutationId:"x") a2: systemUpdate(clientMutationId:"x") ... }
   ```
3. Fix mapping: depth limit (e.g. max 5 levels), per-operation rate limiting
   (not per HTTP request), and batch size caps.

**Map and Remediate**

For each finding write the OWASP API risk ID, the affected endpoint, and the
specific fix. A finding without a mapped fix is half a finding.

### Expected Output

- At least one confirmed BOLA finding (different user's data returned).
- At least one BFLA or BOPLA observation from crAPI.
- Full DVGA schema via introspection.
- Evidence of a depth-DoS or batch request.
- A finding table with API risk IDs and one-line fixes.

### Verify Completion

- You can read another user's object data as user A in crAPI.
- The introspection query returns a non-empty type list from DVGA.

### Cleanup

```bash
docker compose --profile lab2 down -v
```

---

## Lab 16.3 - MobSF Static Analysis on a Vulnerable APK

**Objective:** Run MobSF static analysis on a deliberately vulnerable sample APK,
identify hard-coded secrets, dangerous manifest flags, and weak crypto, then map
each finding to an OWASP MASVS requirement.

### Setup

```bash
docker compose --profile lab3 up -d
# MobSF web UI: http://localhost:8000
```

Image: `opensecurity/mobile-security-framework-mobsf:latest`
(access-date-current release: MobSF v4.4.6, 21 March 2026).

**Obtain the sample APK before running the lab.** See `lab3/README-apk.md`
for the recommended sample. The OWASP UnCrackable Level 1 APK from the MASTG
project is the canonical choice:
  https://github.com/OWASP/owasp-mastg/tree/master/Crackmes/Android/Level_01

Download `UnCrackable-Level1.apk` and have it ready to upload.

### Walkthrough

**Authorisation guard-rail (read first).** Run this lab only against the
deliberately vulnerable sample APK provided, or an app you built yourself.
Decompiling, scanning, or instrumenting an application you neither own nor have
written permission to test is unlawful in most jurisdictions. Scope is not
optional.

1. Browse to http://localhost:8000. The MobSF landing page accepts an APK via
   drag-and-drop or the upload button.

2. Upload the sample APK. MobSF unpacks it, decompiles the bytecode, and runs
   its static engine automatically. No device is required.

3. **Read the manifest analysis.** In the MobSF report, inspect the parsed
   `AndroidManifest.xml` section:
   - Note exported components (activities, services, receivers reachable by
     other apps on the device).
   - Note the requested permissions and flag any dangerous ones.
   - Look for `android:debuggable="true"` (MASVS-RESILIENCE-1) and
     `android:allowBackup="true"` (MASVS-STORAGE-2).
   Map each dangerous flag to its MASVS v2 requirement ID.

4. **Hunt for hard-coded secrets.** In the Strings and Code sections, look for
   hard-coded API keys, credentials, private endpoints, or cryptographic key
   material baked into the package. Anything here was never protected by the
   Android Keystore or iOS Secure Enclave; it is now readable by anyone who
   decompiles the APK.

5. **Review the security scorecard.** MobSF assigns a severity score and lists
   findings by category (insecure storage, weak crypto, cleartext traffic,
   insecure logging). Triage: confirm true positives, discard noise, note
   severity and MASVS mapping.

6. **Write the finding table.** For each finding record: the finding name,
   the MASVS v2 requirement (e.g. MASVS-CRYPTO-1), the severity, and the fix.

### Dynamic Extension (Host Setup - Not Containerised)

The dynamic half of this lab (SSL-pinning bypass, runtime key dumping) requires
Frida attached to a rooted device or emulator you own. This cannot be
containerised because Frida needs direct USB or ADB access to the target device.

**Canonical setup:**
- Install Frida CLI tools on the host: `pip install frida-tools`
  (access-date-current: Frida v17.9.8, 11 May 2026;
  https://github.com/frida/frida/releases)
- Install the Frida server on the rooted Android device/emulator and start it.
- List running processes: `frida-ps -U`
- Trace pinning functions: `frida-trace -U -i "*pinning*" com.example.target`
- Attach a custom hook: `frida -U -f com.example.target -l hook.js`

Use these only on devices you own. The dynamic steps confirm what static
analysis predicted; the static lab above is self-contained and sufficient for
the chapter's learning outcomes.

### Expected Output

- MobSF report with at least one hard-coded secret finding.
- Manifest analysis table with dangerous flags mapped to MASVS requirements.
- A finding table with severity, MASVS ID, and one-line fix per finding.

### Verify Completion

- MobSF report shows a risk score and at least one finding in the "High" or
  "Warning" severity category.
- Your finding table has a MASVS requirement ID for each row.

### Cleanup

```bash
docker compose --profile lab3 down
# MobSF analysis data persists in the mobsf-data volume; remove with:
docker volume rm ch16_mobsf-data   # optional
```

---

## Lab 16.4 - Data Inventory Drill: Classify a Synthetic Dataset and Design a DLP Policy

**Objective:** Build a classified data inventory for a synthetic retailer dataset,
apply ISO/IEC 27001:2022 A.5.12/A.5.13 classification tiers, implement DLP
detection rules (regex, Luhn, label-match), and produce an action grid mapping
(sensitivity x confidence) to a DLP enforcement action.

**All data is synthetic. Never use real personal data in this lab.**

### Setup

```bash
docker compose --profile lab4 up -d
# The container generates the dataset and runs the classification automatically.
# View output: docker logs ch16-lab4-tools -f
```

To work interactively:
```bash
docker compose --profile lab4 run --rm lab4-tools bash
cd /lab4
python synthetic_dataset.py --rows 100
python classify_and_policy.py --csv synthetic_customers.csv
```

### Walkthrough

1. **Generate the synthetic dataset.** The `synthetic_dataset.py` script creates
   a CSV with ten columns of mixed sensitivity: `customer_id`, `full_name`,
   `email`, `date_of_birth`, `postal_address`, `payment_card_number` (Luhn-valid
   synthetic PANs), `passport_number`, `order_total`, `marketing_opt_in`,
   `internal_notes`. All values are invented; no real PII is involved.

2. **Inspect the Luhn check.** The script self-checks a sample PAN against the
   Luhn algorithm and prints confirmation. Understand why a bare 16-digit regex
   would match order numbers; the Luhn check eliminates most false positives by
   requiring the mod-10 checksum to pass.

3. **Build and review the data inventory.** `classify_and_policy.py` prints a
   classified inventory table with four columns per field: what it is, where it
   lives, why it is held (processing purpose), and retention period. Notice that
   `passport_number` is flagged `[!]` - it should be deleted after the KYC check
   passes, not stored indefinitely. This is the Optus-style latent risk the book
   describes: data retained beyond its stated purpose.

4. **Classify each column.** The script applies:
   - `Restricted`: `date_of_birth`, `payment_card_number`, `passport_number`
   - `Confidential`: `full_name`, `email`, `postal_address`
   - `Internal`: `customer_id`, `order_total`, `marketing_opt_in`, `internal_notes`
   Adjust the classification in `classify_and_policy.py` to match your own
   organisation's scheme and re-run.

5. **Review the DLP detection rules.** The script applies three detectors:
   - Regex + Luhn for `payment_card_number` (high confidence on Luhn pass, low
     on regex-only fail)
   - Regex for `passport_number` (medium confidence)
   - Classification-label match for Confidential fields (high confidence)

6. **Study the action grid.** The script prints the (sensitivity x confidence)
   to action mapping:
   - High-confidence Restricted to an external destination: BLOCK
   - Medium-confidence Confidential: QUARANTINE
   - Low-confidence Internal: LOG
   Note the "why start in monitor mode" explanation at the bottom of the output.

7. **Write up the one-page policy.** Combine the inventory table, detection rules,
   and action grid into a concise document an engineer could implement. This is
   the Lab 16.4 deliverable.

### Expected Output

Terminal output showing:
- The classified data inventory table (10 columns, classification + retention).
- DLP detection results for the first 5 rows (finding, confidence, action).
- The DLP action grid with rationale per cell.

### Verify Completion

- `payment_card_number` rows show `detector=regex+Luhn` and `action=BLOCK`.
- `passport_number` is flagged in the inventory as over-retained.
- The action grid has at least one BLOCK, one QUARANTINE, and one LOG cell.

### Cleanup

```bash
docker compose --profile lab4 down
```

---

## Lab 16.5 - Differentially Private Query Layer with diffprivlib

**Objective:** Build a DP query layer over a synthetic income dataset using
IBM's `diffprivlib` library, observe the privacy-utility trade-off as epsilon
sweeps across 0.01 to 10.0, and implement budget composition that refuses queries
once the total epsilon budget is exhausted.

**All data is synthetic. Never use real personal data in this lab.**

### Setup

```bash
docker compose --profile lab5 up -d
# The container installs diffprivlib==0.6.6 and runs the demo automatically.
# View output: docker logs ch16-lab5-tools -f
```

To work interactively:
```bash
docker compose --profile lab5 run --rm lab5-tools bash
cd /lab5
pip install 'diffprivlib==0.6.6' numpy --quiet
python dp_query_layer.py --rows 2000 --budget 1.0
```

### Walkthrough

1. **Non-private baseline.** The script first computes true mean income, count,
   and standard deviation over 2,000 synthetic records. This is your ground truth.

2. **DP mean with an explicit budget.** The `diffprivlib.tools.mean` function
   requires you to declare `bounds` (the sensitivity of the query) because the
   noise scale depends on the data range. Run the DP mean at epsilon=0.1 and
   run it several times; note that the answer jitters - the mechanism is
   randomised. This jitter IS the privacy guarantee: an attacker observing the
   output cannot reconstruct the exact input.

3. **Epsilon sweep (the privacy-utility trade-off table).** The script sweeps
   epsilon across [0.01, 0.1, 0.5, 1.0, 5.0, 10.0] and tabulates the average
   absolute error against ground truth. Watch the noise shrink as epsilon grows.
   Run the script twice and compare columns - the individual cells change, but
   the trend is stable.

4. **Budget-enforcing query layer.** The `DPQueryLayer` class holds a fixed total
   budget (default: epsilon=1.0). Each query call deducts its epsilon from the
   remaining budget and is logged. Once the budget is exhausted, further queries
   raise a `RuntimeError` (demonstrated in the demo: a third query at epsilon=0.3
   is refused when only 0.4 budget remains). This is composition as code, not
   just theory.

5. **Authorisation note.** The script prints the reminder from the book:
   a DP query layer governs *what a statistic reveals*, not *who may ask*. Put
   authentication and authorisation (sections 16.2-16.3) in front of the DP
   endpoint. A budget the client can reset is no budget at all.

### Expected Output

Terminal output showing:
- Non-private baseline statistics.
- The epsilon sweep table with error columns.
- Budget composition demo: three query attempts, the third refused.
- Query audit log showing epsilon spent and remaining per query.

### Verify Completion

- The epsilon sweep table shows error decreasing as epsilon increases.
- Running the script twice produces different individual epsilon-0.1 cells
  (randomised mechanism).
- The third query in the budget demo is refused with a RuntimeError message
  quoting the remaining budget and the requested epsilon.

### Cleanup

```bash
docker compose --profile lab5 down
```

---

## Teardown (All Labs)

```bash
docker compose down -v
```

This stops all containers and removes named volumes (crAPI databases, MobSF
analysis data). Images remain cached locally; remove them with `docker image prune`
if disk space is needed.

---

## Safety and Authorisation (repeated for emphasis)

Every offensive technique in this chapter (access-control bypass, API object
enumeration, GraphQL introspection, mobile decompilation) is legal and educational
only when run against the deliberate targets provided here, or against systems you
own and are explicitly authorised to test. The same conduct directed at live or
third-party systems without written authorisation is a criminal offence in most
jurisdictions. See Chapter 6 for the legal framework. Authorisation is not
optional, and "I was just testing" is not a defence.
