API Security Research: Content Protection for Glidr

Threat Model

What we are protecting: - A question bank (981 questions with explanations) that represents significant editorial work - Not financial data, medical data, or personal information - Business goal: prevent competitors from bulk-downloading questions for free

Realistic threats: 1. Casual scraping — someone writes a script to download all content 2. Competitor copying — another app developer bulk-downloads the question bank 3. NOT a concern: sophisticated nation-state attackers, reverse engineers with unlimited resources

Conclusion: We need "good enough" security, not military-grade protection. A determined attacker with the app binary can always extract keys, but we want to raise the bar above casual scraping.


Security Options Evaluated

Option 1: API Key in App Binary (Basic, Recommended for v1)

How it works: - A shared secret (e.g., X-Glidr-Key: abc123...) is embedded in the app - Server validates this header on all content endpoints - Key is obfuscated in the binary using compile-time string splitting or encryption

Implementation: ```dart // Store as environment variable injected at build time // Never hardcode in plain text in source const apiKey = String.fromEnvironment('GLIDRAPIKEY');

// In HTTP client dio.options.headers['X-Glidr-Key'] = apiKey; ```

Server side (PHP example): ```php $key = $SERVER['HTTPXGLIDRKEY'] ?? ''; if ($key !== getenv('GLIDRAPIKEY')) { httpresponsecode(403); die('Forbidden'); } ```

Pros: Simple, zero infrastructure cost, stops casual scrapers Cons: Key is extractable from app binary by determined attacker Verdict: Sufficient for protecting a $49.99 exam app's question bank


Option 2: Certificate Pinning

How it works: - App validates that tekmidian.com presents the exact SSL certificate it expects - Prevents man-in-the-middle attacks even on compromised networks

Implementation in Dio: ```dart (dio.httpClientAdapter as IOHttpClientAdapter).onHttpClientCreate = (client) { client.badCertificateCallback = (cert, host, port) => false; SecurityContext context = SecurityContext(); context.setTrustedCertificatesBytes(pinnedCertBytes); return HttpClient(context: context); }; ```

Pros: Prevents MITM interception of API key Cons: Certificate rotation causes app to break; requires app update when cert expires Verdict: Nice-to-have, add in v2 if abuse becomes a problem


Option 3: Apple App Attest + Google Play Integrity

How it works: - Apple/Google cryptographically verify the app is genuine and unmodified - Backend receives attestation token, validates with Apple/Google servers - Only genuine, unmodified app instances can download content

Pros: Strongest protection available; cannot be bypassed without jailbreak Cons: - Requires backend infrastructure to validate attestation tokens - Apple App Attest has rate limits (free tier: limited attestations/day) - Adds significant implementation complexity - Overkill for a small hobby/niche app

Verdict: Not needed for v1. Consider for v2 if piracy becomes a real problem.


Option 4: JWT Tokens with Device Fingerprinting

How it works: - App registers with backend using device ID + purchase receipt - Backend issues a JWT valid for this device - JWT is used for all content requests - Content is tied to a specific "account"

Pros: Can revoke access per device; enables future account features Cons: Requires user accounts infrastructure; adds backend complexity Verdict: Not needed for v1 one-time purchase model with no accounts


Recommended Security Architecture for Glidr v1

Layer 1: HTTPS (mandatory, baseline)

All API traffic over HTTPS. tekmidian.com must have a valid SSL certificate.

Layer 2: API Key Header

Layer 3: Rate Limiting on Server

Layer 4: Content Structure (Defense in Depth)

Layer 5: Monitoring


API Endpoint Design

Base URL: https://tekmidian.com/glidr/api/v1/

All requests require header: X-Glidr-Key: {secret}

``` GET /manifest.json Response: { "version": "1.2.0", "subjects": { "air_law": "abc123hash", ... } }

GET /subjects/{subject_id}.json Response: Full subject JSON with all questions Example: /subjects/air_law.json

GET /figures/{filename} Response: Image file (PNG or SVG) Example: /figures/bazl30q08ask21speed_polar.png ```

Manifest Response Example

```json { "version": "1.2.0", "updated_at": "2026-03-15T00:00:00Z", "subjects": { "airlaw": { "hash": "sha256:abc...", "questioncount": 110, "size_bytes": 45000 }, "meteorology": { "hash": "sha256:def...", "questioncount": 110, "sizebytes": 52000 } }, "figures": { "hash": "sha256:ghi...", "count": 58, "size_bytes": 4200000 } } ```

App caches subject hashes locally. On launch, compares cached hash vs remote manifest. Downloads only changed subjects.


Server Setup on tekmidian.com

Minimal PHP implementation:

``` /glidr/ api/ v1/ .htaccess # auth check + routing auth.php # API key validation manifest.json # pre-generated static file subjects/ air_law.json meteorology.json ... (9 files) figures/ *.png *.svg ```

.htaccess: ```apache RewriteEngine On RewriteCond %{HTTP:X-Glidr-Key} !={GLIDRAPIKEY} RewriteRule ^ - [F,L] ```

This is the simplest possible implementation — Apache validates the key before serving any file.