Nguyên tắc bảo mật
Tổng quan
Phần tiêu đề “Tổng quan”Tài liệu này phác thảo các phương pháp bảo mật tốt nhất để phát triển XOOPS, bao gồm xác thực đầu vào, mã hóa đầu ra, xác thực, ủy quyền và bảo vệ chống lại các lỗ hổng web phổ biến.
Nguyên tắc bảo mật
Phần tiêu đề “Nguyên tắc bảo mật”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] endXác thực đầu vào
Phần tiêu đề “Xác thực đầu vào”Yêu cầu vệ sinh
Phần tiêu đề “Yêu cầu vệ sinh”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');Quy tắc xác thực
Phần tiêu đề “Quy tắc xác thực”// 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');}Phòng chống tiêm SQL
Phần tiêu đề “Phòng chống tiêm SQL”Sử dụng truy vấn được tham số hóa
Phần tiêu đề “Sử dụng truy vấn được tham số hóa”// 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;Sử dụng Đối tượng Tiêu chí
Phần tiêu đề “Sử dụng Đối tượng Tiêu chí”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);Phòng chống XSS
Phần tiêu đề “Phòng chống XSS”Mã hóa đầu ra
Phần tiêu đề “Mã hóa đầu ra”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);Chính sách bảo mật nội dung
Phần tiêu đề “Chính sách bảo mật nội dung”// Set CSP headersheader("Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'");Bảo vệ CSRF
Phần tiêu đề “Bảo vệ CSRF”Triển khai mã thông báo
Phần tiêu đề “Triển khai mã thông báo”// 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');}Sử dụng XoopsForm
Phần tiêu đề “Sử dụng XoopsForm”// Automatically adds CSRF token$form = new XoopsThemeForm('Edit Article', 'articleform', 'save.php');$form->addElement(new XoopsFormHiddenToken());Xác thực
Phần tiêu đề “Xác thực”Xử lý mật khẩu
Phần tiêu đề “Xử lý mật khẩu”// 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}Bảo mật phiên
Phần tiêu đề “Bảo mật phiên”// 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');Ủy quyền
Phần tiêu đề “Ủy quyền”Kiểm tra quyền
Phần tiêu đề “Kiểm tra quyền”// 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');}Quyền truy cập dựa trên vai trò
Phần tiêu đề “Quyền truy cập dựa trên vai trò”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'); }}Bảo mật tải lên tệp
Phần tiêu đề “Bảo mật tải lên tệp”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; }}Ghi nhật ký kiểm tra
Phần tiêu đề “Ghi nhật ký kiểm tra”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); }}Tiêu đề bảo mật
Phần tiêu đề “Tiêu đề bảo mật”// 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');}Giới hạn tỷ lệ
Phần tiêu đề “Giới hạn tỷ lệ”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');}Danh sách kiểm tra bảo mật
Phần tiêu đề “Danh sách kiểm tra bảo mật”- [] Tất cả đầu vào của người dùng được xác thực và vệ sinh
- [] Truy vấn được tham số hóa cho tất cả các hoạt động của cơ sở dữ liệu
- [] Mã hóa đầu ra cho tất cả nội dung do người dùng tạo
- Mã thông báo CSRF trên tất cả các hình thức thay đổi trạng thái
- Băm mật khẩu an toàn (Argon2id)
- [] Đã định cấu hình bảo mật phiên
- [] Xác thực tải lên tệp
- [] Đã đặt tiêu đề bảo mật
- Đã triển khai giới hạn tỷ lệ
- [] Đã bật ghi nhật ký kiểm tra
- Thông báo lỗi không rò rỉ thông tin nhạy cảm
Tài liệu liên quan
Phần tiêu đề “Tài liệu liên quan”- Hệ thống xác thực
- Hệ thống cấp phép
- Xác thực đầu vào