Ga naar inhoud

Invoersanering

Vertrouw nooit op gebruikersinvoer. Valideer en zuiver altijd alle invoergegevens voordat u deze gebruikt. XOOPS biedt de klasse MyTextSanitizer voor het opschonen van tekstinvoer en verschillende helperfuncties voor validatie.

  • Best-practices op het gebied van beveiliging - Uitgebreide beveiligingsgids
  • CSRF-bescherming - Tokensysteem en XoopsSecurity-klasse
  • SQL-Injectiepreventie - Databasebeveiligingspraktijken

Vertrouw nooit gebruikersinvoer. Alle gegevens uit externe bronnen moeten:

  1. Gevalideerd: controleer of het overeenkomt met het verwachte formaat en type
  2. Opgeschoond: verwijder of ontsnap aan potentieel gevaarlijke karakters
  3. Escaped: bij uitvoer ontsnappen voor de specifieke context (HTML, JavaScript, SQL)

XOOPS biedt de klasse MyTextSanitizer (gewoonlijk alias $myts) voor het opschonen van tekst.

// Get the singleton instance
$myts = MyTextSanitizer::getInstance();
$myts = MyTextSanitizer::getInstance();
// For plain text fields (no HTML allowed)
$title = $myts->htmlSpecialChars($_POST['title']);
// This converts:
// < to &lt;
// > to &gt;
// & to &amp;
// " to &quot;
// ' to &#039;

De displayTarea()-methode biedt uitgebreide tekstgebiedverwerking:

$myts = MyTextSanitizer::getInstance();
$content = $myts->displayTarea(
$_POST['content'],
$allowhtml = 0, // 0 = No HTML allowed, 1 = HTML allowed
$allowsmiley = 1, // 1 = Smilies enabled
$allowxcode = 1, // 1 = XOOPS codes enabled (BBCode)
$allowimages = 1, // 1 = Images allowed
$allowlinebreak = 1 // 1 = Line breaks converted to <br>
);
$myts = MyTextSanitizer::getInstance();
// HTML special characters escaping
$safe_text = $myts->htmlSpecialChars($text);
// Strip slashes if magic quotes are on
$text = $myts->stripSlashesGPC($text);
// Convert XOOPS codes (BBCode) to HTML
$html = $myts->xoopsCodeDecode($text);
// Convert smileys to images
$html = $myts->smiley($text);
// Make clickable links
$html = $myts->makeClickable($text);
// Complete text processing for preview
$preview = $myts->previewTarea($text, $allowhtml, $allowsmiley, $allowxcode);
// Validate integer ID
$id = isset($_REQUEST['id']) ? (int)$_REQUEST['id'] : 0;
if ($id <= 0) {
redirect_header('index.php', 3, 'Invalid ID');
exit();
}
// Alternative with filter_var
$id = filter_var($_REQUEST['id'] ?? 0, FILTER_VALIDATE_INT);
if ($id === false || $id <= 0) {
redirect_header('index.php', 3, 'Invalid ID');
exit();
}
$email = filter_var($_POST['email'], FILTER_VALIDATE_EMAIL);
if (!$email) {
redirect_header('form.php', 3, 'Invalid email address');
exit();
}
$url = filter_var($_POST['url'], FILTER_VALIDATE_URL);
if (!$url) {
redirect_header('form.php', 3, 'Invalid URL');
exit();
}
// Additional check for allowed protocols
$parsed = parse_url($url);
$allowed_schemes = ['http', 'https'];
if (!in_array($parsed['scheme'], $allowed_schemes)) {
redirect_header('form.php', 3, 'Only HTTP and HTTPS URLs are allowed');
exit();
}
$date = $_POST['date'] ?? '';
// Validate date format (YYYY-MM-DD)
if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $date)) {
redirect_header('form.php', 3, 'Invalid date format');
exit();
}
// Validate actual date validity
$parts = explode('-', $date);
if (!checkdate($parts[1], $parts[2], $parts[0])) {
redirect_header('form.php', 3, 'Invalid date');
exit();
}
// Remove all characters except alphanumeric, underscore, and hyphen
$filename = preg_replace('/[^a-zA-Z0-9_-]/', '', $_POST['filename']);
// Or use a whitelist approach
$allowed_chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-';
$filename = '';
foreach (str_split($_POST['filename']) as $char) {
if (strpos($allowed_chars, $char) !== false) {
$filename .= $char;
}
}
$myts = MyTextSanitizer::getInstance();
// Short text (titles, names)
$title = $myts->htmlSpecialChars(trim($_POST['title']));
// Limit length
if (strlen($title) > 255) {
$title = substr($title, 0, 255);
}
// Check for empty required fields
if (empty($title)) {
redirect_header('form.php', 3, 'Title is required');
exit();
}
// Integer
$count = (int)$_POST['count'];
$count = max(0, min($count, 1000)); // Ensure range 0-1000
// Float
$price = (float)$_POST['price'];
$price = round($price, 2); // Round to 2 decimal places
// Validate range
if ($price < 0 || $price > 99999.99) {
redirect_header('form.php', 3, 'Invalid price');
exit();
}
// Checkbox values
$is_active = isset($_POST['is_active']) ? 1 : 0;
// Or with explicit value check
$is_active = ($_POST['is_active'] ?? '') === '1' ? 1 : 0;
// Validate array input (e.g., multiple checkboxes)
$selected_ids = [];
if (isset($_POST['ids']) && is_array($_POST['ids'])) {
foreach ($_POST['ids'] as $id) {
$clean_id = (int)$id;
if ($clean_id > 0) {
$selected_ids[] = $clean_id;
}
}
}
// Validate against allowed values
$allowed_statuses = ['draft', 'published', 'archived'];
$status = $_POST['status'] ?? '';
if (!in_array($status, $allowed_statuses)) {
redirect_header('form.php', 3, 'Invalid status');
exit();
}

Bij gebruik van XMF zorgt de klasse Request voor een schonere invoerverwerking:

use Xmf\Request;
// Get integer
$id = Request::getInt('id', 0);
// Get string
$title = Request::getString('title', '');
// Get array
$ids = Request::getArray('ids', []);
// Get with method specification
$id = Request::getInt('id', 0, 'POST');
$search = Request::getString('q', '', 'GET');
// Check request method
if (Request::getMethod() !== 'POST') {
redirect_header('form.php', 3, 'Invalid request method');
exit();
}

Voor complexe formulieren maakt u een speciale validatieklasse:

<?php
namespace XoopsModules\MyModule;
class Validator
{
private $errors = [];
public function validateItem(array $data): bool
{
$this->errors = [];
// Title validation
if (empty($data['title'])) {
$this->errors['title'] = 'Title is required';
} elseif (strlen($data['title']) > 255) {
$this->errors['title'] = 'Title must be 255 characters or less';
}
// Email validation
if (!empty($data['email'])) {
if (!filter_var($data['email'], FILTER_VALIDATE_EMAIL)) {
$this->errors['email'] = 'Invalid email format';
}
}
// Status validation
$allowed = ['draft', 'published'];
if (!in_array($data['status'], $allowed)) {
$this->errors['status'] = 'Invalid status';
}
return empty($this->errors);
}
public function getErrors(): array
{
return $this->errors;
}
public function getError(string $field): ?string
{
return $this->errors[$field] ?? null;
}
}

Gebruik:

$validator = new Validator();
$data = [
'title' => $_POST['title'],
'email' => $_POST['email'],
'status' => $_POST['status'],
];
if (!$validator->validateItem($data)) {
$errors = $validator->getErrors();
// Display errors to user
}

Bij het opslaan van gegevens in de database:

$myts = MyTextSanitizer::getInstance();
// For storage (will be processed again on display)
$title = $myts->addSlashes($_POST['title']);
// Better: Use prepared statements (see SQL Injection Prevention)
$sql = "INSERT INTO " . $xoopsDB->prefix('mytable') . " (title) VALUES (?)";
$result = $xoopsDB->query($sql, [$_POST['title']]);

Verschillende contexten vereisen verschillende ontsnappingen:

$myts = MyTextSanitizer::getInstance();
// HTML context
echo $myts->htmlSpecialChars($title);
// Within HTML attributes
echo htmlspecialchars($title, ENT_QUOTES, 'UTF-8');
// JavaScript context
echo json_encode($title);
// URL parameter
echo urlencode($title);
// Full URL
echo htmlspecialchars($url, ENT_QUOTES, 'UTF-8');

Probleem: gegevens worden meerdere keren gecodeerd

// Wrong - double encoding
$title = $myts->htmlSpecialChars($myts->htmlSpecialChars($_POST['title']));
// Right - encode once, at the appropriate time
$title = $_POST['title']; // Store raw
echo $myts->htmlSpecialChars($title); // Encode on output

Probleem: Sommige uitgangen zijn gecodeerd, andere niet

Oplossing: gebruik altijd een consistente aanpak, bij voorkeur codering bij uitvoer:

// Template assignment
$GLOBALS['xoopsTpl']->assign('title', htmlspecialchars($title, ENT_QUOTES, 'UTF-8'));

Probleem: Alleen ontsmetten zonder valideren

Oplossing: Altijd eerst valideren en dan ontsmetten:

// First validate
if (!preg_match('/^[a-z0-9_]+$/', $_POST['username'])) {
redirect_header('form.php', 3, 'Username contains invalid characters');
exit();
}
// Then sanitize for storage/display
$username = $myts->htmlSpecialChars($_POST['username']);
  1. Gebruik MyTextSanitizer voor de verwerking van tekstinhoud
  2. Gebruik filter_var() voor specifieke formaatvalidatie
  3. Gebruik type casting voor numerieke waarden
  4. Toegestane waarden op witte lijst voor geselecteerde invoer
  5. Valideren vóór ontsmetten
  6. Escape op uitgang, niet op ingang
  7. Gebruik voorbereide instructies voor databasequery’s
  8. Maak validatieklassen voor complexe formulieren
  9. Vertrouw nooit op validatie aan de clientzijde - valideer altijd aan de serverzijde

#security #sanitization #validatie #xoops #MyTextSanitizer #input-handling