Skip to main content

Insecure service configuration - BREACH Attack

Need

Secure service configuration to prevent BREACH attacks

Context

  • Usage of PHP 7.0 for server-side scripting and web development
  • Usage of random_bytes for generating random bytes or cryptographic keys

Description

Non compliant code

<?php
// vulnerable.php
session_start();

if (!isset($_SESSION['token'])) {
$_SESSION['token'] = bin2hex(random_bytes(32));
}

if (isset($_POST['user-input'])) {
$userInput = $_POST['user-input'];
} else {
$userInput = '';
}

header('Content-Encoding: gzip');
echo 'Your input: ' . htmlentities($userInput) . '<br>';
echo 'Your token: ' . $_SESSION['token'];
?>

In the above code, the application is using HTTP gzip compression, which is enabled by the header 'Content-Encoding: gzip'.

The user input is reflected back to them on the website with the line "echo 'Your input: ' . htmlentities($userInput) . br;". This means that any data entered by the user is displayed back to them, making the site potentially vulnerable to a BREACH attack.

Finally, the application stores secrets in the form of session tokens with the line "echo 'Your token: ' . $_SESSION['token'];". This is the secret that an attacker could potentially uncover through a BREACH attack.

In a Laravel application, this might be a CSRF token or a session ID stored in a cookie. The combination of these factors makes the application potentially vulnerable to BREACH attacks.

Steps

  • Disable HTTP gzip compression. This is one of the conditions that make the site vulnerable to BREACH attacks.
  • Avoid reflecting user input directly on the site. Instead, use a secure method to handle user input, such as input validation or output encoding.
  • Implement a secure method to handle secrets. For example, use secure, encrypted cookies to store session tokens or anti-CSRF tokens, and ensure they are only sent over HTTPS.

Compliant code

<?php
// secure.php
session_start();

if (!isset($_SESSION['token'])) {
$_SESSION['token'] = bin2hex(random_bytes(32));
}

if (isset($_POST['user-input'])) {
$userInput = filter_input(INPUT_POST, 'user-input', FILTER_SANITIZE_STRING);
} else {
$userInput = '';
}

// Removed the gzip compression
// header('Content-Encoding: gzip');

echo 'Your input: ' . htmlentities($userInput, ENT_QUOTES, 'UTF-8') . '<br>';
echo 'Your token: ' . $_SESSION['token'];
?>

The updated code includes several changes to mitigate the risk of a BREACH attack:

  1. HTTP gzip compression is disabled: The header('Content-Encoding: gzip'); line has been removed. This prevents the site from using HTTP gzip compression, which is one of the conditions that make it vulnerable to BREACH attacks.

  2. User input is sanitized: The filter_input() function is used to sanitize the user input. This function filters data coming from insecure sources (like user input) and can validate or sanitize it. In this case, it's used with the FILTER_SANITIZE_STRING filter, which strips tags and remove or encode special characters from a string.

  3. Output encoding is used: The htmlentities() function is used with the ENT_QUOTES flag to convert both double and single quotes to their HTML entities. This prevents any potential HTML injection attacks by ensuring that any characters that have special meaning in HTML are properly encoded.

  4. Session tokens are handled securely: The session token is generated using the bin2hex(random_bytes(32)) function, which generates a cryptographically secure random string. This token is stored in a session variable, which is a secure way to handle secrets as it's stored on the server side and can't be accessed via JavaScript.

Remember to always use HTTPS to ensure that the session token is sent over a secure connection.

References