Skip to main content

Logging Security Guidelines

This document outlines secure logging practices to prevent CWE-117 log injection vulnerabilities and comply with OWASP logging guidelines.

Security Principles

1. Never Log Sensitive Data

NEVER log the following types of data:

  • Authentication tokens (JWT, Bearer tokens, API keys)
  • Passwords or password hashes
  • Session identifiers
  • Payment information (card numbers, CVV, bank details)
  • Personal Identifiable Information (PII)
  • Raw request/response payloads without sanitization
  • Internal system secrets

2. Sanitize All User Input Before Logging

All user-provided data must be sanitized before logging to prevent log injection attacks:

# BAD - Direct logging of user input
log.info("User input received", data=request.POST)

# GOOD - Use structured logging with sanitized data
log.info("User registration attempt", username=username[:50], ip_address=get_client_ip(request))

3. Use Structured Logging

Our structlog configuration includes automatic sanitization. Use structured logging instead of string formatting:

# BAD - String formatting vulnerable to injection
log.info(f"User {username} logged in")

# GOOD - Structured logging with automatic sanitization
log.info("User login successful", username=username, user_id=user.id)

4. Log What's Necessary for Security

DO Log:

  • Authentication attempts (success/failure)
  • Authorization failures
  • Input validation failures
  • Security-relevant application events
  • Administrative actions
  • Data access patterns

DON'T Log:

  • Full request/response bodies
  • Sensitive data fields
  • Internal application state details

5. Implementation Examples

Authentication Logging

# Login success
log.info("User authentication successful",
user_id=user.id,
ip_address=get_client_ip(request),
user_agent_hash=hashlib.sha256(request.META.get('HTTP_USER_AGENT', '').encode()).hexdigest()[:16])

# Login failure
log.warn("Authentication failed",
username=username[:50], # Truncate to prevent log pollution
ip_address=get_client_ip(request),
failure_reason="invalid_credentials")

API Request Logging

# API access
log.info("API request",
endpoint=request.path,
method=request.method,
user_id=getattr(request.user, 'id', None),
status_code=response.status_code,
response_time_ms=response_time)

Error Logging

# System errors
log.error("Database connection failed",
operation="user_lookup",
error_code="DB_TIMEOUT",
retry_count=retry_count)

6. Log Sanitizer Configuration

Our log sanitizer automatically removes:

  • CRLF injection attempts (\r\n, %0a, %0d)
  • Control characters that could affect log parsing
  • Fields containing sensitive patterns (token, password, secret, etc.)
  • Overly long strings (truncated to 1000 chars)

Common Vulnerabilities to Avoid

CWE-117: Log Injection

# VULNERABLE
log.info(f"Processing request: {user_input}")

# SECURE
log.info("Processing user request", request_id=generate_request_id(), user_id=user.id)

Information Disclosure

# VULNERABLE
log.debug("Full user object", user=user.__dict__)

# SECURE
log.debug("User operation", user_id=user.id, operation="profile_update")

Log Pollution

# VULNERABLE - Can fill logs with junk
log.info("User message", message=untrusted_input)

# SECURE - Truncate and sanitize
log.info("User message received",
message_length=len(untrusted_input),
message_hash=hashlib.sha256(untrusted_input.encode()).hexdigest()[:16])

Testing Logging Security

Regularly test for:

  1. Log injection attempts in all input fields
  2. Sensitive data exposure in log files
  3. Log parsing errors due to malformed input
  4. Performance impact of logging under load

Compliance

This logging approach helps meet:

  • OWASP Logging Cheat Sheet recommendations
  • CWE-117 prevention guidelines
  • GDPR data minimization principles
  • SOC 2 logging requirements