Secure Development

When Logs Save the Day: A Developer’s Guide to Security Logging

Security logging: “Real” Stories from the Development Trenches

Amine Raji
3 min readNov 4, 2024

--

Photo by l ch on Unsplash

The 3 AM Wake-Up Call

It was 3 AM when Sarah, a senior developer at an e-commerce platform, received an urgent call. Multiple customers reported unauthorized purchases on their accounts. Without proper logging, finding the breach could have taken weeks. Thanks to her team’s robust security logging implementation, they identified the issue within hours: a vulnerability in their authentication system was allowing session hijacking.

# The logging pattern that saved the day
def log_session_activity(session_id, user_id, action, metadata=None):
log.info({
"event_type": "session_activity",
"timestamp": datetime.utcnow().isoformat(),
"session_id": session_id,
"user_id": user_id,
"action": action,
"ip_address": request.remote_addr,
"user_agent": request.headers.get('User-Agent'),
"metadata": metadata,
"request_id": request.id
})

The Missing Audit Trail

Alex’s team was building a healthcare application when they received their first HIPAA audit. The auditors requested six months of access logs for patient records. That’s when they realized their basic logging wasn’t enough:

Photo by Adrian Swancar on Unsplash

Before: Basic Logging

# Too simplistic, lacks crucial audit information
log.info(f"User {user_id} accessed patient record {record_id}")

After: Audit-Ready Logging

def log_medical_record_access(user_id, record_id, action, reason):
log.info({
"event": "medical_record_access",
"timestamp": datetime.utcnow().isoformat(),
"user": {
"id": user_id,
"role": get_user_role(user_id),
"department": get_user_department(user_id)
},
"record": {
"id": record_id,
"type": get_record_type(record_id),
"action": action
},
"access_reason": reason,
"access_location": get_user_location(),
"session_id": current_session_id,
"correlation_id": current_correlation_id
})

The Silent Security Breach

Mike’s fintech startup discovered a breach three months after it happened. An attacker had slowly escalated privileges across multiple accounts. The traditional security tools missed it because each individual action looked legitimate. Here’s how they redesigned their logging:

class SecurityEventLogger:
def __init__(self):
self.suspicious_patterns = {
"privilege_escalation": {
"threshold": 3,
"window_minutes": 60
},
"failed_logins": {
"threshold": 5,
"window_minutes": 15
}
}

def log_permission_change(self, user_id, target_user_id, old_perms, new_perms):
event = {
"event": "permission_modification",
"timestamp": datetime.utcnow().isoformat(),
"actor_id": user_id,
"target_id": target_user_id,
"old_permissions": old_perms,
"new_permissions": new_perms,
"change_vector": self._calculate_permission_change_vector(old_perms, new_perms)
}

log.info(event)
self._check_escalation_pattern(user_id)

def _check_escalation_pattern(self, user_id):
# Check for suspicious patterns in recent permission changes
recent_changes = self._get_recent_permission_changes(
user_id,
minutes=self.suspicious_patterns["privilege_escalation"]["window_minutes"]
)

if len(recent_changes) >= self.suspicious_patterns["privilege_escalation"]["threshold"]:
self._trigger_security_alert(user_id, "suspicious_permission_changes", recent_changes)

The Production Debug Nightmare

Jennifer’s team was handling a critical payment system. During a post-mortem of a failed transaction, they realized their logs were flooded with unnecessary information while missing crucial transaction details:

Before: Noisy Logging

# Too much noise, missing important context
log.debug("Starting transaction")
log.debug("Checking user balance")
log.debug("Processing payment")
log.info("Transaction completed")

After: Context-Rich Logging

def process_payment(transaction_id, amount, user_id):
payment_logger = PaymentLogger(transaction_id)

try:
payment_logger.start_transaction({
"amount": amount,
"user_id": user_id,
"currency": "USD",
"payment_method": get_user_payment_method(user_id)
})

# Process payment...

payment_logger.complete_transaction({
"status": "success",
"processing_time_ms": processing_time,
"confirmation_code": confirmation_code
})

except PaymentException as e:
payment_logger.failed_transaction({
"error_code": e.code,
"error_message": str(e),
"failure_point": e.failure_point
})
raise

class PaymentLogger:
def __init__(self, transaction_id):
self.transaction_id = transaction_id
self.start_time = time.time()

def _log_event(self, event_type, data):
log.info({
"service": "payment",
"event": event_type,
"transaction_id": self.transaction_id,
"timestamp": datetime.utcnow().isoformat(),
"elapsed_ms": int((time.time() - self.start_time) * 1000),
"data": data
})

Lessons Learned

1. Context is King

  • Always include correlation IDs
  • Log user context and business context
  • Include timestamps in UTC
  • Add relevant metadata for debugging

2. Security First

  • Never log sensitive data
  • Include IP addresses and user agents
  • Log authentication events extensively
  • Track permission changes

3. Performance Matters

  • Use asynchronous logging
  • Implement log levels appropriately
  • Consider log rotation and storage
  • Monitor logging impact on performance

4. Compliance Ready

  • Maintain audit trails
  • Include user roles and reasons
  • Log access to sensitive data
  • Implement retention policies

The Developer’s Logging Checklist

Before deploying your next feature, ask yourself:

  • Would these logs help me debug an issue at 3 AM?
  • Could I track a suspicious user’s actions across the system?
  • Would these logs satisfy our compliance requirements?
  • Is sensitive information properly masked?
  • Can I trace a request across all our services?

Conclusion

As these stories show, proper security logging isn’t just about following best practices — it’s about preparing for the unexpected. Every log entry you write today could be the crucial piece of evidence you need tomorrow. Remember: in the world of security, you’re not just logging for debugging; you’re logging for survival.

--

--

Amine Raji
Amine Raji

Written by Amine Raji

Security expert 🔒 | Empowering organizations 🌐 to safeguard their assets with future-proof architectures & security solutions💥