/ Security

Security

Miko's Security class provides protection against common web vulnerabilities including XSS, CSRF, and SQL injection.


Security Methods Summary

Method Description
escape($string)Escape HTML entities (XSS protection)
sanitize($string)Remove dangerous characters
generateCsrfToken()Generate CSRF token
validateCsrfToken($token)Validate CSRF token
hashPassword($password)Hash password with bcrypt
verifyPassword($password, $hash)Verify password hash

XSS Protection

Escaping Output

use Miko\Library\Security;

// Escape HTML entities
$userInput = '<script>alert("XSS")</script>';
$safe = Security::escape($userInput);
// Output: &lt;script&gt;alert(&quot;XSS&quot;)&lt;/script&gt;

// Use in templates
echo Security::escape($user->Name);
echo Security::escape($comment->Content);

Sanitizing Input

// Remove dangerous characters
$clean = Security::sanitize($userInput);

// Strip HTML tags
$plain = Security::stripTags($html);

// Allow specific tags
$safe = Security::stripTags($html, '<p><br><strong><em>');

CSRF Protection

Generate Token

// Generate and store CSRF token
$token = Security::generateCsrfToken();
$_SESSION['csrf_token'] = $token;

Include in Forms

<form method="POST" action="/submit">
    <input type="hidden" name="_token" value="<?= $token ?>">
    <!-- form fields -->
    <button type="submit">Submit</button>
</form>

Validate Token

// Validate on form submission
$submittedToken = $_POST['_token'] ?? '';

if (!Security::validateCsrfToken($submittedToken, $_SESSION['csrf_token'])) {
    http_response_code(403);
    die('Invalid CSRF token');
}

Password Security

Hashing Passwords

// Hash password (bcrypt)
$password = 'user-password-123';
$hash = Security::hashPassword($password);

// Store $hash in database
User::create([
    'Email' => $email,
    'Password' => $hash
]);

Verifying Passwords

// Verify password
$user = User::where('Email', $email)->first();

if ($user && Security::verifyPassword($inputPassword, $user->Password)) {
    // Password is correct
    $_SESSION['user_id'] = $user->Id;
} else {
    // Invalid credentials
}

SQL Injection Protection

Miko ORM uses prepared statements by default:

// SAFE: Using Query Builder (parameterized)
$users = User::where('Email', $email)->get();

// SAFE: Using prepared statements
$users = DB::query("SELECT * FROM users WHERE Email = ?", [$email]);

// DANGEROUS: Never do this!
// $users = DB::query("SELECT * FROM users WHERE Email = '$email'");

Input Validation

// Validate and sanitize input
$email = filter_var($_POST['email'], FILTER_VALIDATE_EMAIL);
$age = filter_var($_POST['age'], FILTER_VALIDATE_INT);

if (!$email) {
    throw new Exception('Invalid email');
}

// Use Validator for complex validation
$validator = new Validator($_POST);
$validator->validate([
    'email' => 'required|email',
    'password' => 'required|min:8'
]);

Rate Limiting

class RateLimiter
{
    public static function check(string $key, int $maxAttempts, int $decayMinutes): bool
    {
        $cacheKey = "rate_limit:$key";
        $attempts = Cache::get($cacheKey, 0);
        
        if ($attempts >= $maxAttempts) {
            return false;  // Rate limited
        }
        
        Cache::put($cacheKey, $attempts + 1, $decayMinutes * 60);
        return true;
    }
}

// Usage: Limit login attempts
$ip = $_SERVER['REMOTE_ADDR'];
if (!RateLimiter::check("login:$ip", 5, 15)) {
    http_response_code(429);
    die('Too many attempts. Please try again later.');
}

Secure Headers

// Set security headers
header('X-Content-Type-Options: nosniff');
header('X-Frame-Options: DENY');
header('X-XSS-Protection: 1; mode=block');
header('Referrer-Policy: strict-origin-when-cross-origin');
header('Content-Security-Policy: default-src \'self\'');

// HTTPS only
if ($_SERVER['HTTPS'] !== 'on') {
    header('Location: https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
    exit;
}

Session Security

// Secure session configuration
ini_set('session.cookie_httponly', 1);
ini_set('session.cookie_secure', 1);
ini_set('session.use_strict_mode', 1);
ini_set('session.cookie_samesite', 'Strict');

session_start();

// Regenerate session ID after login
session_regenerate_id(true);

Best Practices

Practice Description
Escape outputAlways escape user data before display
Use prepared statementsNever concatenate SQL queries
Validate inputValidate all user input server-side
Hash passwordsUse bcrypt, never store plain text
Use HTTPSEncrypt all traffic
Set secure headersPrevent common attacks
Rate limitPrevent brute force attacks
Keep secrets safeUse environment variables