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: <script>alert("XSS")</script>
// 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 output | Always escape user data before display |
| Use prepared statements | Never concatenate SQL queries |
| Validate input | Validate all user input server-side |
| Hash passwords | Use bcrypt, never store plain text |
| Use HTTPS | Encrypt all traffic |
| Set secure headers | Prevent common attacks |
| Rate limit | Prevent brute force attacks |
| Keep secrets safe | Use environment variables |