F4.08 · part 3 of 3
Redis keys
In Redis the id is a string key, namespaced with a colon: user:USR0NbWMtkosp8.
The namespace keeps key spaces apart and makes a scan or an eviction policy easy to scope. The same
self-validating id pays off harder here than anywhere: a cache exists to absorb load, so the cheapest win is to
reject the load that should never reach it. A malformed or impossible id is a 404 at the
edge — no GET, no fallback query.
A burst of eight requests, some real and some the kind a scanner sends. Compare an edge that validates first with one that forwards everything. Select a mode.
Validate, then reach the cache
The same eight requests, two edges. With validation, only well-formed, plausibly-timed
USR ids become a cache lookup; the rest are shed for the cost of a decode. Without it,
every request becomes a GET, and the ones that cannot exist miss the cache and fall
through to the database. Select a mode.
Edge mode · select one
edge: validates before the cache
load on store: 3 lookups
A cache absorbs load best when it never sees the load it should not. Validating the id at the edge turns a scanner’s flood into constant-time 404s and leaves the cache for requests that could be real.
Advanced: the keyspace and the honest limit
The key is the branded id under a type namespace — user:USR0NbWMtkosp8,
session:SES… — so one Redis instance holds several record kinds without
collision, and a colon prefix scopes a SCAN or a per-type eviction. The validating
plug runs before the Redix call, so a rejected id never becomes a network round-trip to the cache, let alone a
database read.
The honest limit, the same as the hub’s: validation proves an id is well-formed and
plausibly-timed, not that it exists. A correctly-shaped USR id that was
never issued still costs one cache lookup, and a miss still falls through to one query — that path
cannot be skipped without knowing the keyspace. What the edge removes is the high-volume, zero-effort probe:
wrong length, non-base62, out of range, wrong namespace, future timestamp. Those are most of a scan, and they
now cost the attacker a 404 and the store nothing.
# validate at the edge; only then touch Redis, only then the DB def profile(conn, %{"id" => id}) do with {:ok, _snow} <- Portal.Id.validate(id, :USR), # no I/O {:ok, json} <- Redix.command(["GET", "user:" <> id]) do json(conn, json) # cache hit else {:error, _} -> send_resp(conn, 404, "") # malformed id: shed {:ok, nil} -> load_from_db_and_cache(conn, id) # well-formed miss end end
a self-describing id
The edge can judge its shape and time with no lookup.
a protected cache
Bogus traffic is 404’d before Redis; only plausible ids reach the keyspace.
That completes F4.08: the branded id is a bigint key, a time-range bound, and a namespaced cache key — and a gate that sheds what cannot exist. Next module: F4.09 — Branded CHAMP maps & GenServer, which keys an in-memory CHAMP on the same id, partitioned by namespace.
References
Primary sources for this lesson, and where it connects in the course.
Sources
- Redis — Keys & key space — namespaced string keys and key conventions.
- Redix — the Elixir Redis client used at the edge.
- OWASP — Broken Access Control (IDOR) — the enumeration class this shedding narrows.
Related in this course
- F4.08 · Branded ids & persistence — the module hub and its request validator.
- F4.07 · Identifiers, Snowflake & branded ids — why the id is self-describing.
- F4 · Algorithms & Data Structures