Aller au contenu

Assainissement des données d'entrée

Ne faites jamais confiance à l’entrée utilisateur. Validez et assainissez toujours toutes les données d’entrée avant de les utiliser. XOOPS fournit la classe MyTextSanitizer pour assainir l’entrée de texte et diverses fonctions d’aide pour la validation.

  • Security-Best-Practices - Guide de sécurité complet
  • CSRF-Protection - Système de jetons et classe XoopsSecurity
  • SQL-Injection-Prevention - Pratiques de sécurité de base de données

Ne jamais faire confiance à l’entrée utilisateur. Toutes les données de sources externes doivent :

  1. Être validées : Vérifier qu’elles correspondent au format et au type attendus
  2. Être assainies : Supprimer ou échapper les caractères potentiellement dangereux
  3. Être échappées : Lors de la sortie, échapper pour le contexte spécifique (HTML, JavaScript, SQL)

XOOPS provides the MyTextSanitizer class (commonly aliased as $myts) for text sanitization.

// 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;

La méthode displayTarea() method provides comprehensive textarea processing:

$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();
}

When using XMF, the Request class provides cleaner input handling:

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();
}

For complex forms, create a dedicated validation class:

<?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;
}
}

Usage:

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

When storing data in the 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']]);

Different contexts require different escaping:

$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');

Problem: Data gets encoded multiple times

// 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

Problem: Some outputs are encoded, some are not

Solution: Always use a consistent approach, preferably encoding on output:

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

Problem: Only sanitizing without validating

Solution: Always validate first, then sanitize:

// 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. Use MyTextSanitizer for text content processing
  2. Use filter_var() for specific format validation
  3. Use type casting for numeric values
  4. Whitelist allowed values for select inputs
  5. Validate before sanitizing
  6. Escape on output, not on input
  7. Use prepared statements for database queries
  8. Create validation classes for complex forms
  9. Never trust client-side validation - always validate server-side

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