Loading learning content...
When you withdraw money from an ATM, you trust that your account balance reflects reality. When a nuclear power plant reads sensor data, that reading must be accurate. When a surgeon reviews patient records before an operation, those records must be correct. This trust in the accuracy and reliability of information is what security professionals call Integrity.
Integrity is the second pillar of the CIA triad, ensuring that data remains accurate, consistent, and trustworthy throughout its lifecycle. While confidentiality protects information from unauthorized disclosure, integrity protects it from unauthorized modification. A system with perfect confidentiality but no integrity is nearly worthless—what good is secret data if it might be wrong?
By the end of this page, you will understand integrity as a protection goal, distinguish between different types of integrity violations, understand the mechanisms operating systems use to ensure data integrity, appreciate the role of checksums and cryptographic hashes, and recognize how integrity monitoring detects tampering.
Integrity, in security terminology, encompasses two related concepts that are essential to understand distinctly:
Data Integrity:
Data integrity ensures that information has not been modified in an unauthorized manner. When you save a file, read it back, and find the exact same contents, data integrity has been maintained. Data integrity failures can be accidental (hardware errors, software bugs) or malicious (tampering, injection attacks).
System Integrity:
System integrity ensures that the system itself operates correctly and has not been compromised. A system with integrity executes only authorized code, maintains correct configurations, and operates according to its security policy. Rootkits, malware, and unauthorized configuration changes violate system integrity.
| Dimension | Definition | Violation Example |
|---|---|---|
| Data Integrity | Data has not been modified without authorization | Attacker modifies financial transaction amount in transit |
| Origin Integrity (Authenticity) | Data comes from its claimed source | Attacker sends forged email appearing to be from CEO |
| System Integrity | System operates according to design and policy | Malware modifies kernel to hide malicious processes |
| Semantic Integrity | Data operations preserve logical consistency | Race condition allows account balance to go negative |
| Entity Integrity | Each entity is uniquely identifiable | Duplicate primary keys allow record confusion |
| Referential Integrity | References between entities remain valid | Deleted user still referenced in authorization tables |
While Bell-LaPadula addresses confidentiality, the Biba model (1977) formalizes integrity. Its core principle—'no read down, no write up'—is the inverse of Bell-LaPadula. High-integrity subjects should not read low-integrity data (which might be corrupted), and low-integrity subjects should not write to high-integrity objects (which would contaminate them). This model guides the design of systems where data trustworthiness is paramount.
Integrity violations can be more dangerous than confidentiality breaches because they corrupt the very data we rely upon for decisions. Consider the difference: if an attacker reads your bank balance, that's a privacy violation; if an attacker changes your bank balance, that's theft.
Operational Consequences:
Systems depend on accurate data to function correctly. Flight control software trusts sensor readings. Medical devices trust configuration parameters. Power grids trust demand forecasts. When integrity fails in these contexts, the consequences range from inconvenience to catastrophe.
Trust and Decision-Making:
Every decision based on data implicitly assumes that data is correct. If you can't trust your data, you can't trust decisions made using that data. Integrity violations undermine the entire epistemological foundation of data-driven operations.
Integrity underpins the other security properties. If attackers can modify access control lists, confidentiality protections fail. If attackers can corrupt system binaries, availability suffers. If attackers can alter authentication databases, the entire security model collapses. In this sense, integrity is the most fundamental of the three pillars.
Operating systems employ multiple mechanisms to maintain data integrity, ranging from low-level hardware features to high-level abstractions.
Memory Protection:
The same memory isolation mechanisms that enforce confidentiality also protect integrity. If a process cannot access another process's memory, it cannot corrupt that memory either. The MMU enforces read-only protection on certain memory regions, preventing modification of shared libraries and code sections.
Write Protection:
Operating systems mark certain memory pages as read-only, preventing even the owning process from modifying them. The text segment (executable code) is typically read-only to prevent code modification. Critical kernel data structures are similarly protected.
| Protection | Scope | What It Prevents | Implementation |
|---|---|---|---|
| Read-Only Pages | Memory regions | Code modification, constant corruption | MMU page table permissions |
| NX/XD Bit | Memory pages | Code execution in data regions | CPU No-Execute feature |
| W^X Policy | Process memory | Pages being both writable and executable | Memory allocator enforcement |
| Stack Canaries | Function stack frames | Stack buffer overflow exploitation | Compiler-inserted checks |
| ASLR | Process layout | Predictable memory corruption attacks | Randomized base addresses |
| Guard Pages | Memory boundaries | Buffer overruns crossing regions | Unmapped sentinel pages |
File System Integrity:
File systems maintain integrity through multiple mechanisms. Access control prevents unauthorized modification. Journaling ensures that file system metadata remains consistent even after crashes. Checksums detect corruption from media degradation or hardware errors.
Transaction Semantics:
Modern file systems use transactional approaches to ensure integrity. Operations either complete fully or not at all—there are no partial updates that leave the file system in an inconsistent state. This atomic, consistent, isolated, durable (ACID) approach originated in databases but is now essential in file systems.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
#!/bin/bash# File integrity monitoring using cryptographic hashes # Generate baseline checksums for critical system filescreate_baseline() { echo "Creating integrity baseline..." # Hash critical system directories find /bin /sbin /usr/bin /usr/sbin -type f -exec sha256sum {} \; \ > /var/lib/integrity/baseline.sha256 # Include configuration files for config in /etc/passwd /etc/shadow /etc/sudoers /etc/ssh/sshd_config; do if [ -f "$config" ]; then sha256sum "$config" >> /var/lib/integrity/baseline.sha256 fi done # Sign the baseline to prevent tampering gpg --detach-sign /var/lib/integrity/baseline.sha256 echo "Baseline created with $(wc -l < /var/lib/integrity/baseline.sha256) entries"} # Verify system integrity against baselineverify_integrity() { echo "Verifying system integrity..." # First, verify baseline signature if ! gpg --verify /var/lib/integrity/baseline.sha256.sig 2>/dev/null; then echo "WARNING: Baseline signature verification failed!" return 1 fi # Check each file against baseline violations=0 while read -r expected_hash filepath; do if [ ! -f "$filepath" ]; then echo "MISSING: $filepath" ((violations++)) else current_hash=$(sha256sum "$filepath" | cut -d' ' -f1) if [ "$current_hash" != "$expected_hash" ]; then echo "MODIFIED: $filepath" ((violations++)) fi fi done < /var/lib/integrity/baseline.sha256 echo "Integrity check complete: $violations violations found" return $violations} # Detect new files not in baseline (potential malware/backdoors)detect_additions() { echo "Checking for unauthorized additions..." baseline_files=$(cut -d' ' -f3 /var/lib/integrity/baseline.sha256 | sort) current_files=$(find /bin /sbin /usr/bin /usr/sbin -type f | sort) # Find files in current that are not in baseline comm -13 <(echo "$baseline_files") <(echo "$current_files") | \ while read -r newfile; do echo "NEW FILE: $newfile" done}Checksums and cryptographic hashes are the workhorses of integrity verification. While closely related, they serve different purposes and offer different security guarantees.
Checksums (CRC, Parity):
Simple checksums like CRC (Cyclic Redundancy Check) detect accidental corruption—bit flips during storage or transmission. They are computationally cheap and excellent at catching random errors. However, they are not cryptographically secure; an attacker who can modify data can also compute a valid checksum for the modified data.
Cryptographic Hashes:
Cryptographic hash functions (SHA-256, SHA-3, BLAKE2) provide much stronger guarantees. A cryptographic hash is:
| Method | Speed | Accidental Errors | Malicious Modification | Use Case |
|---|---|---|---|---|
| Parity Bit | Fastest | Detects single bit errors | No protection | Memory ECC, simple protocols |
| CRC-32 | Very fast | Excellent for burst errors | No protection | Network packets, file formats |
| MD5 | Fast | Excellent | Broken (collisions found) | Legacy verification, non-security |
| SHA-1 | Fast | Excellent | Weakened (collisions found) | Legacy systems, being phased out |
| SHA-256 | Moderate | Excellent | Currently secure | Digital signatures, file integrity |
| SHA-3 | Moderate | Excellent | Currently secure | New applications, diversity |
| BLAKE2 | Very fast | Excellent | Currently secure | Modern replacement for MD5 |
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
#include <stdio.h>#include <string.h>#include <openssl/sha.h> /** * Demonstrates cryptographic hash usage for integrity verification */ /* Calculate SHA-256 hash of a buffer */int calculate_sha256(const unsigned char *data, size_t len, unsigned char *hash_out) { SHA256_CTX ctx; if (!SHA256_Init(&ctx)) return -1; if (!SHA256_Update(&ctx, data, len)) return -1; if (!SHA256_Final(hash_out, &ctx)) return -1; return 0;} /* Hash comparison must be constant-time to prevent timing attacks */int secure_hash_compare(const unsigned char *a, const unsigned char *b, size_t len) { unsigned char result = 0; /* Compare all bytes regardless of differences */ for (size_t i = 0; i < len; i++) { result |= a[i] ^ b[i]; } /* Result is 0 only if all bytes match */ return result == 0 ? 0 : -1;} /* Verify data integrity against expected hash */int verify_integrity(const unsigned char *data, size_t len, const unsigned char *expected_hash) { unsigned char computed_hash[SHA256_DIGEST_LENGTH]; if (calculate_sha256(data, len, computed_hash) != 0) { return -1; /* Hash computation failed */ } /* Use constant-time comparison */ return secure_hash_compare(computed_hash, expected_hash, SHA256_DIGEST_LENGTH);} /* * HMAC: Hash-based Message Authentication Code * Provides both integrity AND authenticity * * Unlike a plain hash, HMAC requires a secret key. * An attacker without the key cannot forge valid HMACs. */int calculate_hmac_sha256(const unsigned char *key, size_t key_len, const unsigned char *data, size_t data_len, unsigned char *hmac_out) { /* HMAC(K, m) = H((K' xor opad) || H((K' xor ipad) || m)) */ /* This protects against length-extension attacks on plain hashes */ unsigned char k_prime[SHA256_BLOCK_SIZE] = {0}; unsigned char o_key_pad[SHA256_BLOCK_SIZE]; unsigned char i_key_pad[SHA256_BLOCK_SIZE]; /* If key is longer than block size, hash it first */ if (key_len > SHA256_BLOCK_SIZE) { SHA256(key, key_len, k_prime); } else { memcpy(k_prime, key, key_len); } /* Compute inner and outer padded keys */ for (int i = 0; i < SHA256_BLOCK_SIZE; i++) { i_key_pad[i] = k_prime[i] ^ 0x36; o_key_pad[i] = k_prime[i] ^ 0x5c; } /* Inner hash: H(i_key_pad || message) */ SHA256_CTX ctx; unsigned char inner_hash[SHA256_DIGEST_LENGTH]; SHA256_Init(&ctx); SHA256_Update(&ctx, i_key_pad, SHA256_BLOCK_SIZE); SHA256_Update(&ctx, data, data_len); SHA256_Final(inner_hash, &ctx); /* Outer hash: H(o_key_pad || inner_hash) */ SHA256_Init(&ctx); SHA256_Update(&ctx, o_key_pad, SHA256_BLOCK_SIZE); SHA256_Update(&ctx, inner_hash, SHA256_DIGEST_LENGTH); SHA256_Final(hmac_out, &ctx); return 0;}Use CRC for detecting accidental corruption (disk reads, network transmission). Use cryptographic hashes for detecting intentional modification (file integrity, password storage). Use HMAC when you need to prove that data was created by someone with the secret key (API authentication, session tokens).
Beyond data integrity, operating systems must protect their own integrity. If attackers can modify the kernel, device drivers, or critical system files, they gain persistent, privileged access that survives reboots and can evade security tools running within the compromised system.
Secure Boot:
Secure Boot establishes a chain of trust from power-on to operating system load. Each stage verifies the signature of the next stage before transferring control. UEFI firmware verifies the bootloader, the bootloader verifies the kernel, and the kernel verifies critical system files. If any signature check fails, the boot process halts.
Kernel Lockdown:
Modern kernels implement self-protection mechanisms that restrict what even root-privileged processes can do. Linux's kernel lockdown mode, for example, prevents writing to /dev/mem, blocks kexec, and restricts kernel module loading. These restrictions prevent rootkits from modifying the running kernel.
| Mechanism | OS | What It Protects | How It Works |
|---|---|---|---|
| Secure Boot | Cross-platform | Boot chain | Cryptographic signature verification before execution |
| SIP | macOS | System files and processes | Kernel restricts modification of protected paths |
| Windows Defender System Guard | Windows | System boot and runtime | Measured boot + runtime attestation |
| dm-verity | Linux/Android | Filesystem integrity | Merkle tree verification of block devices |
| IMA | Linux | File integrity | Kernel measures files before execution |
| Kernel Lockdown | Linux | Kernel integrity | Restricts runtime kernel modification |
macOS System Integrity Protection (SIP):
macOS SIP restricts the root user from modifying protected system locations. Even with root access, processes cannot write to /System, /usr, /bin, or /sbin. Only Apple-signed software running during boot can modify these locations. This ensures that malware cannot persistently compromise the operating system, even if it briefly obtains root access.
Linux Integrity Measurement Architecture (IMA):
IMA provides runtime integrity verification for Linux systems. When files are opened or executed, IMA calculates their hash and optionally verifies it against a stored reference. If verification fails, access is denied. IMA logs form an audit trail that can prove system integrity to remote verifiers through attestation.
12345678910111213141516171819202122232425262728293031323334
# Linux Integrity Measurement Architecture (IMA)# /etc/ima/ima-policy # Measure all executed binariesmeasure func=BPRM_CHECK mask=MAY_EXEC # Measure all shared librariesmeasure func=FILE_MMAP mask=MAY_EXEC # Measure all files opened for read by rootmeasure func=FILE_CHECK mask=MAY_READ uid=0 # Appraise (verify) executables against signaturesappraise func=BPRM_CHECK mask=MAY_EXEC appraise_type=imasig # Appraise kernel modules against signatures appraise func=MODULE_CHECK appraise_type=imasig # Appraise firmware against signaturesappraise func=FIRMWARE_CHECK appraise_type=imasig # Checking IMA measurements$ cat /sys/kernel/security/ima/ascii_runtime_measurements10 abc123... ima-ng sha256:def456... /usr/bin/bash10 bcd234... ima-ng sha256:efg567... /lib/x86_64-linux-gnu/libc.so.6... # Each line shows:# - PCR index (Platform Configuration Register)# - Template hash (for TPM extension)# - Template type# - File hash: filepath # These measurements can be remotely attested using a TPMEvery integrity verification chain must start somewhere. This 'root of trust' is typically immutable hardware or firmware that cannot be forged. TPM chips, UEFI firmware in protected flash, and CPU boot ROM provide these trust anchors. If the root of trust is compromised, all downstream integrity guarantees fail.
File systems face constant integrity challenges. Media degrades over time, cosmic rays flip bits, power failures interrupt writes, and bugs in storage stacks can corrupt data. Modern file systems implement sophisticated integrity mechanisms to detect and often correct these problems.
Journaling:
Journaling file systems like ext4, NTFS, and HFS+ maintain a log (journal) of pending changes. Before modifying file system metadata, the change is written to the journal. If a crash occurs during the actual update, the journal allows recovery to a consistent state. This protects metadata integrity but typically does not cover file contents.
Copy-on-Write and Checksums:
ZFS and Btrfs go further by checksumming all data and metadata. Every block has an associated checksum verified on read. If corruption is detected and redundant copies exist (through mirroring or RAID), the file system automatically uses the good copy and repairs the corrupt one. This catches 'bit rot' that would go undetected by traditional file systems.
dm-verity for Immutable Integrity:
dm-verity provides verified boot for block devices on Linux and Android. The entire file system is hashed in a Merkle tree structure. When any block is read, its hash is verified against the tree. If verification fails, the read returns an error rather than corrupt data.
This is particularly powerful for read-only systems. The root hash of the Merkle tree is stored in a trusted location (like kernel command line, verified by Secure Boot). Any modification to any block—even a single bit—changes the root hash and is immediately detected.
Studies have shown that enterprise storage systems experience 1 undetected corruption per 8.5 years of operation per drive. With hundreds or thousands of drives, this becomes a near-certainty. File systems that detect and correct such corruption are essential for large-scale storage integrity.
Prevention is ideal, but detection is essential. No system is impervious to attack, and integrity monitoring provides a crucial layer of defense by detecting modifications after they occur.
File Integrity Monitoring (FIM):
FIM tools like AIDE, OSSEC, and Tripwire periodically scan file systems and compare current states against known-good baselines. Changes to critical system files, configuration, or binaries trigger alerts for investigation. FIM is a cornerstone of compliance requirements and security best practices.
Runtime Integrity Monitoring:
Beyond file system monitoring, systems can monitor runtime behavior for integrity violations. Unexpected process behavior, anomalous system calls, or deviation from established baselines may indicate compromise. eBPF programs in Linux enable sophisticated runtime monitoring with minimal performance impact.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
# /etc/aide/aide.conf - Advanced Intrusion Detection Environment # Define what changes to monitor# p: permissions, i: inode, n: link count, u: user, g: group# s: size, b: block count, m: mtime, a: atime, c: ctime# S: check for growing size, acl: access control lists# selinux: SELinux context, xattrs: extended attributes# sha256: SHA256 hash, sha512: SHA512 hash # Rule definitionsNORMAL = p+i+n+u+g+s+m+c+acl+selinux+xattrs+sha256DATAONLY = p+n+u+g+s+sha256LOGS = p+n+u+g+S # What to monitor # Binaries - changes are suspicious/bin NORMAL/sbin NORMAL/usr/bin NORMAL/usr/sbin NORMAL # Libraries - changes are suspicious/lib NORMAL/lib64 NORMAL/usr/lib NORMAL # Configuration - track all changes/etc NORMAL # Logs - should only grow, not shrink/var/log LOGS # Exclude transient files!/var/cache!/var/tmp!/proc!/sys # Initialize baseline$ aide --init# Creates /var/lib/aide/aide.db.new.gz # Perform integrity check$ aide --check # Update baseline after verified changes$ aide --update # Example output showing detected change:# Entry /etc/passwd in databases has different attributes:# m ... ..T...: 2024-01-15 10:00:00 -> 2024-01-16 14:30:00# sha256 ...: hash1... -> hash2...Integrity monitoring systems are themselves targets. Sophisticated attackers will attempt to modify baseline databases, disable monitoring agents, or filter their activities from logs. Best practices store baselines on read-only media, run monitors in isolated environments, and forward logs to remote systems before attackers can tamper with them.
Integrity ensures that data and systems remain accurate, consistent, and trustworthy. Operating systems implement integrity through memory protection, file system mechanisms, cryptographic verification, and comprehensive monitoring. Let's consolidate the key concepts:
What's Next:
We've explored confidentiality and integrity—two of the three pillars of the CIA triad. In the next page, we'll examine Availability, the protection goal that ensures systems and data remain accessible when needed. While confidentiality and integrity protect the quality of information, availability ensures that information is actually usable.
You now understand integrity as a protection goal, including its mechanisms, verification techniques, and monitoring approaches. This knowledge enables you to design systems that maintain trustworthy data and detect tampering when it occurs. Next, we'll complete the CIA triad by examining availability.