🛡️ XSS Prevention & Input Sanitization
Comprehensive XSS protection implementation
<?php
// XSS Prevention Class
class XSSProtection
{
public static function sanitizeInput($input, $type = 'string')
{
switch ($type) {
case 'string':
return htmlspecialchars(
trim($input),
ENT_QUOTES | ENT_HTML5,
'UTF-8'
);
case 'email':
return filter_var(
trim($input),
FILTER_SANITIZE_EMAIL
);
case 'url':
return filter_var(
trim($input),
FILTER_SANITIZE_URL
);
case 'html':
// HTML purifier implementation
$config = HTMLPurifier_Config::createDefault();
$config->set('HTML.Allowed',
'p,b,strong,i,em,u,ul,ol,li,br,a[href|title]'
);
$purifier = new HTMLPurifier($config);
return $purifier->purify($input);
default:
return strip_tags(trim($input));
}
}
public static function generateCSRFToken()
{
if (session_status() !== PHP_SESSION_ACTIVE) {
session_start();
}
$token = bin2hex(random_bytes(32));
$_SESSION['csrf_token'] = $token;
$_SESSION['csrf_time'] = time();
return $token;
}
public static function validateCSRFToken($token)
{
if (session_status() !== PHP_SESSION_ACTIVE) {
session_start();
}
if (!isset($_SESSION['csrf_token']) ||
!isset($_SESSION['csrf_time'])) {
return false;
}
// Token expires in 1 hour
if (time() - $_SESSION['csrf_time'] > 3600) {
unset($_SESSION['csrf_token']);
unset($_SESSION['csrf_time']);
return false;
}
return hash_equals($_SESSION['csrf_token'], $token);
}
}
// Usage Example
$userInput = $_POST['comment'] ?? '';
$cleanComment = XSSProtection::sanitizeInput($userInput, 'html');
if ($_POST['csrf_token'] &&
XSSProtection::validateCSRFToken($_POST['csrf_token'])) {
// Process secure input
saveComment($cleanComment);
}
?>
💉 SQL Injection Prevention
Parameterized queries ile database security
<?php
// Secure Database Class
class SecureDatabase
{
private $pdo;
private $logger;
public function __construct($dsn, $username, $password)
{
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
PDO::MYSQL_ATTR_FOUND_ROWS => true
];
$this->pdo = new PDO($dsn, $username, $password, $options);
$this->logger = new Logger('database');
}
public function select($table, $conditions = [], $limit = null)
{
$sql = "SELECT * FROM `{$table}`";
$params = [];
if (!empty($conditions)) {
$sql .= " WHERE ";
$whereClause = [];
foreach ($conditions as $field => $value) {
$placeholder = ":{$field}";
$whereClause[] = "`{$field}` = {$placeholder}";
$params[$placeholder] = $value;
}
$sql .= implode(' AND ', $whereClause);
}
if ($limit) {
$sql .= " LIMIT " . intval($limit);
}
try {
$stmt = $this->pdo->prepare($sql);
$stmt->execute($params);
$this->logger->info('Query executed', [
'sql' => $sql,
'params' => array_keys($params)
]);
return $stmt->fetchAll();
} catch (PDOException $e) {
$this->logger->error('Query failed', [
'error' => $e->getMessage(),
'sql' => $sql
]);
throw new DatabaseException('Query execution failed');
}
}
public function insert($table, $data)
{
$fields = array_keys($data);
$placeholders = array_map(function($field) {
return ":{$field}";
}, $fields);
$sql = "INSERT INTO `{$table}`
(`" . implode('`, `', $fields) . "`)
VALUES
(" . implode(', ', $placeholders) . ")";
try {
$stmt = $this->pdo->prepare($sql);
$result = $stmt->execute($data);
if ($result) {
return $this->pdo->lastInsertId();
}
} catch (PDOException $e) {
$this->logger->error('Insert failed', [
'error' => $e->getMessage(),
'table' => $table,
'data' => array_keys($data)
]);
throw new DatabaseException('Insert operation failed');
}
return false;
}
}
// Usage
$db = new SecureDatabase($dsn, $user, $pass);
// Safe query with parameters
$users = $db->select('users', [
'status' => 'active',
'role' => 'admin'
], 10);
?>
🔐 Authentication & Session Security
Secure user authentication ve session management
<?php
// Secure Authentication System
class SecureAuth
{
private const HASH_ALGORITHM = PASSWORD_ARGON2ID;
private const SESSION_LIFETIME = 3600; // 1 hour
public static function hashPassword($password)
{
$options = [
'memory_cost' => 65536, // 64 MB
'time_cost' => 4, // 4 iterations
'threads' => 3, // 3 threads
];
return password_hash($password, self::HASH_ALGORITHM, $options);
}
public static function verifyPassword($password, $hash)
{
return password_verify($password, $hash);
}
public static function createSecureSession($userId, $userData = [])
{
// Regenerate session ID to prevent fixation
session_regenerate_id(true);
$_SESSION['user_id'] = $userId;
$_SESSION['login_time'] = time();
$_SESSION['last_activity'] = time();
$_SESSION['user_agent'] = $_SERVER['HTTP_USER_AGENT'] ?? '';
$_SESSION['ip_address'] = $_SERVER['REMOTE_ADDR'] ?? '';
$_SESSION['session_token'] = bin2hex(random_bytes(32));
// Store additional user data
foreach ($userData as $key => $value) {
$_SESSION["user_{$key}"] = $value;
}
// Set secure session cookie
session_set_cookie_params([
'lifetime' => self::SESSION_LIFETIME,
'path' => '/',
'domain' => $_SERVER['SERVER_NAME'],
'secure' => isset($_SERVER['HTTPS']),
'httponly' => true,
'samesite' => 'Strict'
]);
}
public static function validateSession()
{
if (session_status() !== PHP_SESSION_ACTIVE) {
session_start();
}
// Check if session exists
if (!isset($_SESSION['user_id'])) {
return false;
}
// Check session timeout
if (time() - $_SESSION['last_activity'] > self::SESSION_LIFETIME) {
self::destroySession();
return false;
}
// Validate user agent (basic fingerprinting)
if ($_SESSION['user_agent'] !== ($_SERVER['HTTP_USER_AGENT'] ?? '')) {
self::destroySession();
return false;
}
// Update last activity
$_SESSION['last_activity'] = time();
return true;
}
public static function destroySession()
{
if (session_status() === PHP_SESSION_ACTIVE) {
$_SESSION = [];
session_destroy();
// Delete session cookie
if (isset($_COOKIE[session_name()])) {
setcookie(
session_name(),
'',
time() - 3600,
'/',
$_SERVER['SERVER_NAME'],
isset($_SERVER['HTTPS']),
true
);
}
}
}
public static function requireAuth()
{
if (!self::validateSession()) {
http_response_code(401);
header('Location: /login');
exit('Authentication required');
}
}
}
?>
🔒 File Upload Security
Secure file upload implementation ve validation
<?php
class SecureFileUpload
{
private const ALLOWED_TYPES = [
'image/jpeg' => 'jpg',
'image/png' => 'png',
'image/gif' => 'gif',
'image/webp' => 'webp',
'application/pdf' => 'pdf'
];
private const MAX_FILE_SIZE = 5242880; // 5MB
private const UPLOAD_PATH = '/secure/uploads/';
public static function validateFile($file)
{
$errors = [];
// Check if file was uploaded
if (!isset($file['tmp_name']) || !is_uploaded_file($file['tmp_name'])) {
$errors[] = 'Invalid file upload';
return $errors;
}
// Check file size
if ($file['size'] > self::MAX_FILE_SIZE) {
$errors[] = 'File size exceeds limit';
}
// Validate MIME type
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimeType = finfo_file($finfo, $file['tmp_name']);
finfo_close($finfo);
if (!array_key_exists($mimeType, self::ALLOWED_TYPES)) {
$errors[] = 'Invalid file type';
}
// Validate file extension
$extension = pathinfo($file['name'], PATHINFO_EXTENSION);
if (self::ALLOWED_TYPES[$mimeType] !== strtolower($extension)) {
$errors[] = 'File extension mismatch';
}
// Additional security checks for images
if (strpos($mimeType, 'image/') === 0) {
$imageInfo = getimagesize($file['tmp_name']);
if ($imageInfo === false) {
$errors[] = 'Invalid image file';
}
}
return $errors;
}
public static function secureUpload($file, $userId)
{
$validation = self::validateFile($file);
if (!empty($validation)) {
return ['success' => false, 'errors' => $validation];
}
// Generate secure filename
$extension = pathinfo($file['name'], PATHINFO_EXTENSION);
$filename = hash('sha256', uniqid() . $userId . time()) . '.' . $extension;
// Create user-specific directory
$userDir = self::UPLOAD_PATH . substr(hash('md5', $userId), 0, 2) . '/';
if (!is_dir($userDir)) {
mkdir($userDir, 0755, true);
}
$targetPath = $userDir . $filename;
// Move uploaded file
if (move_uploaded_file($file['tmp_name'], $targetPath)) {
// Set secure permissions
chmod($targetPath, 0644);
// Log successful upload
error_log("Secure file upload: {$targetPath} by user {$userId}");
return [
'success' => true,
'filename' => $filename,
'path' => $targetPath,
'size' => $file['size']
];
}
return ['success' => false, 'errors' => ['Upload failed']];
}
}
?>