Uwierzytelnianie
Uwierzytelnianie w XOOPS
Dział zatytułowany „Uwierzytelnianie w XOOPS”System uwierzytelniania XOOPS zapewnia bezpieczną weryfikację użytkowników, zarządzanie sesją i zaawansowane funkcje bezpieczeństwa, w tym uwierzytelnianie dwuskładnikowe i integrację OAuth. Dokument ten obejmuje przepływy uwierzytelniania, wdrażanie i najlepsze praktyki.
Przepływ uwierzytelniania
Dział zatytułowany „Przepływ uwierzytelniania”Diagram sekwencji logowania
Dział zatytułowany „Diagram sekwencji logowania”sequenceDiagram participant User as User Browser participant Server as XOOPS Server participant DB as Database participant Session as Session Manager participant Cache as Cache/APCu
User->>Server: POST /user.php?op=login note over User, Server: username/email + password
Server->>Server: Validate Input note over Server: Check format, CSRF token
alt Invalid Format Server-->>User: 400 Bad Request else Valid Format Server->>Cache: Check Account Lockout Cache-->>Server: Lockout Status?
alt Account Locked Server-->>User: Account Temporarily Locked else Not Locked Server->>DB: Query User by Username/Email DB-->>Server: User Record
alt User Not Found Server->>Cache: Increment Failed Attempts Server-->>User: Invalid Credentials else User Found Server->>Server: Verify Password Hash note over Server: password_verify()
alt Password Incorrect Server->>Cache: Increment Failed Attempts Server-->>User: Invalid Credentials else Password Correct Server->>Server: Check Account Status alt Account Inactive Server-->>User: Account Inactive else Account Active Server->>Cache: Clear Failed Attempts Server->>Session: Create Session note over Session: Generate token,<br/>store in DB
Server->>DB: Update Last Login DB-->>Server: Updated
alt Remember Me Checked Server->>Server: Generate Persistent Token Server->>User: Set Persistent Cookie else Remember Me Unchecked Server->>User: Set Session Cookie end
Server-->>User: 302 Redirect to Dashboard end end end end endSzczegółowy proces logowania
Dział zatytułowany „Szczegółowy proces logowania”graph TD A["User Submits Login Form"] --> B["CSRF Token Validation"] B --> C{"Token Valid?"} C -->|No| D["Reject Request"] C -->|Yes| E["Validate Input Format"] E --> F{"Format Valid?"} F -->|No| G["Show Validation Errors"] F -->|Yes| H["Check Lockout Status"] H --> I{"Account Locked?"} I -->|Yes| J["Show Lockout Message"] I -->|No| K["Query User Database"] K --> L{"User Exists?"} L -->|No| M["Record Attempt<br/>Show Error"] L -->|Yes| N["Verify Password Hash"] N --> O{"Match?"} O -->|No| M O -->|Yes| P["Check Account Status"] P --> Q{"Active?"} Q -->|No| R["Show Status Error"] Q -->|Yes| S["Clear Failed Attempts"] S --> T["Create Session"] T --> U["Update Last Login"] U --> V{"Remember Me?"} V -->|Yes| W["Create Persistent Token<br/>Set Long-lived Cookie"] V -->|No| X["Set Session Cookie"] W --> Y["Redirect to Dashboard"] X --> YZarządzanie sesją
Dział zatytułowany „Zarządzanie sesją”Konfiguracja sesji
Dział zatytułowany „Konfiguracja sesji”<?php/** * XOOPS Session Configuration * Typically in /include/session.php */
// Session cookie parameters for securitysession_set_cookie_params([ 'lifetime' => 0, // Session cookie (deleted on browser close) 'path' => '/', // Cookie path 'domain' => '', // Cookie domain (empty = current domain) 'secure' => true, // HTTPS only 'httponly' => true, // Not accessible to JavaScript 'samesite' => 'Strict' // CSRF protection]);
// Set session configurationini_set('session.name', 'XOOPSPHPSESSID');ini_set('session.use_strict_mode', 1);ini_set('session.use_only_cookies', 1);ini_set('session.cookie_httponly', 1);ini_set('session.cookie_secure', 1);ini_set('session.gc_maxlifetime', 28800); // 8 hours
// Start sessionsession_start();
// Verify session fixation protectionif (!isset($_SESSION['initiated'])) { session_regenerate_id(); $_SESSION['initiated'] = true;}Implementacja obsługi sesji
Dział zatytułowany „Implementacja obsługi sesji”<?php/** * XOOPS Session Handler */class XoopsSessionHandler{ private $sessionTimeout = 28800; // 8 hours private $sessionTokenLength = 32; private $db;
public function __construct() { $this->db = XoopsDatabaseFactory::getDatabaseConnection(); }
/** * Create new session * * @param XoopsUser $user User object * @param bool $rememberMe Persistent login flag * @return bool Success status */ public function createSession(XoopsUser $user, bool $rememberMe = false): bool { try { // Generate secure token $token = bin2hex(random_bytes($this->sessionTokenLength));
// Store in session $_SESSION['xoopsUserId'] = $user->getVar('uid'); $_SESSION['xoopsUserName'] = $user->getVar('uname'); $_SESSION['xoopsSessionToken'] = $token; $_SESSION['xoopsSessionCreated'] = time(); $_SESSION['xoopsSessionIP'] = $this->getClientIP(); $_SESSION['xoopsSessionUA'] = $_SERVER['HTTP_USER_AGENT'] ?? '';
// Store token in database $this->storeSessionToken( $user->getVar('uid'), $token, $this->sessionTimeout );
// Handle persistent login if ($rememberMe) { $this->createPersistentLogin($user->getVar('uid')); }
return true; } catch (Exception $e) { error_log('Session creation failed: ' . $e->getMessage()); return false; } }
/** * Validate current session * * @return bool Session valid */ public function validateSession(): bool { // Check session variables exist if (!isset($_SESSION['xoopsUserId'], $_SESSION['xoopsSessionToken'])) { return false; }
// Verify session timeout $created = $_SESSION['xoopsSessionCreated'] ?? 0; if (time() - $created > $this->sessionTimeout) { $this->destroySession(); return false; }
// Verify IP address consistency if ($this->getClientIP() !== ($_SESSION['xoopsSessionIP'] ?? '')) { error_log('Session IP mismatch - possible session hijacking'); $this->destroySession(); return false; }
// Verify User Agent consistency $currentUA = $_SERVER['HTTP_USER_AGENT'] ?? ''; if ($currentUA !== ($_SESSION['xoopsSessionUA'] ?? '')) { error_log('Session UA mismatch - possible session hijacking'); $this->destroySession(); return false; }
// Verify token in database if (!$this->verifySessionToken( $_SESSION['xoopsUserId'], $_SESSION['xoopsSessionToken'] )) { return false; }
return true; }
/** * Destroy session */ public function destroySession(): void { if (isset($_SESSION['xoopsUserId'])) { $this->deleteSessionToken( $_SESSION['xoopsUserId'], $_SESSION['xoopsSessionToken'] ?? '' ); }
// Clear session data $_SESSION = [];
// Delete session cookie if (ini_get('session.use_cookies')) { $params = session_get_cookie_params(); setcookie( session_name(), '', time() - 42000, $params['path'], $params['domain'], $params['secure'], $params['httponly'] ); }
session_destroy(); }
/** * Store session token in database * * @param int $uid User ID * @param string $token Session token * @param int $lifetime Token lifetime in seconds */ private function storeSessionToken(int $uid, string $token, int $lifetime): void { $tokenHash = hash('sha256', $token); $expiresAt = time() + $lifetime;
$this->db->query( "INSERT INTO xoops_sessions (uid, token, ip, user_agent, expires_at) VALUES (?, ?, ?, ?, ?)", array($uid, $tokenHash, $this->getClientIP(), $_SERVER['HTTP_USER_AGENT'] ?? '', $expiresAt) ); }
/** * Verify session token * * @param int $uid User ID * @param string $token Session token * @return bool Valid token */ private function verifySessionToken(int $uid, string $token): bool { $tokenHash = hash('sha256', $token);
$result = $this->db->query( "SELECT id FROM xoops_sessions WHERE uid = ? AND token = ? AND expires_at > ?", array($uid, $tokenHash, time()) );
return $this->db->getRowCount($result) > 0; }
/** * Delete session token * * @param int $uid User ID * @param string $token Session token (optional) */ private function deleteSessionToken(int $uid, string $token = ''): void { if (!empty($token)) { $tokenHash = hash('sha256', $token); $this->db->query( "DELETE FROM xoops_sessions WHERE uid = ? AND token = ?", array($uid, $tokenHash) ); } else { // Delete all sessions for user $this->db->query( "DELETE FROM xoops_sessions WHERE uid = ?", array($uid) ); } }
/** * Get client IP address * * @return string IP address */ private function getClientIP(): string { if (!empty($_SERVER['HTTP_CF_CONNECTING_IP'])) { return $_SERVER['HTTP_CF_CONNECTING_IP']; } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { $ips = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']); return trim($ips[0]); } elseif (!empty($_SERVER['HTTP_X_FORWARDED'])) { return $_SERVER['HTTP_X_FORWARDED']; } elseif (!empty($_SERVER['HTTP_FORWARDED_FOR'])) { return $_SERVER['HTTP_FORWARDED_FOR']; } elseif (!empty($_SERVER['HTTP_FORWARDED'])) { return $_SERVER['HTTP_FORWARDED']; } elseif (!empty($_SERVER['REMOTE_ADDR'])) { return $_SERVER['REMOTE_ADDR']; } return ''; }}Funkcjonalność Zapamiętaj mnie
Dział zatytułowany „Funkcjonalność Zapamiętaj mnie”Implementacja logowania trwałego
Dział zatytułowany „Implementacja logowania trwałego”<?php/** * Remember Me (Persistent Login) Handler */class PersistentLoginHandler{ private $cookieName = 'xoops_persistent_login'; private $cookieLifetime = 1209600; // 14 days private $db;
public function __construct() { $this->db = XoopsDatabaseFactory::getDatabaseConnection(); }
/** * Create persistent login token * * @param int $uid User ID * @return string Cookie token */ public function createPersistentToken(int $uid): string { // Generate random token $token = bin2hex(random_bytes(32)); $tokenHash = hash('sha256', $token);
// Store in database $expiresAt = time() + $this->cookieLifetime;
$this->db->query( "INSERT INTO xoops_persistent_tokens (uid, token_hash, expires_at) VALUES (?, ?, ?)", array($uid, $tokenHash, $expiresAt) );
// Set cookie setcookie( $this->cookieName, $token, time() + $this->cookieLifetime, '/', '', true, // HTTPS only true // HttpOnly );
return $token; }
/** * Validate persistent login cookie * * @return XoopsUser|false Authenticated user or false */ public function validatePersistentToken() { if (!isset($_COOKIE[$this->cookieName])) { return false; }
$token = $_COOKIE[$this->cookieName]; $tokenHash = hash('sha256', $token);
// Query database $result = $this->db->query( "SELECT uid FROM xoops_persistent_tokens WHERE token_hash = ? AND expires_at > ?", array($tokenHash, time()) );
if ($this->db->getRowCount($result) === 0) { return false; }
$row = $this->db->fetchArray($result); $uid = $row['uid'];
// Get user $userHandler = xoops_getHandler('user'); $user = $userHandler->getUser($uid);
if (!$user) { return false; }
// Refresh token (sliding window) $this->refreshPersistentToken($uid, $token);
return $user; }
/** * Refresh persistent token (sliding window) * * @param int $uid User ID * @param string $oldToken Old token */ private function refreshPersistentToken(int $uid, string $oldToken): void { // Delete old token $oldTokenHash = hash('sha256', $oldToken); $this->db->query( "DELETE FROM xoops_persistent_tokens WHERE token_hash = ?", array($oldTokenHash) );
// Create new token $this->createPersistentToken($uid); }
/** * Clear persistent login * * @param int $uid User ID */ public function clearPersistentLogin(int $uid): void { // Delete all tokens for user $this->db->query( "DELETE FROM xoops_persistent_tokens WHERE uid = ?", array($uid) );
// Delete cookie setcookie( $this->cookieName, '', time() - 3600, '/', '', true, true ); }}Haszowanie hasła
Dział zatytułowany „Haszowanie hasła”Bezpieczna obsługa hasła
Dział zatytułowany „Bezpieczna obsługa hasła”<?php/** * Password hashing and verification */class PasswordManager{ /** * Hash password using bcrypt * * @param string $password Plain text password * @return string Hashed password */ public static function hash(string $password): string { return password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]); }
/** * Verify password against hash * * @param string $password Plain text password * @param string $hash Password hash * @return bool Match status */ public static function verify(string $password, string $hash): bool { return password_verify($password, $hash); }
/** * Check if password needs rehashing (stronger algorithm available) * * @param string $hash Password hash * @return bool Needs rehashing */ public static function needsRehash(string $hash): bool { return password_needs_rehash($hash, PASSWORD_BCRYPT, ['cost' => 12]); }
/** * Validate password strength * * @param string $password Password to validate * @return array Validation result */ public static function validateStrength(string $password): array { $errors = [];
// Minimum length if (strlen($password) < 8) { $errors[] = 'Password must be at least 8 characters'; }
// Require uppercase if (!preg_match('/[A-Z]/', $password)) { $errors[] = 'Password must contain uppercase letter'; }
// Require lowercase if (!preg_match('/[a-z]/', $password)) { $errors[] = 'Password must contain lowercase letter'; }
// Require number if (!preg_match('/[0-9]/', $password)) { $errors[] = 'Password must contain number'; }
// Require special character if (!preg_match('/[!@#$%^&*(),.?":{}|<>]/', $password)) { $errors[] = 'Password must contain special character'; }
return [ 'valid' => empty($errors), 'errors' => $errors ]; }
/** * Generate random password * * @param int $length Password length * @return string Random password */ public static function generateRandom(int $length = 12): string { $charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*'; $password = '';
for ($i = 0; $i < $length; $i++) { $password .= $charset[random_int(0, strlen($charset) - 1)]; }
return $password; }}Uwierzytelnianie dwuskładnikowe
Dział zatytułowany „Uwierzytelnianie dwuskładnikowe”Przegląd implementacji 2FA
Dział zatytułowany „Przegląd implementacji 2FA”<?php/** * Two-Factor Authentication Handler */class TwoFactorAuthHandler{ private $db; private $qrCodeGenerator; private $totpTimeout = 30;
public function __construct() { $this->db = XoopsDatabaseFactory::getDatabaseConnection(); }
/** * Enable 2FA for user * * @param int $uid User ID * @return array Setup data with secret and QR code */ public function enable2FA(int $uid): array { // Generate secret $secret = $this->generateSecret();
// Generate QR code $qrCode = $this->generateQRCode($uid, $secret);
// Store secret temporarily (not yet confirmed) $this->storeTempSecret($uid, $secret);
return [ 'secret' => $secret, 'qrCode' => $qrCode ]; }
/** * Confirm 2FA setup with TOTP code * * @param int $uid User ID * @param string $code TOTP code * @return bool Confirmation success */ public function confirm2FA(int $uid, string $code): bool { // Get temporary secret $tempSecret = $this->getTempSecret($uid); if (!$tempSecret) { return false; }
// Verify TOTP code if (!$this->verifyTOTP($code, $tempSecret)) { return false; }
// Make 2FA active $this->db->query( "UPDATE xoops_user_2fa SET status = 'active' WHERE uid = ?", array($uid) );
return true; }
/** * Verify TOTP code during login * * @param int $uid User ID * @param string $code TOTP code * @return bool Valid code */ public function verifyTOTP(int $uid, string $code): bool { // Get active secret $result = $this->db->query( "SELECT secret FROM xoops_user_2fa WHERE uid = ? AND status = 'active'", array($uid) );
if ($this->db->getRowCount($result) === 0) { return false; }
$row = $this->db->fetchArray($result); $secret = $row['secret'];
// Verify TOTP return $this->verifyTOTPCode($code, $secret); }
/** * Verify TOTP code against secret * * @param string $code TOTP code * @param string $secret Shared secret * @return bool Valid */ private function verifyTOTPCode(string $code, string $secret): bool { // Allow for time drift (current, -1, +1) $timeSlice = floor(time() / 30);
for ($i = -1; $i <= 1; $i++) { $timestamp = ($timeSlice + $i) * 30; $generated = $this->generateTOTP($secret, $timestamp);
if ($generated === $code) { return true; } }
return false; }
/** * Generate TOTP code * * @param string $secret Shared secret * @param int $timestamp Unix timestamp * @return string TOTP code */ private function generateTOTP(string $secret, int $timestamp): string { $secretBinary = $this->base32Decode($secret); $time = pack('N', $timestamp); $hmac = hash_hmac('SHA1', $time, $secretBinary, true);
$offset = ord($hmac[strlen($hmac) - 1]) & 0x0F; $code = (ord($hmac[$offset]) & 0x7F) << 24 | (ord($hmac[$offset + 1]) & 0xFF) << 16 | (ord($hmac[$offset + 2]) & 0xFF) << 8 | (ord($hmac[$offset + 3]) & 0xFF);
return str_pad($code % 1000000, 6, '0', STR_PAD_LEFT); }
/** * Generate random secret for 2FA * * @return string Base32-encoded secret */ private function generateSecret(): string { $bytes = random_bytes(20); return $this->base32Encode($bytes); }
/** * Base32 encode * * @param string $data Data to encode * @return string Base32-encoded string */ private function base32Encode(string $data): string { $alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'; $encoded = ''; $len = strlen($data); $bits = 0; $value = 0;
for ($i = 0; $i < $len; $i++) { $value = ($value << 8) | ord($data[$i]); $bits += 8;
while ($bits >= 5) { $bits -= 5; $encoded .= $alphabet[($value >> $bits) & 31]; } }
if ($bits > 0) { $encoded .= $alphabet[($value << (5 - $bits)) & 31]; }
return $encoded; }
/** * Base32 decode * * @param string $encoded Base32-encoded string * @return string Decoded binary data */ private function base32Decode(string $encoded): string { $alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'; $decoded = ''; $len = strlen($encoded); $bits = 0; $value = 0;
for ($i = 0; $i < $len; $i++) { $pos = strpos($alphabet, $encoded[$i]); if ($pos === false) continue;
$value = ($value << 5) | $pos; $bits += 5;
if ($bits >= 8) { $bits -= 8; $decoded .= chr(($value >> $bits) & 255); } }
return $decoded; }
/** * Generate QR code for 2FA setup * * @param int $uid User ID * @param string $secret TOTP secret * @return string QR code data URL */ private function generateQRCode(int $uid, string $secret): string { global $xoopsConfig;
$user = xoops_getHandler('user')->getUser($uid); $label = $user->getVar('uname') . '@' . $_SERVER['HTTP_HOST']; $otpauthUrl = "otpauth://totp/" . urlencode($label) . "?secret=" . urlencode($secret) . "&issuer=" . urlencode($xoopsConfig['sitename']);
// Generate QR code using external library // This example uses a placeholder - use actual QR code library return "data:image/svg+xml,%3Csvg%3E...%3C/svg%3E"; }}Integracja OAuth
Dział zatytułowany „Integracja OAuth”Przepływ logowania OAuth2
Dział zatytułowany „Przepływ logowania OAuth2”<?php/** * OAuth2 Integration */class OAuth2Handler{ private $providers = [ 'google' => [ 'client_id' => '', 'client_secret' => '', 'auth_url' => 'https://accounts.google.com/o/oauth2/v2/auth', 'token_url' => 'https://www.googleapis.com/oauth2/v4/token', 'userinfo_url' => 'https://www.googleapis.com/oauth2/v1/userinfo' ], 'github' => [ 'client_id' => '', 'client_secret' => '', 'auth_url' => 'https://github.com/login/oauth/authorize', 'token_url' => 'https://github.com/login/oauth/access_token', 'userinfo_url' => 'https://api.github.com/user' ] ];
private $db; private $userHandler;
public function __construct() { $this->db = XoopsDatabaseFactory::getDatabaseConnection(); $this->userHandler = xoops_getHandler('user'); }
/** * Get OAuth authorization URL * * @param string $provider OAuth provider * @return string Authorization URL */ public function getAuthorizationUrl(string $provider): string { if (!isset($this->providers[$provider])) { throw new Exception('Unknown provider: ' . $provider); }
$config = $this->providers[$provider]; $state = bin2hex(random_bytes(16));
// Store state for verification $_SESSION['oauth_state'] = $state; $_SESSION['oauth_provider'] = $provider;
$params = [ 'client_id' => $config['client_id'], 'redirect_uri' => $this->getCallbackUrl($provider), 'response_type' => 'code', 'scope' => 'openid email profile', 'state' => $state ];
return $config['auth_url'] . '?' . http_build_query($params); }
/** * Handle OAuth callback * * @param string $provider OAuth provider * @param string $code Authorization code * @return XoopsUser|false Authenticated user or false */ public function handleCallback(string $provider, string $code) { // Verify state if ($_SESSION['oauth_state'] !== ($_GET['state'] ?? '')) { throw new Exception('Invalid state parameter'); }
if (!isset($this->providers[$provider])) { throw new Exception('Unknown provider: ' . $provider); }
$config = $this->providers[$provider];
// Exchange code for token $token = $this->exchangeCodeForToken( $provider, $code, $config );
if (!$token) { return false; }
// Get user info $userInfo = $this->getUserInfo( $provider, $token, $config );
if (!$userInfo) { return false; }
// Find or create user return $this->findOrCreateUser($provider, $userInfo); }
/** * Exchange authorization code for access token * * @param string $provider Provider name * @param string $code Authorization code * @param array $config Provider config * @return array|false Token data */ private function exchangeCodeForToken( string $provider, string $code, array $config ) { $params = [ 'code' => $code, 'client_id' => $config['client_id'], 'client_secret' => $config['client_secret'], 'redirect_uri' => $this->getCallbackUrl($provider), 'grant_type' => 'authorization_code' ];
$ch = curl_init($config['token_url']); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params)); curl_setopt($ch, CURLOPT_HEADER, ['Accept: application/json']);
$response = curl_exec($ch); curl_close($ch);
return json_decode($response, true); }
/** * Get user info from provider * * @param string $provider Provider name * @param array $token Access token * @param array $config Provider config * @return array|false User info */ private function getUserInfo( string $provider, array $token, array $config ) { $ch = curl_init($config['userinfo_url']); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Authorization: Bearer ' . $token['access_token'], 'Accept: application/json' ]);
$response = curl_exec($ch); curl_close($ch);
return json_decode($response, true); }
/** * Find or create user from OAuth info * * @param string $provider Provider name * @param array $userInfo User info from provider * @return XoopsUser|false */ private function findOrCreateUser(string $provider, array $userInfo) { // Check if user already linked $result = $this->db->query( "SELECT uid FROM xoops_oauth_users WHERE provider = ? AND provider_id = ?", array($provider, $userInfo['id']) );
if ($this->db->getRowCount($result) > 0) { $row = $this->db->fetchArray($result); return $this->userHandler->getUser($row['uid']); }
// Try to find user by email if (isset($userInfo['email'])) { $user = $this->userHandler->getUserByEmail($userInfo['email']); if ($user) { // Link existing user to OAuth account $this->linkOAuthAccount( $user->getVar('uid'), $provider, $userInfo['id'] ); return $user; } }
// Create new user $newUser = $this->createOAuthUser($provider, $userInfo); return $newUser; }
/** * Create new user from OAuth info * * @param string $provider Provider name * @param array $userInfo User info * @return XoopsUser|false */ private function createOAuthUser(string $provider, array $userInfo) { // Generate unique username from provider data $baseUsername = preg_replace('/[^a-zA-Z0-9_-]/', '', $userInfo['name'] ?? ''); $username = $baseUsername ?: 'oauth_' . substr($userInfo['id'], 0, 8);
// Make unique $counter = 1; $originalUsername = $username; while ($this->userHandler->getUserByName($username)) { $username = $originalUsername . $counter; $counter++; }
// Create user $user = $this->userHandler->create(); $user->setVar('uname', $username); $user->setVar('email', $userInfo['email'] ?? ''); $user->setVar('pass', password_hash(bin2hex(random_bytes(32)), PASSWORD_BCRYPT)); $user->setVar('user_regdate', time());
if (!$this->userHandler->insertUser($user)) { return false; }
// Link OAuth account $this->linkOAuthAccount( $user->getVar('uid'), $provider, $userInfo['id'] );
return $user; }
/** * Link OAuth account to user * * @param int $uid User ID * @param string $provider Provider name * @param string $providerId Provider user ID */ private function linkOAuthAccount(int $uid, string $provider, string $providerId): void { $this->db->query( "INSERT INTO xoops_oauth_users (uid, provider, provider_id) VALUES (?, ?, ?)", array($uid, $provider, $providerId) ); }
/** * Get OAuth callback URL * * @param string $provider Provider name * @return string Callback URL */ private function getCallbackUrl(string $provider): string { global $xoopsConfig; return $xoopsConfig['siteurl'] . '/user.php?op=oauth_callback&provider=' . $provider; }}Najlepsze praktyki bezpieczeństwa
Dział zatytułowany „Najlepsze praktyki bezpieczeństwa”Lista kontrolna bezpieczeństwa uwierzytelniania
Dział zatytułowany „Lista kontrolna bezpieczeństwa uwierzytelniania”<?php/** * Security best practices */
// 1. HTTPS enforcedif (empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] === 'off') { die('HTTPS required for authentication');}
// 2. CSRF protectionfunction generateCSRFToken() { if (empty($_SESSION['csrf_token'])) { $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); } return $_SESSION['csrf_token'];}
function verifyCSRFToken($token) { return hash_equals($_SESSION['csrf_token'] ?? '', $token);}
// 3. Rate limiting on login attemptsclass RateLimiter { public static function checkLoginLimit($identifier) { $key = 'login_attempt_' . md5($identifier); $attempts = apcu_fetch($key) ?: 0;
if ($attempts > 5) { throw new Exception('Too many login attempts'); }
apcu_store($key, $attempts + 1, 900); // 15 minute window }}
// 4. Secure password requirements$passwordValidation = PasswordManager::validateStrength($password);if (!$passwordValidation['valid']) { throw new Exception(implode(', ', $passwordValidation['errors']));}
// 5. Secure session cookieheader('Strict-Transport-Security: max-age=31536000; includeSubDomains');header('X-Content-Type-Options: nosniff');header('X-Frame-Options: DENY');header('X-XSS-Protection: 1; mode=block');header('Content-Security-Policy: default-src \'self\'');Powiązane linki
Dział zatytułowany „Powiązane linki”- User Management.md
- Group System.md
- Permission System.md
- ../../Security/Security-Guidelines.md
Znaczniki
Dział zatytułowany „Znaczniki”#authentication #login #sessions #security #password-hashing #2fa #oauth #session-management