Key Takeaways

  • Never trust user input - validate everything
  • Use parameterized queries - prevent injection
  • Encode output - context-aware escaping
  • Fail securely - don't leak information

1. Secure Coding Principles

2. Input Validation

Insecure
// SQL Injection vulnerable
$query = "SELECT * FROM users WHERE id = " . $_GET['id'];
mysqli_query($conn, $query);

// Direct use of user input
echo "Hello, " . $_GET['name'];
Secure
// Parameterized query
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$_GET['id']]);

// Validate and sanitize
$name = filter_input(INPUT_GET, 'name', FILTER_SANITIZE_STRING);
echo "Hello, " . htmlspecialchars($name, ENT_QUOTES, 'UTF-8');

Validation Rules

3. Output Encoding

// Context-aware encoding

// HTML context
htmlspecialchars($data, ENT_QUOTES, 'UTF-8');

// JavaScript context
json_encode($data);

// URL context
urlencode($data);

// CSS context
// Avoid user input in CSS

// Frameworks often handle this:
// React: {data} is auto-escaped
// Blade: {{ $data }} is escaped

4. Secure Authentication

# Password storage
import bcrypt

# Hash password (never store plaintext!)
hashed = bcrypt.hashpw(password.encode(), bcrypt.gensalt(12))

# Verify
bcrypt.checkpw(password.encode(), stored_hash)

# Session management
# - Regenerate session ID on login
# - Secure, HttpOnly, SameSite cookies
# - Implement session timeout
# - Invalidate on logout

# MFA
# Always implement for sensitive applications

5. Access Control

# IDOR Prevention
// Insecure - trusts user ID from URL
$user_id = $_GET['id'];
$data = get_user_data($user_id);

// Secure - verify ownership
$current_user = get_logged_in_user();
$data = get_user_data($user_id);
if ($data['owner_id'] !== $current_user['id']) {
    die('Access denied');
}

# Principle of least privilege
# - Default deny
# - Check authorization on every request
# - Verify at the function/data level, not just UI

6. Cryptography Best Practices

7. Secure Error Handling

# Insecure - leaks information
try {
    $result = $db->query($sql);
} catch (Exception $e) {
    echo $e->getMessage();  // Shows SQL error to user!
}

# Secure
try {
    $result = $db->query($sql);
} catch (Exception $e) {
    error_log($e->getMessage());  // Log for developers
    echo "An error occurred";     // Generic message for users
}

8. Security Checklist

Before Deployment
  • ☐ All inputs validated server-side
  • ☐ Parameterized queries (no SQL injection)
  • ☐ Output encoding in all contexts
  • ☐ Strong password hashing (Argon2id/bcrypt)
  • ☐ Secure session management
  • ☐ HTTPS enforced
  • ☐ Security headers configured
  • ☐ No secrets in code
  • ☐ Error messages don't leak info
  • ☐ Dependencies updated

FAQ

Should I use a web framework?
Yes! Modern frameworks (Django, Laravel, Rails, Spring) have built-in security features like CSRF protection, parameterized queries, and output encoding.

OWASP Top 10 API Security DevSecOps