Information flow security analyzes how data flows through a program to prevent unauthorized information leakage. The central property is noninterference: if two executions differ only in a secret input, their observable outputs should be identical (secrets don't interfere with public behavior). Approaches include: static analysis (tracking data dependencies to detect where secrets flow), type-based enforcement (assigning security labels to data, with type rules preventing secret data from leaking to public channels), and dynamic monitoring (tainting data as it flows and preventing tainted data from reaching public outputs). Information flow analysis detects subtle security vulnerabilities like timing attacks (program execution time depends on secrets) and side-channel attacks (memory access patterns leak information). The framework is foundational to computer security, applying to both software security (protecting passwords, encryption keys) and privacy (preventing unauthorized access to personal data).
Most security focuses on preventing direct access to secrets: lock passwords in files, encrypt data in transit. But secrets can leak through information flow — the paths data takes through computation. A program might never explicitly output a password but might leak it through timing, memory access patterns, or inferred values. Information flow security detects and prevents these leaks.
Noninterference: The Ideal
The gold standard of information flow security is noninterference: an attacker observing the program's outputs learns nothing about secrets. Formally, if two executions differ only in secret inputs, their observable outputs are identical. Noninterference is powerful: it rules out all possible information leakage through observable channels (outputs, timing, resources). But proving noninterference is hard, requiring global analysis of the entire program. Practical techniques approximate noninterference using static and dynamic analysis.
Static Analysis: Data Dependency Tracking
One approach is taint analysis: mark sensitive data as "tainted," track how it flows through the program, and flag any flow to public outputs. If a password P is tainted and a comparison `if (P == "admin")` produces a boolean B, then B is tainted (it depends on the secret). If B is used to print "access granted," the analysis flags an error: tainted data reaches public output.
Taint analysis is conservative — it marks data as tainted if it depends on secrets, even if the dependence is cryptographically secure (e.g., hash functions). But this conservatism is practical: it catches obvious leaks. Sophisticated analyses refine this by understanding special operations (cryptographic functions, error correction codes) that break the taint propagation.
Type-Based Enforcement
A more principled approach is type-based information flow: assign security labels to all data (Secret, Public, or a lattice of levels like {Public < Confidential < Secret}). Type rules enforce that operations on labeled data preserve security properties. A function accepting both Public and Secret inputs requires its output type to be Secret (information from Secret inputs contaminates the output). A function that only reads Public inputs can safely output Public.
The type checker verifies globally that Secret data never flows to Public outputs. This provides compile-time guarantees of noninterference without runtime monitoring. Languages like Jif (Java Information Flow) and LIO (Liquid Information Flow) implement this, allowing programmers to write secure code with precise security guarantees.
Dynamic Monitoring
Type-based enforcement is static and conservative. Dynamic information flow monitors data at runtime, tainting data that flows from secrets and preventing tainted data from leaving the system. Android's information flow framework uses dynamic taint analysis to track sensitive data (phone numbers, contacts) and prevent unauthorized sharing. The advantage of dynamic analysis is accuracy: you know exactly what data actually flowed, not a conservative over-approximation. The disadvantage is runtime overhead and the inability to catch errors before deployment.
Covert Channels and Timing Attacks
Explicit data flow (variable assignments) is only one path for information leakage. Covert channels leak information through indirect means:
1. Timing channels: Program execution time depends on secrets (e.g., password checker exits early on mismatch). An attacker measures timing and infers secrets.
2. Power channels: Power consumption during execution depends on data; monitoring power reveals information.
3. Cache channels: Memory access patterns affect CPU caches; cache timing attacks infer accessed data.
Information flow analysis can detect timing channels by checking whether control flow depends on secrets. If a secret value determines which branch executes, execution time will differ, creating a timing channel. To prevent this, the program must use constant-time operations — operations whose execution time is independent of secret inputs.
Practical Applications
Research Frontiers
Current challenges include: (1) handling implicit flows (control flow depending on secrets), (2) reasoning about probabilistic information leakage (leaking partial information is sometimes acceptable), (3) scaling to complex systems with many interacting components, (4) handling cryptographic functions and their non-leakage properties. The field is maturing from academic theory to practical tools (Rust cryptographic libraries with constant-time guarantees, JavaScript isolation guarantees), and information flow analysis is becoming standard in security-critical software development.
No topics depend on this one yet.