Ga naar inhoud

ADR-004 - Architectuur van beveiligingssysteem

ADR-004: Architectuur van beveiligingssysteem

Section titled “ADR-004: Architectuur van beveiligingssysteem”

Uitgebreide beveiligingsarchitectuur voor XOOPS CMS ter bescherming tegen moderne bedreigingen.


Geaccepteerd - Kernbeveiligingslaag sinds XOOPS 2.5


XOOPS heeft een robuust beveiligingssysteem nodig dat:

  1. Beschermt tegen veelvoorkomende kwetsbaarheden op internet (OWASP Top 10)
  2. Biedt gedetailleerd toestemmingscontrole voor alle modules
  3. Maakt veilige gebruikersauthenticatie mogelijk met moderne standaarden
  4. Voorkomt datalekken en ongeautoriseerde toegang
  5. Ondersteunt toegangscontrole op meerdere niveaus (beheerder, moderator, gebruiker, gast)
  6. Integreert naadloos met alle modules

Moderne webaanvallen omvatten:

  • SQL Injectie - Schadelijke SQL in gebruikersinvoer
  • XSS (Cross-Site Scripting) - JavaScript in pagina’s geïnjecteerd
  • CSRF (Cross-Site Request Forgery) - Ongeautoriseerde formulierinzendingen
  • Authenticatie omzeilen - Zwakke verwerking van sessies/wachtwoorden
  • Autorisatie omzeilen - Escalatie van bevoegdheden
  • Gegevensblootstelling - Gevoelige gegevens in URL’s, logs of caches
  1. Gebruikersauthenticatie en sessiebeheer
  2. Rolgebaseerde toegangscontrole (RBAC)
  3. Machtigingssysteem voor modules en objecten
  4. Invoervalidatie en uitvoer ontsnappen
  5. Bescherming tegen veelvoorkomende aanvallen
  6. Auditregistratie van beveiligingsgebeurtenissen
  7. Veilig omgaan met wachtwoorden
  8. CSRF-tokenbescherming

graph TB
subgraph "Authentication Layer"
A["User Authentication<br/>(Login/Sessions)"]
B["Session Management<br/>(Tokens/Cookies)"]
C["Password Security<br/>(Hashing/Salts)"]
end
subgraph "Authorization Layer"
D["Role Management<br/>(Admin/User/Guest)"]
E["Permission System<br/>(Module-level)"]
F["Object Permissions<br/>(Item-level)"]
end
subgraph "Protection Layer"
G["Input Validation<br/>(Type/Format)"]
H["Output Escaping<br/>(HTML/JavaScript)"]
I["CSRF Protection<br/>(Token Validation)"]
end
subgraph "Monitoring Layer"
J["Audit Logging<br/>(Security Events)"]
K["Rate Limiting<br/>(Brute Force)"]
L["Intrusion Detection<br/>(Suspicious Activity)"]
end
A --> B
A --> C
D --> E
E --> F
G --> I
H --> I
J --> K
K --> L

Aanmeldingsproces gebruiker:

<?php
// 1. Validate credentials
$user = $userHandler->findByLogin($username);
if (!$user || !password_verify($password, $user->getVar('pass'))) {
throw new AuthenticationException('Invalid credentials');
}
// 2. Check if account is active
if (!$user->getVar('uactive')) {
throw new AuthenticationException('Account inactive');
}
// 3. Create secure session
session_regenerate_id(true);
$_SESSION['uid'] = $user->getVar('uid');
$_SESSION['token'] = bin2hex(random_bytes(32));
$_SESSION['created'] = time();
// 4. Log the login
$this->auditLog('USER_LOGIN', $user->getVar('uid'));

Wachtwoordbeveiliging:

<?php
// Use password_hash (not MD5 or SHA1)
$hashed = password_hash($password, PASSWORD_BCRYPT, [
'cost' => 12, // High cost = slow brute force
]);
// Verify password
if (!password_verify($inputPassword, $hashed)) {
throw new Exception('Invalid password');
}
// Rehash if algorithm or cost changed
if (password_needs_rehash($hashed, PASSWORD_BCRYPT, ['cost' => 12])) {
$newHash = password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]);
$user->setVar('pass', $newHash);
$userHandler->insert($user);
}

Veilige sessieafhandeling:

<?php
// Session configuration
ini_set('session.cookie_httponly', true); // No JS access
ini_set('session.cookie_secure', true); // HTTPS only
ini_set('session.cookie_samesite', 'Strict'); // CSRF protection
ini_set('session.gc_maxlifetime', 3600); // 1 hour timeout
ini_set('session.sid_length', 64); // 64-char session ID
// Validate session
function validateSession() {
// Check timeout
if (time() - $_SESSION['created'] > 3600) {
session_destroy();
throw new SessionExpiredException();
}
// Validate user agent (prevent session hijacking)
if ($_SESSION['user_agent'] !== $_SERVER['HTTP_USER_AGENT']) {
throw new SessionInvalidException();
}
// Validate IP (optional, can be too strict)
if (!in_array($_SERVER['REMOTE_ADDR'], $_SESSION['ips'])) {
$_SESSION['ips'][] = $_SERVER['REMOTE_ADDR'];
}
}

Op rollen gebaseerd toegangscontrole:

<?php
class XoopsUser {
public function hasPermission(string $permissionName): bool
{
// Get user groups
$groups = $this->getGroups();
// Check if any group has permission
foreach ($groups as $groupId) {
if ($this->checkGroupPermission($groupId, $permissionName)) {
return true;
}
}
return false;
}
/**
* User groups and their permissions
* Admin: Full access
* Moderator: Content management
* User: Create own content
* Guest: Read-only access
*/
private function checkGroupPermission(int $groupId, string $permission): bool
{
$permissions = [
1 => ['admin_access'], // Admin group
2 => ['moderate_content', 'edit_own'], // Moderator group
3 => ['create_content', 'edit_own'], // User group
4 => [], // Guest group (no permissions)
];
return in_array($permission, $permissions[$groupId] ?? []);
}
}

Voorkom SQL injectie- en typefouten:

<?php
// Always use prepared statements
$sql = 'SELECT * FROM users WHERE id = ?';
$result = $db->query($sql, [$userId]); // ✅ Safe
// Input validation
function validateUserInput(array $data): array
{
return [
'email' => filter_var($data['email'] ?? '', FILTER_VALIDATE_EMAIL),
'age' => filter_var($data['age'] ?? 0, FILTER_VALIDATE_INT),
'website' => filter_var($data['website'] ?? '', FILTER_VALIDATE_URL),
'title' => substr(trim($data['title'] ?? ''), 0, 255),
];
}
// XOOPS Safe Input class
$safe = \Xmf\Request::getHtmlRequest('var_name', '');
$int = \Xmf\Request::getInt('page', 1);

Voorkom XSS-aanvallen:

<?php
// In PHP templates
echo htmlspecialchars($userInput, ENT_QUOTES, 'UTF-8');
// In Smarty templates (automatic escaping)
<{$user_input}> {* Escaped by default *}
<{$html|escape:false}> {* Only when needed *}
// JavaScript context
<script>
var message = "<{$userMessage|escape:'javascript'}>";
</script>
// URL context
<a href="<{$url|escape:'url'}>">Link</a>

Voorkomen van vervalsing op verschillende sites:

<?php
// Generate CSRF token
session_start();
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
// In forms
<form method="POST">
<input type="hidden" name="csrf_token" value="<{$csrf_token}>">
<button type="submit">Submit</button>
</form>
// Validate token
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'] ?? '')) {
// Process form
} else {
throw new InvalidTokenException('CSRF token invalid');
}
}

  1. Uitgebreide bescherming - Dekt de belangrijkste kwetsbaarheidsklassen
  2. Gelaagde beveiliging - Meerdere verdedigingslagen
  3. Flexibel RBAC - Fijnmazig toestemmingsbeheer
  4. Audittraject - Volg beveiligingsgebeurtenissen
  5. Industriestandaard - Komt overeen met de aanbevelingen van OWASP
  6. Module-integratie - Modules kunnen eenvoudig beveiligings-API’s gebruiken
  1. Complexiteit - Er is meer code en configuratie nodig
  2. Prestaties - Hashing en validatie voegen overhead toe
  3. Gebruikerservaring - Beveiliging soms lastig
  4. Onderhoud - Vereist voortdurende beveiligingsupdates
  5. Training vereist - Ontwikkelaars moeten de praktijken volgen
RisicoErnstMitigatie
Ontwikkelaar negeert beveiligingHoogCodebeoordeling, beveiligingstraining
Nieuwe kwetsbaarheden ontdektMiddelRegelmatige beveiligingsaudits, updates
Prestatie-impactLaagOptimaliseer hotpaths, caching
Te complexe machtigingenMiddelDuidelijke documentatie, voorbeelden

<?php
// ✅ DO: Use prepared statements
$result = $db->prepare('SELECT * FROM table WHERE id = ?')->execute([$id]);
// ❌ DON'T: Concatenate queries
$result = $db->query("SELECT * FROM table WHERE id = $id");
// ✅ DO: Escape output
echo htmlspecialchars($user_input, ENT_QUOTES, 'UTF-8');
// ❌ DON'T: Output raw user data
echo $user_input;
// ✅ DO: Check permissions
if (!$user->hasPermission('edit_content')) {
throw new PermissionException();
}
// ❌ DON'T: Trust user roles directly
if ($_POST['is_admin']) {
// Make user admin - SECURITY HOLE!
}
// ✅ DO: Validate input types
$page = (int)$_GET['page'];
// ❌ DON'T: Use untrusted values directly
$sql .= " LIMIT " . $_GET['limit'];

Waarom in eerste instantie niet gekozen: Te complex voor een gedeelde hostingomgeving, maar goed voor toekomstige integratie met externe authenticatiesystemen.

Status: Geaccepteerd als uitbreiding, geen kernvereiste, zie ADR-006

Status: Geïmplementeerd - voorkomt JavaScript-toegang tot sessiegegevens


  • ADR-001: Modulaire architectuur - Modules implementeren beveiliging
  • ADR-005: Modulemachtigingssysteem
  • ADR-006: tweefactorauthenticatie (toekomstig)


  • Gebruikersauthenticatiesysteem
  • Sessiebeheer
  • Wachtwoordhashing (bcrypt)
  • Rolgebaseerde toegangscontrole
  • Modulerechten
  • Kader voor invoervalidatie
  • Uitgang ontsnappen (PHP + Smarty)
  • CSRF-tokenbescherming
  • Logboekregistratie van beveiligingsaudits
  • Snelheidslimiet
  • Beveiligingsheaders

VersieDatumWijzigingen
1.0.028-01-2024Oorspronkelijk document

#xoops #adr #security #architectuur #authenticatie #autorisatie #rbac