Οδηγίες ασφαλείας
Επισκόπηση
Ενότητα με τίτλο «Επισκόπηση»Αυτό το έγγραφο περιγράφει τις βέλτιστες πρακτικές ασφάλειας για την ανάπτυξη του XOOPS, καλύπτοντας την επικύρωση εισόδου, την κωδικοποίηση εξόδου, τον έλεγχο ταυτότητας, την εξουσιοδότηση και την προστασία από κοινές ευπάθειες ιστού.
Αρχές ασφάλειας
Ενότητα με τίτλο «Αρχές ασφάλειας»flowchart TB subgraph "Defense in Depth" A[Input Validation] --> B[Authentication] B --> C[Authorization] C --> D[Data Sanitization] D --> E[Output Encoding] E --> F[Audit Logging] endΕπικύρωση εισόδου
Ενότητα με τίτλο «Επικύρωση εισόδου»# Ζητήστε απολύμανση
Ενότητα με τίτλο «# Ζητήστε απολύμανση»use Xoops\Core\Request;
// Always use typed getters$id = Request::getInt('id', 0, 'GET');$name = Request::getString('name', '', 'POST');$email = Request::getEmail('email', '', 'POST');$url = Request::getUrl('website', '', 'POST');
// Never use raw $_GET/$_POST/$_REQUEST// Bad: $id = $_GET['id'];// Good: $id = Request::getInt('id', 0, 'GET');# Κανόνες επικύρωσης
Ενότητα με τίτλο «# Κανόνες επικύρωσης»// Validate before useif ($id <= 0) { throw new InvalidArgumentException('Invalid ID');}
if (!preg_match('/^[a-zA-Z0-9_]{3,50}$/', $username)) { throw new InvalidArgumentException('Invalid username format');}
// Use whitelist validation for enums$allowedStatuses = ['draft', 'published', 'archived'];if (!in_array($status, $allowedStatuses, true)) { throw new InvalidArgumentException('Invalid status');}SQL Πρόληψη ένεσης
Ενότητα με τίτλο «SQL Πρόληψη ένεσης»# Χρησιμοποιήστε παραμετροποιημένα ερωτήματα
Ενότητα με τίτλο «# Χρησιμοποιήστε παραμετροποιημένα ερωτήματα»// GOOD: Parameterized query$sql = "SELECT * FROM {$xoopsDB->prefix('users')} WHERE uid = ?";$result = $xoopsDB->query($sql, [$userId]);
// BAD: String concatenation (vulnerable!)// $sql = "SELECT * FROM users WHERE uid = " . $userId;# Χρήση αντικειμένων κριτηρίων
Ενότητα με τίτλο «# Χρήση αντικειμένων κριτηρίων»use Criteria;use CriteriaCompo;
$criteria = new CriteriaCompo();$criteria->add(new Criteria('status', 'published'));$criteria->add(new Criteria('uid', $userId, '='));$criteria->add(new Criteria('created', time() - 86400, '>'));
$articles = $articleHandler->getObjects($criteria);XSS Πρόληψη
Ενότητα με τίτλο «XSS Πρόληψη»# Κωδικοποίηση εξόδου
Ενότητα με τίτλο «# Κωδικοποίηση εξόδου»use Xoops\Core\Text\Sanitizer;
// HTML context$safeName = htmlspecialchars($userName, ENT_QUOTES, 'UTF-8');
// In templates (auto-escaped){$userName|escape}
// For rich content$sanitizer = Sanitizer::getInstance();$safeContent = $sanitizer->sanitizeForDisplay($content);# Πολιτική ασφάλειας περιεχομένου
Ενότητα με τίτλο «# Πολιτική ασφάλειας περιεχομένου»// Set CSP headersheader("Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'");CSRF Προστασία
Ενότητα με τίτλο «CSRF Προστασία»# Εφαρμογή Token
Ενότητα με τίτλο «# Εφαρμογή Token»// Generate tokenuse Xoops\Core\Security;
$token = Security::createToken();
// In formecho '<input type="hidden" name="XOOPS_TOKEN_REQUEST" value="' . $token . '">';
// Verify on submissionif (!Security::checkToken()) { die('Security token mismatch');}# Χρήση XoopsForm
Ενότητα με τίτλο «# Χρήση XoopsForm»// Automatically adds CSRF token$form = new XoopsThemeForm('Edit Article', 'articleform', 'save.php');$form->addElement(new XoopsFormHiddenToken());Έλεγχος ταυτότητας
Ενότητα με τίτλο «Έλεγχος ταυτότητας»# Χειρισμός κωδικού πρόσβασης
Ενότητα με τίτλο «# Χειρισμός κωδικού πρόσβασης»// Hash passwords (PHP 5.5+)$hashedPassword = password_hash($plainPassword, PASSWORD_ARGON2ID);
// Verify passwordsif (password_verify($plainPassword, $storedHash)) { // Password correct}
// Check if rehash neededif (password_needs_rehash($storedHash, PASSWORD_ARGON2ID)) { $newHash = password_hash($plainPassword, PASSWORD_ARGON2ID); // Update stored hash}# Ασφάλεια συνεδρίας
Ενότητα με τίτλο «# Ασφάλεια συνεδρίας»// Regenerate session ID after loginsession_regenerate_id(true);
// Set secure session cookie optionsini_set('session.cookie_httponly', 1);ini_set('session.cookie_secure', 1);ini_set('session.cookie_samesite', 'Lax');Εξουσιοδότηση
Ενότητα με τίτλο «Εξουσιοδότηση»# Έλεγχοι άδειας
Ενότητα με τίτλο «# Έλεγχοι άδειας»// Check module adminif (!$xoopsUser || !$xoopsUser->isAdmin($xoopsModule->mid())) { redirect_header('index.php', 3, 'Access denied');}
// Check group permissions$grouppermHandler = xoops_getHandler('groupperm');$groups = $xoopsUser ? $xoopsUser->getGroups() : [XOOPS_GROUP_ANONYMOUS];
if (!$grouppermHandler->checkRight('view_item', $itemId, $groups, $moduleId)) { throw new AccessDeniedException('Permission denied');}# Πρόσβαση βάσει ρόλων
Ενότητα με τίτλο «# Πρόσβαση βάσει ρόλων»class PermissionChecker{ public function canEdit(Article $article, ?XoopsUser $user): bool { if (!$user) { return false; }
// Admin can edit anything if ($user->isAdmin()) { return true; }
// Author can edit their own if ($article->getAuthorId() === $user->uid()) { return true; }
// Check editor permission return $this->hasPermission($user, 'article_edit'); }}Ασφάλεια μεταφόρτωσης αρχείων
Ενότητα με τίτλο «Ασφάλεια μεταφόρτωσης αρχείων»class SecureUploader{ private array $allowedMimeTypes = [ 'image/jpeg', 'image/png', 'image/gif' ];
private array $allowedExtensions = ['jpg', 'jpeg', 'png', 'gif'];
public function validate(array $file): bool { // Check file size if ($file['size'] > 2 * 1024 * 1024) { throw new FileTooLargeException(); }
// Verify MIME type $finfo = new finfo(FILEINFO_MIME_TYPE); $mimeType = $finfo->file($file['tmp_name']);
if (!in_array($mimeType, $this->allowedMimeTypes, true)) { throw new InvalidFileTypeException(); }
// Check extension $extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION)); if (!in_array($extension, $this->allowedExtensions, true)) { throw new InvalidFileTypeException(); }
// Generate safe filename return true; }
public function generateSafeFilename(string $original): string { $extension = strtolower(pathinfo($original, PATHINFO_EXTENSION)); return bin2hex(random_bytes(16)) . '.' . $extension; }}Καταγραφή ελέγχου
Ενότητα με τίτλο «Καταγραφή ελέγχου»class SecurityLogger{ public function logAuthAttempt(string $username, bool $success, string $ip): void { $data = [ 'username' => $username, 'success' => $success, 'ip' => $ip, 'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? '', 'timestamp' => time() ];
// Log to database or file $this->log('auth', $data); }
public function logSensitiveAction(int $userId, string $action, array $context): void { $data = [ 'user_id' => $userId, 'action' => $action, 'context' => json_encode($context), 'ip' => $_SERVER['REMOTE_ADDR'], 'timestamp' => time() ];
$this->log('audit', $data); }}Κεφαλίδες ασφαλείας
Ενότητα με τίτλο «Κεφαλίδες ασφαλείας»// Recommended security headersheader('X-Content-Type-Options: nosniff');header('X-Frame-Options: SAMEORIGIN');header('X-XSS-Protection: 1; mode=block');header('Referrer-Policy: strict-origin-when-cross-origin');header('Permissions-Policy: geolocation=(), microphone=(), camera=()');
// HSTS (only for HTTPS sites)if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') { header('Strict-Transport-Security: max-age=31536000; includeSubDomains');}Περιορισμός ποσοστού
Ενότητα με τίτλο «Περιορισμός ποσοστού»class RateLimiter{ public function check(string $key, int $maxAttempts, int $windowSeconds): bool { $cacheKey = 'rate_limit:' . $key; $attempts = (int) $this->cache->get($cacheKey, 0);
if ($attempts >= $maxAttempts) { return false; // Rate limited }
$this->cache->increment($cacheKey, 1, $windowSeconds); return true; }}
// Usage$limiter = new RateLimiter();if (!$limiter->check('login:' . $ip, 5, 300)) { throw new TooManyRequestsException('Too many login attempts');}Λίστα ελέγχου ασφαλείας
Ενότητα με τίτλο «Λίστα ελέγχου ασφαλείας»- Όλες οι εισροές χρήστη έχουν επικυρωθεί και απολυμανθεί
- Παραμετροποιημένα ερωτήματα για όλες τις λειτουργίες της βάσης δεδομένων
- Κωδικοποίηση εξόδου για όλο το περιεχόμενο που δημιουργείται από τον χρήστη
- CSRF διακριτικά σε όλες τις φόρμες που αλλάζουν κατάσταση
- Ασφαλής κατακερματισμός κωδικού πρόσβασης (Argon2id)
- Διαμορφώθηκε η ασφάλεια περιόδου λειτουργίας
- Επικύρωση μεταφόρτωσης αρχείου
- Σύνολο κεφαλίδων ασφαλείας
- Εφαρμόστηκε ο περιορισμός ποσοστού
- Η καταγραφή ελέγχου είναι ενεργοποιημένη
- Τα μηνύματα σφάλματος δεν διαρρέουν ευαίσθητες πληροφορίες
Σχετική τεκμηρίωση
Ενότητα με τίτλο «Σχετική τεκμηρίωση»- Σύστημα ελέγχου ταυτότητας
- Σύστημα αδειών
- Επικύρωση εισόδου