Improper Enforcement of Message Integrity During Transmission in a Communication Channel

Description

Improper Enforcement of Message Integrity During Transmission occurs when a product establishes a communication channel with an endpoint and receives messages from that endpoint, but does not sufficiently ensure that messages were not modified during transmission. Without proper integrity verification mechanisms, attackers who can access the network path between communicating parties can modify message contents without detection. This includes altering data values, injecting malicious content, replaying old messages, or completely substituting messages.

Risk

This vulnerability enables various man-in-the-middle attack scenarios. Attackers can modify financial transactions to change amounts or destinations. Command and control messages can be altered to execute different operations. Software update mechanisms can be compromised to deliver malicious payloads. Configuration data can be changed to weaken security settings. Authentication tokens or session data can be modified for privilege escalation. The risk is particularly severe in protocols that transmit sensitive or security-critical information, as modifications may go undetected until significant damage has occurred.

Solution

Implement cryptographic message integrity verification using HMACs (Hash-based Message Authentication Codes) or digital signatures. Use authenticated encryption modes (GCM, CCM) that provide both confidentiality and integrity. Employ TLS/HTTPS for transport security, which provides built-in integrity checks. Include sequence numbers or timestamps to prevent replay attacks. Verify message integrity before processing any message content. For signed messages, validate signatures using trusted public keys. Consider using established protocols (TLS, SSH) rather than implementing custom integrity mechanisms.

Common Consequences

ImpactDetails
IntegrityScope: Integrity

Modify Application Data - Attackers can modify message contents during transmission without detection.
Integrity, ConfidentialityScope: Integrity, Confidentiality

Gain Privileges or Assume Identity - If attackers can spoof endpoints or modify messages, they may gain privileges intended for legitimate parties.

Example Code

Vulnerable Code

# Vulnerable: No message integrity verification
import socket
import json

class VulnerableClient:

    def __init__(self, host, port):
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.connect((host, port))

    def send_command(self, command, amount):
        # Vulnerable: No integrity protection
        message = json.dumps({
            'command': command,
            'amount': amount
        })
        self.sock.send(message.encode())

    def receive_response(self):
        # Vulnerable: No verification that response wasn't modified
        data = self.sock.recv(4096)
        return json.loads(data.decode())

# Attacker on network can modify "transfer 100" to "transfer 100000"
// Vulnerable: Custom protocol without message authentication
public class VulnerableProtocol {

    public void sendMessage(OutputStream out, String command, Map<String, String> params)
            throws IOException {

        // Vulnerable: No integrity check
        StringBuilder message = new StringBuilder();
        message.append(command).append("|");

        for (Map.Entry<String, String> entry : params.entrySet()) {
            message.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
        }

        out.write(message.toString().getBytes());
        out.flush();

        // Attacker can modify message content in transit
    }

    public Map<String, String> receiveMessage(InputStream in) throws IOException {
        byte[] buffer = new byte[4096];
        int bytesRead = in.read(buffer);

        // Vulnerable: Trusting received data without verification
        String message = new String(buffer, 0, bytesRead);
        return parseMessage(message);
    }
}
// Vulnerable: Configuration update without integrity check
typedef struct {
    char server_address[256];
    int port;
    int security_level;
    char admin_password[64];
} Config;

int vulnerable_update_config(int socket_fd) {
    Config new_config;

    // Vulnerable: Reading config directly from network without verification
    ssize_t bytes_read = recv(socket_fd, &new_config, sizeof(Config), 0);

    if (bytes_read == sizeof(Config)) {
        // Apply config without checking integrity
        apply_config(&new_config);  // Attacker modified config accepted!
        return 0;
    }

    return -1;
}
// Vulnerable: API without message signing
async function vulnerableApiCall(endpoint, data) {
    // Vulnerable: No integrity verification of response
    const response = await fetch(endpoint, {
        method: 'POST',
        body: JSON.stringify(data),
        headers: { 'Content-Type': 'application/json' }
    });

    // Attacker could have modified the response
    const result = await response.json();
    return result;  // Processing potentially modified data
}
# Vulnerable: Software update without verification
import urllib.request

class VulnerableUpdater:

    def download_update(self, url):
        # Vulnerable: No verification of update integrity
        response = urllib.request.urlopen(url)
        update_data = response.read()

        # Attacker could serve malicious update
        self.install_update(update_data)

    def install_update(self, data):
        # Installing potentially modified/malicious update
        with open('/opt/myapp/update.bin', 'wb') as f:
            f.write(data)
        # Execute update...

Fixed Code

# Fixed: Message integrity with HMAC
import socket
import json
import hmac
import hashlib
import os

class FixedClient:

    def __init__(self, host, port, shared_secret):
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.connect((host, port))
        self.secret = shared_secret.encode()
        self.sequence = 0

    def send_command(self, command, amount):
        self.sequence += 1

        message = json.dumps({
            'command': command,
            'amount': amount,
            'sequence': self.sequence,
            'timestamp': time.time()
        })

        # Fixed: Calculate HMAC for integrity
        mac = hmac.new(self.secret, message.encode(), hashlib.sha256)
        signature = mac.hexdigest()

        # Send message with signature
        packet = json.dumps({
            'message': message,
            'signature': signature
        })
        self.sock.send(packet.encode())

    def receive_response(self):
        data = self.sock.recv(4096)
        packet = json.loads(data.decode())

        message = packet['message']
        received_signature = packet['signature']

        # Fixed: Verify HMAC before trusting data
        expected_mac = hmac.new(self.secret, message.encode(), hashlib.sha256)
        expected_signature = expected_mac.hexdigest()

        if not hmac.compare_digest(received_signature, expected_signature):
            raise SecurityError("Message integrity check failed!")

        return json.loads(message)
// Fixed: Message authentication with digital signatures
import java.security.*;
import javax.crypto.*;

public class FixedProtocol {

    private PrivateKey signingKey;
    private PublicKey verifyKey;

    public FixedProtocol(PrivateKey signingKey, PublicKey verifyKey) {
        this.signingKey = signingKey;
        this.verifyKey = verifyKey;
    }

    public void sendMessage(OutputStream out, String command, Map<String, String> params)
            throws Exception {

        StringBuilder message = new StringBuilder();
        message.append(command).append("|");
        message.append(System.currentTimeMillis()).append("|");

        for (Map.Entry<String, String> entry : params.entrySet()) {
            message.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
        }

        byte[] messageBytes = message.toString().getBytes("UTF-8");

        // Fixed: Sign the message
        Signature sig = Signature.getInstance("SHA256withRSA");
        sig.initSign(signingKey);
        sig.update(messageBytes);
        byte[] signature = sig.sign();

        // Send length + message + signature
        DataOutputStream dos = new DataOutputStream(out);
        dos.writeInt(messageBytes.length);
        dos.write(messageBytes);
        dos.writeInt(signature.length);
        dos.write(signature);
        dos.flush();
    }

    public Map<String, String> receiveMessage(InputStream in) throws Exception {
        DataInputStream dis = new DataInputStream(in);

        int msgLength = dis.readInt();
        byte[] messageBytes = new byte[msgLength];
        dis.readFully(messageBytes);

        int sigLength = dis.readInt();
        byte[] signature = new byte[sigLength];
        dis.readFully(signature);

        // Fixed: Verify signature before trusting data
        Signature sig = Signature.getInstance("SHA256withRSA");
        sig.initVerify(verifyKey);
        sig.update(messageBytes);

        if (!sig.verify(signature)) {
            throw new SecurityException("Message signature verification failed!");
        }

        return parseMessage(new String(messageBytes, "UTF-8"));
    }
}
// Fixed: Configuration update with integrity check
#include <openssl/evp.h>
#include <openssl/hmac.h>

typedef struct {
    char server_address[256];
    int port;
    int security_level;
    char admin_password[64];
    unsigned char hmac[32];  // SHA-256 HMAC
} SecureConfig;

static const unsigned char shared_key[] = "...";  // Should be securely stored

int fixed_update_config(int socket_fd) {
    SecureConfig new_config;

    ssize_t bytes_read = recv(socket_fd, &new_config, sizeof(SecureConfig), 0);

    if (bytes_read != sizeof(SecureConfig)) {
        return -1;
    }

    // Fixed: Verify HMAC before trusting config
    unsigned char expected_hmac[32];
    unsigned int hmac_len;

    // Calculate HMAC over config data (excluding the HMAC field itself)
    HMAC(EVP_sha256(),
         shared_key, sizeof(shared_key),
         (unsigned char*)&new_config, sizeof(SecureConfig) - 32,
         expected_hmac, &hmac_len);

    // Fixed: Constant-time comparison
    if (CRYPTO_memcmp(new_config.hmac, expected_hmac, 32) != 0) {
        fprintf(stderr, "Config integrity check failed!\n");
        return -1;
    }

    // Config verified, safe to apply
    apply_config(&new_config);
    return 0;
}
// Fixed: API with request/response signing
const crypto = require('crypto');

class SecureApiClient {
    constructor(apiKey, secretKey) {
        this.apiKey = apiKey;
        this.secretKey = secretKey;
    }

    async makeRequest(endpoint, data) {
        const timestamp = Date.now().toString();
        const nonce = crypto.randomBytes(16).toString('hex');

        const payload = JSON.stringify({
            data,
            timestamp,
            nonce
        });

        // Fixed: Sign the request
        const signature = crypto
            .createHmac('sha256', this.secretKey)
            .update(payload)
            .digest('hex');

        const response = await fetch(endpoint, {
            method: 'POST',
            body: payload,
            headers: {
                'Content-Type': 'application/json',
                'X-Api-Key': this.apiKey,
                'X-Signature': signature,
                'X-Timestamp': timestamp,
                'X-Nonce': nonce
            }
        });

        const responseBody = await response.text();
        const responseSignature = response.headers.get('X-Response-Signature');

        // Fixed: Verify response signature
        const expectedSignature = crypto
            .createHmac('sha256', this.secretKey)
            .update(responseBody)
            .digest('hex');

        if (responseSignature !== expectedSignature) {
            throw new Error('Response integrity verification failed!');
        }

        return JSON.parse(responseBody);
    }
}
# Fixed: Software update with cryptographic verification
import urllib.request
import hashlib
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding

class FixedUpdater:

    def __init__(self, public_key_pem):
        self.public_key = serialization.load_pem_public_key(public_key_pem)

    def download_update(self, url, signature_url, expected_hash):
        # Download update
        response = urllib.request.urlopen(url)
        update_data = response.read()

        # Fixed: Verify hash
        actual_hash = hashlib.sha256(update_data).hexdigest()
        if actual_hash != expected_hash:
            raise SecurityError("Update hash mismatch!")

        # Download signature
        sig_response = urllib.request.urlopen(signature_url)
        signature = sig_response.read()

        # Fixed: Verify digital signature
        try:
            self.public_key.verify(
                signature,
                update_data,
                padding.PSS(
                    mgf=padding.MGF1(hashes.SHA256()),
                    salt_length=padding.PSS.MAX_LENGTH
                ),
                hashes.SHA256()
            )
        except Exception as e:
            raise SecurityError(f"Update signature verification failed: {e}")

        # Signature valid, safe to install
        self.install_update(update_data)

    def install_update(self, data):
        with open('/opt/myapp/update.bin', 'wb') as f:
            f.write(data)
        # Execute update...

  • CWE-345: Insufficient Verification of Data Authenticity (parent)
  • CWE-354: Improper Validation of Integrity Check Value (related)
  • CWE-494: Download of Code Without Integrity Check (related)
  • CWE-353: Missing Support for Integrity Check (related)

References

  1. MITRE Corporation. "CWE-924: Improper Enforcement of Message Integrity During Transmission in a Communication Channel." https://cwe.mitre.org/data/definitions/924.html
  2. OWASP. "Cryptographic Failures." OWASP Top Ten 2021.
  3. NIST. "Guidelines for the Selection and Use of Transport Layer Security (TLS) Implementations."