Fast Internet Secure Extensible — a rule-based, keyless, high-performance semantic envelope for Web/API & Media data.
Positioning (TL;DR)
FISE is not cryptography and does not replace TLS/AuthZ. It is a semantic obfuscation layer that raises the cost and time of scraping and reverse-engineering client-visible data, while keeping runtime overhead extremely low.
Modern web apps must render meaningful JSON on the client. HTTPS protects transport, but data meaning remains exposed in the browser, making large-scale scraping and cloning cheap. Traditional client-side encryption requires keys in the frontend, which attackers can read; heavy crypto also adds latency.
Design principle: Rather than distributing static client keys, FISE injects shared, ephemeral rules ("rules-as-code") that are bound to context and rotate quickly; any decoder inferred from one session does not generalize to others or future windows.
FISE proposes a rule-based, keyless transformation pipeline that "wraps" responses in a polymorphic semantic envelope. Each application (and optionally each session/request) uses a unique, rotating rule set to assemble salt, offsets, and metadata into a structure with no protocol-level universal decoder—attackers must tailor a decoder per pipeline. FISE focuses on raising attacker cost (not secrecy), with microsecond-level encode/decode on commodity devices.
FISE complements—not replaces—TLS, authentication/authorization, backend rate-limits, and cryptography for secrets. It is best suited where data itself is the asset (e.g., curated POI, pricing, recommendations, AI metadata).
FISE supports chunked, block-local pipelines that enable parallel encode/decode and streaming, allowing clients to begin rendering before the full payload arrives. It generalizes to media (images/video) via framed, chunked pipelines that preserve codec/container compatibility while enabling parallel unwrap on the client. FISE further supports per-session, server-injected rules, avoiding static bundles and reducing reuse value of a captured decoder.
REST/GraphQL APIs commonly return plaintext JSON. Despite TLS, the browser must see readable data, enabling:
- automated scraping
- competitive data harvesting / dataset cloning
- inference of business logic from response shapes
- unauthorized third-party reuse
Goal: protect semantic meaning without frontend keys or heavy crypto, by diversifying and rotating a lightweight envelope that is cheap to run but expensive to reverse for each target.
Even with HTTPS:
- DevTools exposes plaintext JSON.
- Headless browsers can fetch like any user.
- Response schemas leak domain logic.
- Keys must reside in the frontend → discoverable.
- Operational cost per request (key derivation/expansion, AEAD) is non-trivial on low-end clients.
- Resulting ciphertext still needs client-side decryption → plaintext inevitably appears in memory/DOM.
A few fetch calls and pagination often suffice to replicate valuable datasets at scale, creating business risk wherever data is the moat.
Core principle: Rather than distributing static client keys, FISE injects shared, ephemeral rules ("rules-as-code") that are bound to context and rotate quickly. Any decoder inferred from one session does not generalize to others or future windows, making automated attacks at scale economically unattractive and hard to maintain.
This yields the following properties:
- Keyless by design — no static client key to steal.
- Security through diversity — each app/session/request may use a different rule set.
- Infinite customization — salts, offsets, metadata channels, ciphers (optional), assembly strategies.
- Semantic obfuscation — protect meaning, not transport.
- Cheap to run, costly to reverse — microsecond-level ops; no protocol-level universal decoder.
- Streaming & Parallel-ready — rules can be designed block-local, enabling per-chunk encode/decode and multi-core execution.
- Polymorphic-by-session — rules can be server-injected per session, signed and short-lived, minimizing the reuse value of static reverse-engineering artifacts.
Core spirit. Each FISE rule is built from small, linear, easy-to-reason-about operations. When these operations are bound to context (bindings) and composed across chunks/sessions/time, they yield highly complex envelopes from an attacker’s point of view.
Simple primitives (local ops):
offset()— decides where to place/read metadata (spatial diversity).encodeLength()/decodeLength()— decides how length is represented (format diversity).extractSalt()/stripSalt()(optional) — decides how salt/meta is arranged (structural diversity).- A default XOR-style O(n) transform in the reference profile (pluggable and optional).
None of these are mathematically exotic; they are simple, local operations over bytes.
-
Context linkage.
Each step can be seeded byrulesetId,chunkIndex,sessionIdHash,tsBucket, etc. The same formulas produce different concrete results under different bindings, even if the rule code is identical. -
Multi-lane metadata.
Salt/length/offsets can be spread across multiple “lanes” (base36/62, emoji, zero-width, parity/XOR lanes), so there is no protocol-level fixed format that holds across deployments or even across sessions. -
Flexible meta-space.
Implementations may allocate M bytes as the search space forencodeLength()and related metadata:-- Even if offset and saltLen partially leak, an attacker still has to reason about which positions in those M bytes actually encode length and how they encode it. The difficulty scales with (position choices × representation variants), while legitimate decoding remains O(1)/O(n) (read a fixed window, apply a small function).
- The difficulty scales with (position choices × representation variants), while legitimate decoding remains O(1)/O(n) (read a fixed window, apply a small function).
-
Per-chunk heterogeneity.
A small pool (e.g. 3–8) of rules can be selected per chunk, deterministically from a seed/bindings. At the system level, complexity grows roughly as H^C for H rules over C chunks: a single response may already exercise a large portion of the rule space.
Let:
- M = number of bytes available as a “length window” for
encodeLength(), - k = number of positions in that window that are actually meaningful under a given rule,
- H = size of the per-chunk rule pool,
- C = number of chunks in a response.
A very rough upper-bound for structural configurations is:
- window choices ≈
C(M, k)× (representation variants), and - per-chunk rule assignment ≈
H^C.
So the effective search space behaves like:
H^C × C(M, k)(× representation variants)
from the attacker’s perspective, while each local step for a legitimate client is still a small, linear-time operation (add/mul/mod/XOR, simple base conversions, fixed-window reads).
This is not a formal security bound, but an intuition: outputs can appear complex and hard to reuse at scale without the rule, even though each primitive is simple.
Deployers can:
- widen or narrow the meta-space M,
- change which lanes carry length/salt/offset information,
- adjust rotation cadence (per deployment, per session, per time bucket),
- choose whether to use the default XOR transform, no extra transform, or a custom cipher.
As these parameters change, the attacker’s rule inference/search space grows, while runtime for honest clients remains cheap and linear.
The reference implementation ships with a fast default XOR-style O(n) transform. When needed, a deployment can plug in a custom cipher via a simple interface, for example:
interface FiseCipher {
encrypt(plainData, salt);
decrypt(cipherData, salt);
}A concrete deployment chooses and rotates among multiple rule sets. A typical encode flow:
- Variable-length salt (10–99 chars or app-defined).
- Entropy sources: CSPRNG (preferred), timestamp mixes, rolling checksums.
- Recommendation: use server-side CSPRNG to avoid predictability.
Encode salt length, offsets, rulesetId, optional request/session binding tags via one or more channels:
- base36/base62/hex
- emoji lanes
- zero-width characters
- XOR signatures / parity bits
- XOR or AES/WASM stage is optional to balance performance vs. resilience.
- If used, it does not rely on a client secret for security claims; it only raises effort.
Offsets decide where to place metadata, salt, and decoy. They may derive from:
- rulesetId
- time buckets
- prime sequences / rolling checksums
- request/session bindings
Interleave (data + salt + metadata [+ decoy]) into a non-deterministic, non-fixed format.
A string/byte stream with no fixed structure shared across deployments. There is no protocol-level universal decoder; decoding requires the matching rule set.
- Payload is split into chunks; each chunk carries local metadata (rulesetId, offsets) and optional HMAC bindings (server-side verify).
- Interleave/drift parameters derive from (rulesetId, chunkIndex, bindings) → no global dependency, so chunks can be encoded/decoded in parallel.
- A super-header specifies framing (
version,nChunks,flags).
- Each chunk MAY select a different rule from a bounded pool (e.g., 3–8) to increase diversity.
- Selection is deterministic from bindings/seed:
rule_idx = PRNG(seed, chunkIndex) mod K. - A super‑header carries a compact
rule_map; each chunk storesrule_idxinstead of full ids. - Preserve block‑local semantics so chunks decode independently; carry only tiny deterministic state if required.
Goal: deliver a fresh rule per session/request without changing the long‑cached runtime.
- Bootstrap snippet (HTML/SSR): server renders a tiny
<script type="module" nonce=...>containing a compact rule manifest (e.g., DSL bytecode + metadata) and calls the stable FISE runtime to activate it. - Signature: include
sig = HMAC(serverKey, bytecode || manifest || bindings); the runtime verifies before enabling the rule. - Bindings:
(method|pathHash|sessionIdHash|tsBucket)may be embedded to tie the rule to its context. - Caching: mark bootstrap no‑store; keep
fise-runtime.min.jsimmutable and SRI‑pinned. - Deterministic selection: the per‑session rule can still define heterogeneous per‑chunk logic (see §4.8) using a small bounded pool.
Given a matching rule set:
- Extract/locate metadata via channel heuristics.
- Recover salt length & offsets; validate request/session bindings.
- Remove salt/decoy; unwind transformations.
- Reverse optional cipher stage.
- Restore plaintext JSON for rendering.
Framed mode. The client may decode chunk-by-chunk (possibly in parallel workers) and incrementally render while the stream is arriving. If a rule needs cross-chunk state, carry a small deterministic state between chunks.
- Commodity scrapers relying on stable, predictable JSON.
- Universal or reusable decoders across many targets.
- Blind replay/tamper (when server verification is enabled).
- Rapid cloning of curated datasets (cost ↑).
- TLS (transport), authentication/authorization, access control.
- Backend bot controls (rate limit, behavior scoring).
- Cryptography for secrets/PII.
- DRM-like guarantees.
Attackers can run your app, hook decode functions, or dump plaintext after decode. FISE cannot prevent post-decode access; it raises the effort to reach and sustain that point, especially under rotation and validation.
- Request/Session binding: include a hash of
(method|pathHash|queryHash|sessionIdHash|tsBucket)in metadata. - Server-side verification: HMAC (server key only) covering metadata & bindings to reject altered or stale envelopes.
- Short-lived validity: time buckets + skew windows.
- Design channels that survive gzip, Unicode normalization, and CDN transformations.
- Multi-channel redundancy to tolerate lossy intermediaries.
- Per-session or per-request rule set rotation drastically increases reverse-engineering cost and decoder maintenance.
- Anti-reorder/tamper: per-chunk HMAC(meta || chunkIndex || bindings) (server key only).
- Anti-replay: include request/session bindings and time buckets in each chunk’s meta.
- Boundary hiding: optional decoy/padding and variable chunk sizes.
- Limit pool size (e.g., 3–8) to bound code/metadata overhead and improve worker/WASM cache locality.
- Include
rule_idxandchunkIndexunder server HMAC to prevent splice/reorder attacks. - Track field reliability per
rule_idx; rotate out rules with poor normalization fitness.
- Trust on first use: the runtime rejects unsigned/invalid manifests; use CSP nonces to restrict inline code.
- Localized leak: compromise of one session’s rule has limited reuse; subsequent sessions rotate.
- Replay/tamper: include
(sessionId|tsBucket|pathHash)in the signed fields; per‑chunk HMAC continues to guard payload integrity.
Claim wording: We do not claim “impossible to decode.” We claim no protocol-level universal decoder, and significant per-target cost under rotation, validation, and normalization-resistant channels.
Claim (practical): With a sufficiently diverse custom rules pipeline, per-session bindings, heterogeneous per-chunk rules, and temporal rotation, inferring the exact rule in use for a specific envelope becomes very hard within the rule's validity window. Any decoder that is inferred tends to be non-reusable beyond its original session/time-bucket.
Let R = total rule space size, S = number of active sessions, T = time buckets per hour, C = chunks per response, H = rule-pool size per chunk. A conservative upper bound for attacker search space per decoded response is:
O(R × S × T × H^C) (illustrative; parameters may not be fully independent in practice)
Example: R=1000, S=10,000, T=120, C=10, H=5
→ 1.16 × 10^16 combinations
→ At 1 ms/attempt: ≈368,000 years
Defender cost: O(1) per request (hash-table/manifest lookup)
Attacker cost: O(R × S × T × H^C) per response
Asymmetry: small, constant defender cost vs. exploding attacker maintenance cost.
- Non-stationarity (temporal): Rule distribution rotates (e.g., every 30s). Attacker samples stale quickly; inferred decoders degrade to near random for new buckets/sessions.
- Low sample budget: Under i.i.d. assumption, Hoeffding suggests
(N = O\big(\frac{1}{\varepsilon^2}\log\frac{1}{\delta}\big)) samples for ε-accurate inference. With ε=0.01, δ=0.01 → ~26,500. Rotation 30s @ 10 req/s gives ~300 samples → ~88× shortfall. - Context binding + integrity: Each envelope/chunk bound to
method | pathHash | sessionIdHash | tsBucket[|tokenHash(trunc)]and signed server-side (HMACwith tag length t → forgery ≈ 2^-t). Decoders are non-portable across routes/sessions/buckets. - Heterogeneity across chunks: Pool of 3–8 rules per chunk forces H^C combinations (e.g., 5^10 ≈ 9.7M). One chunk error breaks the whole response → automation fragile.
- Attacker economics: Defender ~0.1 ms CPU (O(1)); attacker hours per variant + constant re-work after rotation → maintenance does not scale.
Practical hardness against: passive observation, active probing (per-session), model extraction (staleness), replay (bootstrap expiry/bindings), collaborative sharing (non-transferable decoders).
In scope: automated scrapers, mass extraction, API harvesting at scale.
Out of scope: nation-state adversaries, insider threats, full client compromise, formal cryptographic secrecy, quantum-model guarantees.
Positioning: FISE sits between plaintext (no protection) and strong cryptography/DRM. It complements TLS/JWT/DPoP/DRM rather than replacing them.
Suggested measurements/targets:
- Decoder Breakage Rate (DBR) >95% post-rotation
- Scraper Throughput Reduction (STR) >90%
- Mandatory Lag (ML) > rule lifetime (live profiles)
- Client TTFR overhead P99 <100 ms
- Legitimate Decode Success Rate (DSR) >99.9%
- Attacker Cost Multiplier (ACM) >100×
Note: Move empirical numbers to docs/PERFORMANCE.md once measured via A/B.
Not claiming information-theoretic secrecy, not a replacement for TLS/JWT/DRM, and no cryptographic quantum guarantees. FISE focuses on reducing value and shortening useful lifetime of unauthorized decoding via economic asymmetry and temporal dynamics.
Central idea. FISE targets practical, time-bounded hardness without requiring any client-side secret keys. Server-side integrity remains anchored by a server secret (e.g., HMAC), but no reusable key is shipped to the client.
Traditional systems emphasize:
- Secret keys in clients, strict key management, and long-lived guarantees.
FISE emphasizes:
- No client-side keys (nothing reusable to steal on the client),
- Time asymmetry (rotation > inference/automation),
- Bounded protection (value decays within a rotation window).
Let (T_i) be attacker time-to-infer a working decoder for a given session/bucket, and (T_r) the rotation period. FISE is practically safe when (T_i \gg T_r), so any decoder becomes stale before it scales.
Let (C) be attacker maintenance cost per session/bucket and (V) the exploitable value per unit data in that window. Economic safety improves as (C \gg V) (deterrence by cost).
Illustrative targets (to be validated): (T_i = \text{hours}), (T_r = \text{tens of seconds}) → strong time asymmetry; (C/V \gg 1) under rotation.
- FISE binds envelopes to context (
method|pathHash|sessionIdHash|tsBucket[|tokenHash(trunc)]) and verifies integrity with a server-only HMAC. - The client never holds a reusable decrypt key. Rules are per-session/pool-per-chunk and rotate, so any recovered logic is short-lived and non-portable.
Key insight: Security is achieved via temporal and distribution polymorphism and server-anchored integrity, not via long-lived client keys.
- If bootstrap/manifest is observed: it is meant to be consumable by that session and doesn’t expose server secrets.
- Rule families rotate (per session/time-bucket), so reverse-engineered decoders expire quickly and don’t generalize.
| Dimension | AES/TLS/JWT (classic) | FISE (this work) |
|---|---|---|
| Client-side keys | Often present (must be protected) | None (no reusable decrypt key on client) |
| Server secret | Yes (KMS/HSM, etc.) | Yes (HMAC/manifest integrity only) |
| Protection horizon | Long-lived while secrets hold | Rotation window (tens of seconds/minutes) |
| Break reuse | Often reusable once broken | Non-transferable; expires with rotation |
| Security basis | Math hardness + secrecy | Time & maintenance asymmetry + integrity |
| Role | Transport/auth/strong secrecy | Semantic protection; defense-in-depth |
Scope. FISE complements TLS/JWT/DPoP/DRM. It is not a replacement for cryptographic secrecy where that is required.
Publish and track:
- (T_i/T_r) ratio (observed),
- Decoder breakage rate after rotation,
- Scraper throughput reduction,
- P95/P99 client overhead under legitimate use.
Note: Report concrete numbers in docs/PERFORMANCE.md after A/B experiments.
Goal. Use the same per‑session rule family to protect both directions: server → client (response) and client → server (request), while keeping the hot path lightweight and parallelizable.
What it is. A two‑way semantic envelope: the server injects a signed manifest at bootstrap; responses are wrapped (encode) and requests may optionally be wrapped (encode) by the client and unwrapped (decode) by the other side. The rule is keyless and rotates per session / time bucket; integrity of envelopes is enforced by a server‑only HMAC over metadata/bindings (not by a client secret).
Security properties (adjunct).
- Confidentiality (semantic): hides meaning from naive scraping or middleboxes; not a replacement for TLS.
- Context binding: envelopes are valid only under
(method|pathHash|sessionIdHash|tsBucket[|tokenHash(trunc)]). - Asymmetry: attacker time‑to‑understand >> defender time‑to‑rotate.
- No client secret: avoids key exposure in the browser; HMAC secrets live only on the server.
Performance envelope.
- Linear byte ops (O(n)), block‑local chunks, parallel decode via Workers/JSI/WASM.
- Deterministic rule selection from
(seed, chunkIndex[, tsBucket])within a small warmed pool (3–8).
Recommended usage.
- Responses (default): wrap JSON/media segments.
- Requests (optional): wrap non‑secret payloads (e.g., proprietary query/filters) to raise scraping cost; keep auth/CSRF unchanged.
Idea. Decrypt only when a UI element actually needs data, at the smallest useful granularity (field/segment). This eliminates a single, predictable “global decrypt” point and minimizes plaintext lifetime.
- Behavior-bound. Decode is triggered by real user behavior (open modal, hover/scroll, route enter, component mount).
- Non-aggregatable. Decode → render → drop; avoid assembling full JSON; no long-lived plaintext state.
- Timing obfuscation. Add small jitter and vary decode loci (main thread vs. Web Worker/JSI/WASM) so hooks are non-deterministic.
- Parallel-friendly. Per-chunk decode in Workers; stream and render incrementally.
- Off-main-thread decode (Workers/JSI/WASM); use transferable buffers and zero-copy where possible.
- Zeroize buffers immediately after render; avoid DOM text nodes/logs; do not memoize plaintext.
- Bind envelopes to
(method|pathHash|sessionIdHash|tsBucket[|tokenHash(trunc)]); optionally verify a server-side HMAC for integrity/non-transferability. - Add rate limits and rotate per session/time bucket to cap an attacker’s sample budget.
A fully compromised client can still snapshot plaintext at the exact render moment. FISE’s contribution is to ensure any observed data is fragmented, short-lived, and non-reusable.
- Plaintext lifetime per component (median/P95).
- TTFR / latency overhead for legitimate users (P95/P99).
- Decoder Breakage Rate (DBR) after rotation.
- Scraper Throughput Reduction (STR) vs. baseline.
| Feature | AES/WebCrypto | Obfuscation libs (generic) | FISE (this work) |
|---|---|---|---|
| Requires client key | Yes | No | No |
| Universal decoder | N/A (standard) | Often | No protocol-level universal decoder |
| Performance (client) | Medium–High cost | Fast | Very fast (microseconds) |
| Predictability | Fixed format | Medium | Non-fixed, rotating |
| Semantic protection | Not the goal | Partial | Strong focus |
| Per-app uniqueness | No | Limited | Yes; per-session/request capable |
| Server validation (anti-replay) | Optional (MAC) | Rare | First-class option (HMAC) |
- Encode: ~0.02–0.04 ms
- Decode: ~0.01–0.02 ms
- Optional AES/WASM stage: add 0.1–0.3 ms typical
- Payload sizes: 1 KB, 10 KB, 50 KB.
- Environments: Desktop (M-series), Android mid-range, iOS mid-range.
- Report mean, stdev, P95/P99.
- Measure end-to-end impact (server encode → client decode → render).
Report TTFR (time-to-first-render) and throughput with N workers (server Node workers; client Web Workers/WASM). Typical chunk sizes: 8–32 KB for JSON; 128–512 KB for media segments. Compare streaming vs. non-streaming P95/P99.
- Server: encode + HMAC verify endpoints.
- Client: JS/RN decode runtime.
- Rotation: 2–4 rule sets, per-session selector.
- Bindings: method/pathHash/queryHash + sessionIdHash + time bucket.
- Bot controls: rate limits, light CAPTCHA/Turnstile where appropriate.
- Validate channels across gzip/brotli, Unicode NFC/NFKC, proxies/CDN.
- Provide fallback multi-channel metadata if a lane is stripped.
- Log P50/P95 encode/decode, failure reasons, suspected tamper, rotation distribution.
- A/B toggles to quantify real-world scraping reduction.
- Enable for payloads ≥ 100–200 KB or when using optional WASM/cipher stages.
- Keep rules block-local (or carry tiny state) to preserve parallel decode.
- Validate against Normalization Gauntlet (gzip/brotli, Unicode NFC/NFKC, CDN).
- Video (HLS/DASH/CMAF): wrap segments, not manifests. Bindings include variant id and time buckets. Client unwraps in workers then appends raw bytes to MSE.
- Images: whole‑file wrap (Blob URL) or tile‑based wrap for deep‑zoom; avoid CDN recompression on enveloped assets.
- CDN/Optimizer: disable transforms (recompress/minify) on enveloped media; validate via Gauntlet.
- Chunk sizes: 128–512 KB per segment chunk on web; schedule workers to group identical
rule_idxfor cache locality.
- Web (SSR/SPA): render a per‑session bootstrap with CSP nonce; load
fise-runtime.min.js(immutable). Verify signature, then initialize workers and start framed decoding. - React Native: fetch
GET /fise/rule?sid=...for the manifest; verify signature; pass to native/JSI runtime. - CDN: do not cache the bootstrap; cache the runtime and enveloped payloads normally.
- Web/API response protection where data is the product: POI/travel, pricing, recommendations, AI metadata.
- Admin dashboards/mobile apps exposing sensitive analytics (non-secret).
- Aggregation portals (news/content) reducing bulk harvesting.
- Media delivery: per‑segment video (HLS/DASH/CMAF) and image tiles/files wrapped in FISE for anti‑bulk scraping while preserving player/decoder compatibility.
Not recommended for secrets/PII/keys—use standard cryptography and access control.
- Scraping reduction (A/B): drop in effective scraper throughput (target ≥ 50–70%).
- Time-to-decoder for red-team per rule set (target ≥ 5× vs. baseline).
- Decoder breakage rate under rotation (maintenance cost for attacker).
- Client overhead P95 < 1 ms on mid-range devices for ≤10 KB payloads.
- Multi-block interleaving & decoy noise segments.
- Per-request rule set rotation with server seed.
- Browser-optimized WASM fast path.
- DSL & codegen for polymorphic-by-build pipelines.
- Watermarking/attribution bits for leak tracing.
- Tamper detectors and heuristic anti-hook signals.
FISE reframes client-side protection as a semantic, rule-based envelope: keyless, rotating, and cheap to run. It does not prevent post-decode access, but it raises attacker cost substantially by eliminating a protocol-level universal decoder and coupling data to diversified, validated rule sets. Used alongside TLS/AuthZ, rate-limits, and behavior defenses, FISE provides practical defense-in-depth for teams—especially small teams—whose competitive edge lies in the data they deliver to clients.
This section defines a path to unlock community-driven rule diversity and safe, deterministic execution.
- Rule Diversity at Scale: countless pipelines from community & vendors without breaking safety or DX.
- Deterministic Runtime: same input + same bindings → same output; budgeted CPU/memory/time.
- Programmability: a DSL that compiles to JS/WASM for speed and polymorphic-by-build distribution.
- Trust & Quality: Registry with CI, property tests, normalization gauntlet, and reputation scoring.
- No Secrets in Client: binding and rotation do not expose server keys; HMAC verification remains server-only.
- Declarative operators; no arbitrary IO/network/DOM access.
- Deterministic evaluation; pseudo-randomness only via allowed bindings/seed.
- Budgeted execution:
max_ops,max_ms,max_bytes. - Symmetry: every encode op has a decode inverse.
- Isolation: no DOM, no network/FS; limited memory; timeouts; op-count quotas.
- Determinism: frozen builtins; seeded PRNG derived from bindings/seed only.
- Backends: JS interpreter first; optional WASM fast path.
- Instrumentation: metrics (ops, ms, bytes), decode failures, normalization outcomes.
- Metadata: name, author, semver, ops used, budget, Gauntlet score, P95 decode, payload delta.
- CI: linter, schema validate, property tests, fuzz, budget/time.
- Signatures: rule packages signed (supply-chain).
- Reputation: anonymized usage telemetry (opt‑in), field failure rates, attacker breakage reports.
- Tags:
mobile-fast,normalization-hard,emoji-free,zero-width-lite,wasm-fast,framed.
- Compression: gzip/brotli; Unicode: NFC/NFKC; Proxy/CDN quirks.
- Score: survival metrics + integrity; published in Registry.
- Block editor; live preview; budget sliders; Gauntlet-in-the-loop.
- AI copilot for mutation (“+10% gauntlet score, P95 < 1 ms”).
- Bootstrap generator: export per‑session rule manifest (bytecode + signature fields).
- Polymorphic-by-build codegen variants; per-session/per-request rotation.
- Fallback: multi-channel metadata; decode can attempt multiple lanes.
- Claims policy; disclosure of limits (AitB).
- Reviewer roles (security/perf).
- Bounties/hall‑of‑fame.
- v0.2: JS VM + Registry alpha; Gauntlet CLI; 10 curated rules.
- v0.3: WASM fast path; AI mutation loop; telemetry-backed fitness.
- v1.0: Rule Builder stable; signed packages; enterprise rotation policies.
Goal: container/codec‑preserving envelopes with parallel, chunked unwrap on the client.
- Video: apply FISE per segment (
.ts,.mp4, CMAF). Super‑header announcesversion,nChunks,rule_map. Each chunk carriesrule_idx,chunkIndex,len, bindings, and HMAC (server-only key). - Client flow:
fetch(segment) → WebWorker.decodeFise(chunked) → appendBuffer(bytes)(MSE). Start render as soon as first chunk is decoded. - Images: wrap entire file; decode to
Blobthenimg.src=URL.createObjectURL(blob). For deep‑zoom, wrap per‑tile for higher parallelism and per‑tile rotation.
- Deterministic selection from seed/bindings; keep pool small (3–8). Optimize scheduler to batch by
rule_idxto reduce JIT/WASM thrash.
- Include
(rule_idx || chunkIndex || len || bindings)in HMAC (server key only). Bindings covermethod|path|variant|tsBucket. - Optional decoy/padding and variable chunk sizes to hide internal boundaries.
- Validate against gzip/brotli, Unicode normalization, proxy/CDN mutations, and platform image/video pipelines.
- Disallow CDN recompression on enveloped assets; publish Gauntlet score in Registry metadata.
- TTFR improvement vs. baseline, throughput with N workers, P95/P99 decode, decoder breakage rate under rotation.
Idea: obfuscate a very small portion (≈0.5–3% bytes) that is structurally critical to decoding/visual quality, then restore it client‑side in the framed pipeline. This preserves throughput and parallelism while making CDN-level restreaming very hard and economically unattractive without the rule.
Video (MP4/CMAF/HLS/DASH):
- Init segment: lightly obfuscate parts of parameter sets (e.g., SPS/PPS for AVC/HEVC, sequence headers/OBUs for AV1).
- Key frames (IDR): obfuscate a few tiles/macroblocks at the start of each IDR or selected slice header fields.
- Sample description /
stsd: minimal perturbation that invalidates naive decoders until client restores.
Images (JPEG/WebP/AVIF):
- JPEG: obfuscate a handful of MCU at scan start, or perturb Huffman/Quant tables with a deterministic, invertible delta.
- WebP/AVIF: target a small set of OBU/Chunk headers or the first tile in each region.
Client restoration: performed per‑chunk in Web Workers/JSI/WASM (block‑local), then fed to MSE (video) or Blob URL (image).
When to use: environments you control end‑to‑end (no CDN recompression) or alongside 15.1 Segment‑Envelope as an inner layer for high‑value routes.
Caveats: ensure compatibility with players; validate via Normalization Gauntlet and device lab before rollout.
Goal: make near‑realtime restreaming economically unviable by coupling time‑bucket rotation with heterogeneous per‑chunk rules and (optionally) critical‑fragment obfuscation.
Profile:
- Per‑session bootstrap (signed, no‑store).
- Per‑segment envelope (2–4 s segments) with
super‑header,rule_map, and HMAC(meta || chunkIndex || bindings). - Heterogeneous‑by‑chunk: pool of 3–8 rules, selection deterministic from
(seed, chunkIndex, tsBucket). - Rotation by time‑bucket (e.g., every 15–30 s).
- Optional critical fragments: touch init + IDR boundaries (≤3% bytes) to break naive playback.
- Bindings: include
(method|pathHash|variant|sessionIdHash|tsBucket)in meta/HMAC. - Watermark (optional): per‑session tracers in metadata/offset layout for leak attribution.
Outcome: legitimate clients decode in parallel with low TTFR, while attackers accumulate latency debt (find bootstrap → build N decoders → track rotations), causing restreams to lag or fail.
Modern large‑scale scrapers rely on two assumptions: (1) the protection mechanism is stable over time, and (2) it is uniform across clients. FISE invalidates both by introducing temporal polymorphism and distribution‑level variability: the effective rule‑set for each client (and potentially each request) is inlined at bootstrap time and can be mutated/rotated with negligible operational cost. This unpredictability raises both attack construction and attack maintenance costs.
On each initial HTML load, the app may embed the effective decode rule‑set for that session. The rule need not be static, global, or shared.
Injection vectors (non‑exhaustive):
- Inline
<script type="module">with CSP nonce (short‑lived) - External bundles (per‑build polymorphism)
- Dynamic
import()loaders - Service Worker bootstrap responses
- Inlined bootstrap JSON (
window.__FISE__) - CSS‑encoded lanes (zero‑width / emoji / base62)
- WASM modules with partial decode logic
<meta>‑embedded metadataLink: rel=prefetchheaders- First‑call bootstrap API responses
Apps may select/rotate injection paths at runtime. Thus, even within the same rule set family, each client can receive a structurally different decode pipeline.
Implication. There is no single reliable “place” to locate the decoder; reverse‑engineering must begin from scratch for each injection variant.
Since rules are injected at bootstrap, delivery can vary per‑build, per‑client, per‑session, and even per‑request (for sensitive endpoints). The rule itself may be:
- injected as a concrete pipeline,
- generated via DSL at build‑time,
- mutated by polymorphic codegen, or
- selected from a pool of community salt packs.
This yields a many‑to‑many mapping:
Client 1 → A₁
Client 2 → A₂
Client 3 → B₁
Client 4 → C₃
...
Even within the same family (A, B, C), materialization differs per client.
Implication. Attackers cannot prepare a universal, reusable decoder. At best they reverse one session, which becomes invalid after rotation.
Breaking a pipeline requires:
- locating the injected rule, 2) understanding the pipeline, 3) reconstructing a decoder, 4) validating, 5) automating. This can take hours per pipeline.
Defenders can rotate per deployment / per session / per time bucket / per request with near‑zero cost.
Asymmetry.
Attacker time‑to‑understand >> Defender time‑to‑rotate
Thus, even successful decoding is short‑lived and non‑transferable.
Claim wording: FISE does not prevent decoding; it aims to ensure any successful decoding is short‑lived and non‑reusable.
Traditional anti‑scrape fails because one break scales: same signatures, payload formats, and schemas. FISE breaks that model:
- Decoding logic is session‑local.
- Pipeline structure is instance‑specific.
- Injection vectors are variable.
- Offsets/metadata lanes can differ per request.
- Each instance decays quickly under rotation.
Result. Reverse‑engineering may be feasible but economically useless beyond the original session.
Principle: No protocol‑level universal decoder, no reusable exploit.
Temporal & distribution polymorphism increase:
- attacker cost (initial & ongoing),
- attacker uncertainty,
- scraping maintenance overhead,
- difficulty of automation,
- resistance to pattern matching (including AI‑assisted).
…while maintaining:
- microsecond‑level overhead,
- no client‑side secrets,
- straightforward integration for small/medium teams.
We call this Semantic Protection with Temporal & Distribution Polymorphism (SP‑TDP)—a defense model where attack cost scales roughly per client / per session, while defense cost remains near‑constant.
FISE’s core is dependency‑free, linear byte/string transforms with optional WASM fast paths. This makes it portable across Web, Mobile, TV/IoT, Edge, and Native stacks. Below are reference profiles and packaging targets.
encode(input: Uint8Array, manifest: Manifest): Uint8Arraydecode(input: Uint8Array, manifest: Manifest): Uint8ArrayencodeFramed(stream, manifest): AsyncIterable<Chunk>decodeFramed(stream, manifest, { maxWorkers? }): AsyncIterable<Uint8Array>
Manifest (self‑contained). rulesetId, rule_map, seedHint, bindings, sig, version.
- Profiles:
web-core(JS),web-wasm(auto WASM),media-segment-envelope,media-critical-fragment(opt‑in). - Parallelism: Web Workers; transferable buffers.
- Media: MSE append after unwrap; Image via Blob URL.
- Notes: CSP nonce on bootstrap; Gauntlet (gzip/brotli/NFC/NFKC/CDN).
- Profile:
rn-jsi(C++/Rust core via JSI) + JS shim. - Parallelism: thread pool inside JSI; avoid GC churn; preallocate buffers.
- Media: decode per‑chunk then pass to native players or custom renderers.
- Webview targets (Tizen/webOS/Android TV/kiosk): prefer
media-segment-envelope; Workers if available; WASM optional; fallback scalar. - Native set‑top/embedded: static lib (C/C++/Rust); expose
encode/decode/decodeFramed; 2–4 worker threads are sufficient for 2–4s segments. - Metadata lanes: prefer hex/base36 over zero‑width/emoji on firmware that normalizes content.
- Profile: ESM build, no Node APIs required; Worker pool polyfill for concurrency or single‑thread fallback.
- Streaming: handle
ReadableStreamwith framed decode for low latency.
- iOS: Swift Package + static C/C++/Rust core.
- Android: AAR (Kotlin) with JNI to C/C++ core if needed.
- Desktop: Rust/C++ lib, Node addons for Electron.
- Endianness: operate on byte arrays (endian‑agnostic).
- Budget: ≤ 2k ops/KB; P95 JSON ≤10 KB < 1 ms on mid‑range mobile; minimal allocations.
- Forbidden in hot path: PBKDF, SHA‑heavy, big‑int crypto.
- Gauntlet: test against gzip/brotli, Unicode normalization, proxy/CDN rewrites, and media pipelines.
- Web/Node: ESM + CJS with d.ts; optional WASM.
- RN: JSI module; pods/gradle config.
- Edge: ESM only.
- Native: static libs + thin adapters.
Claim wording. By keeping cores simple and dependency‑free, FISE can be implemented consistently across platforms while preserving performance (parallel, block‑local) and robustness (Gauntlet‑tested lanes).