Log injection - Python

Log injection - Python

Need

Prevention of log injection attacks

Context

  • Usage of Python 3 for developing applications and scripts
  • Usage of logging for recording and tracking application events
  • Usage of Django for building web applications in Python

Description

Non compliant code

        import logging
from django.http import HttpResponse

def log_message(request):
    user_message = request.GET.get('message')
    logging.info('User message: ' + user_message)
    return HttpResponse("Message logged")
        
        

In the above code, the function log_message takes a user input through a GET request and directly logs this message using the logging module of Python. The problem here is that the user's message is not validated, sanitized, or escaped before it is logged. This means that an attacker could potentially pass malicious input that could lead to log injection.

Log injection vulnerabilities occur when data from untrusted sources is written into logs without proper sanitization. Attackers can exploit this vulnerability to insert false entries into log files, or worse, exploit other vulnerabilities such as local file inclusion (LFI) or remote code execution (RCE).

In the context of this code, an attacker could pass a message containing malicious data or commands that could compromise the system when the log is processed. For example, if the log files are later parsed by a tool that executes certain commands present in the logs, or if the logs are used to populate a web page, the attacker's input could lead to harmful actions.

Steps

  • Validate the user input to ensure it is in the expected format.
  • Sanitize the user input to remove any potentially harmful characters or sequences.
  • Escape any special characters in the user input that could be interpreted in a way that alters the log entry's meaning.
  • Consider using a logging library or feature that automatically sanitizes and escapes log entries.

Compliant code

        import logging
from django.http import HttpResponse
from django.utils.html import escape

def log_message(request):
    user_message = request.GET.get('message')
    if user_message:
        # Sanitize the user input
        sanitized_message = escape(user_message)
        logging.info('User message: ' + sanitized_message)
        return HttpResponse("Message logged")
    else:
        return HttpResponse("No message provided")
        
        

The original code was vulnerable to log injection attacks because it directly used user input in a log entry without validating, sanitizing, or escaping it. This could allow an attacker to inject malicious content into the log files, which could then be executed if the log files are processed in a certain way.

The fixed code mitigates this vulnerability by using Django's escape function to sanitize the user input before it is logged. This function replaces any special HTML characters in the input with their corresponding HTML entities, effectively neutralizing any potentially harmful content.

The fixed code also checks if a message was provided by the user before attempting to log it. This prevents an error from occurring if the 'message' parameter is not included in the request.

Please note that this is a basic fix and might not cover all possible edge cases. For a more comprehensive solution, consider using a dedicated input validation and sanitization library, and/or a logging library that automatically sanitizes and escapes log entries.

References