Sanitizzazione dell'Input
Non fidarti mai dell’input dell’utente. Valida e sanitizza sempre tutti i dati di input prima di utilizzarli. XOOPS fornisce la classe MyTextSanitizer per sanitizzare l’input di testo e varie funzioni helper per la validazione.
Documentazione Correlata
Sezione intitolata “Documentazione Correlata”- Security-Best-Practices - Guida completa alla sicurezza
- CSRF-Protection - Sistema di token e classe XoopsSecurity
- SQL-Injection-Prevention - Pratiche di sicurezza del database
La Regola d’Oro
Sezione intitolata “La Regola d’Oro”Non fidarti mai dell’input dell’utente. Tutti i dati da fonti esterne devono:
- Validati: Verificare che corrisponda al formato e tipo previsto
- Sanitizzati: Rimuovere o sfuggire ai caratteri potenzialmente pericolosi
- Sfuggiti: Quando si output, sfuggire per il contesto specifico (HTML, JavaScript, SQL)
Classe MyTextSanitizer
Sezione intitolata “Classe MyTextSanitizer”XOOPS fornisce la classe MyTextSanitizer (comunemente aliased come $myts) per la sanitizzazione del testo.
Ottenere l’Istanza
Sezione intitolata “Ottenere l’Istanza”// Ottieni l'istanza singleton$myts = MyTextSanitizer::getInstance();Sanitizzazione Basica del Testo
Sezione intitolata “Sanitizzazione Basica del Testo”$myts = MyTextSanitizer::getInstance();
// Per campi di testo semplice (nessun HTML consentito)$title = $myts->htmlSpecialChars($_POST['title']);
// Questo converte:// < a <// > a >// & a &// " a "// ' a 'Elaborazione del Contenuto di Textarea
Sezione intitolata “Elaborazione del Contenuto di Textarea”Il metodo displayTarea() fornisce un’elaborazione completa di textarea:
$myts = MyTextSanitizer::getInstance();
$content = $myts->displayTarea( $_POST['content'], $allowhtml = 0, // 0 = Nessun HTML consentito, 1 = HTML consentito $allowsmiley = 1, // 1 = Emoticon abilitate $allowxcode = 1, // 1 = Codici XOOPS abilitati (BBCode) $allowimages = 1, // 1 = Immagini consentite $allowlinebreak = 1 // 1 = A capo convertiti a <br>);Metodi di Sanitizzazione Comuni
Sezione intitolata “Metodi di Sanitizzazione Comuni”$myts = MyTextSanitizer::getInstance();
// Escape dei caratteri speciali HTML$safe_text = $myts->htmlSpecialChars($text);
// Rimuovi barre inverse se magic quotes sono attive$text = $myts->stripSlashesGPC($text);
// Converti codici XOOPS (BBCode) a HTML$html = $myts->xoopsCodeDecode($text);
// Converti emoticon in immagini$html = $myts->smiley($text);
// Rendi cliccabili i link$html = $myts->makeClickable($text);
// Elaborazione completa del testo per l'anteprima$preview = $myts->previewTarea($text, $allowhtml, $allowsmiley, $allowxcode);Validazione dell’Input
Sezione intitolata “Validazione dell’Input”Validazione dei Valori Interi
Sezione intitolata “Validazione dei Valori Interi”// Valida ID intero$id = isset($_REQUEST['id']) ? (int)$_REQUEST['id'] : 0;
if ($id <= 0) { redirect_header('index.php', 3, 'Invalid ID'); exit();}
// Alternativa con filter_var$id = filter_var($_REQUEST['id'] ?? 0, FILTER_VALIDATE_INT);if ($id === false || $id <= 0) { redirect_header('index.php', 3, 'Invalid ID'); exit();}Validazione degli Indirizzi Email
Sezione intitolata “Validazione degli Indirizzi Email”$email = filter_var($_POST['email'], FILTER_VALIDATE_EMAIL);
if (!$email) { redirect_header('form.php', 3, 'Invalid email address'); exit();}Validazione degli URL
Sezione intitolata “Validazione degli URL”$url = filter_var($_POST['url'], FILTER_VALIDATE_URL);
if (!$url) { redirect_header('form.php', 3, 'Invalid URL'); exit();}
// Controllo aggiuntivo per protocolli consentiti$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();}Validazione delle Date
Sezione intitolata “Validazione delle Date”$date = $_POST['date'] ?? '';
// Valida il formato della data (YYYY-MM-DD)if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $date)) { redirect_header('form.php', 3, 'Invalid date format'); exit();}
// Valida la validità della data effettiva$parts = explode('-', $date);if (!checkdate($parts[1], $parts[2], $parts[0])) { redirect_header('form.php', 3, 'Invalid date'); exit();}Validazione dei Nomi di File
Sezione intitolata “Validazione dei Nomi di File”// Rimuovi tutti i caratteri eccetto alfanumerici, underscore e trattino$filename = preg_replace('/[^a-zA-Z0-9_-]/', '', $_POST['filename']);
// O usa un approccio whitelist$allowed_chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-';$filename = '';foreach (str_split($_POST['filename']) as $char) { if (strpos($allowed_chars, $char) !== false) { $filename .= $char; }}Gestione di Diversi Tipi di Input
Sezione intitolata “Gestione di Diversi Tipi di Input”Input di Stringhe
Sezione intitolata “Input di Stringhe”$myts = MyTextSanitizer::getInstance();
// Testo breve (titoli, nomi)$title = $myts->htmlSpecialChars(trim($_POST['title']));
// Limita la lunghezzaif (strlen($title) > 255) { $title = substr($title, 0, 255);}
// Verifica i campi obbligatori vuotiif (empty($title)) { redirect_header('form.php', 3, 'Title is required'); exit();}Input Numerico
Sezione intitolata “Input Numerico”// Intero$count = (int)$_POST['count'];$count = max(0, min($count, 1000)); // Assicura l'intervallo 0-1000
// Float$price = (float)$_POST['price'];$price = round($price, 2); // Arrotonda a 2 cifre decimali
// Valida l'intervalloif ($price < 0 || $price > 99999.99) { redirect_header('form.php', 3, 'Invalid price'); exit();}Input Booleano
Sezione intitolata “Input Booleano”// Valori di spunta$is_active = isset($_POST['is_active']) ? 1 : 0;
// O con controllo esplicito del valore$is_active = ($_POST['is_active'] ?? '') === '1' ? 1 : 0;Input di Array
Sezione intitolata “Input di Array”// Valida input di array (ad es. più caselle di controllo)$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; } }}Input di Selezione/Opzione
Sezione intitolata “Input di Selezione/Opzione”// Valida contro i valori consentiti$allowed_statuses = ['draft', 'published', 'archived'];$status = $_POST['status'] ?? '';
if (!in_array($status, $allowed_statuses)) { redirect_header('form.php', 3, 'Invalid status'); exit();}Oggetto Request (XMF)
Sezione intitolata “Oggetto Request (XMF)”Quando si utilizza XMF, la classe Request fornisce una gestione dell’input più pulita:
use Xmf\Request;
// Ottieni intero$id = Request::getInt('id', 0);
// Ottieni stringa$title = Request::getString('title', '');
// Ottieni array$ids = Request::getArray('ids', []);
// Ottieni con specifica del metodo$id = Request::getInt('id', 0, 'POST');$search = Request::getString('q', '', 'GET');
// Verifica il metodo di richiestaif (Request::getMethod() !== 'POST') { redirect_header('form.php', 3, 'Invalid request method'); exit();}Creazione di una Classe di Validazione
Sezione intitolata “Creazione di una Classe di Validazione”Per moduli complessi, crea una classe di validazione dedicata:
<?phpnamespace XoopsModules\MyModule;
class Validator{ private $errors = [];
public function validateItem(array $data): bool { $this->errors = [];
// Validazione del titolo 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'; }
// Validazione dell'email if (!empty($data['email'])) { if (!filter_var($data['email'], FILTER_VALIDATE_EMAIL)) { $this->errors['email'] = 'Invalid email format'; } }
// Validazione dello stato $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; }}Utilizzo:
$validator = new Validator();$data = [ 'title' => $_POST['title'], 'email' => $_POST['email'], 'status' => $_POST['status'],];
if (!$validator->validateItem($data)) { $errors = $validator->getErrors(); // Visualizza gli errori all'utente}Sanitizzazione per l’Archiviazione nel Database
Sezione intitolata “Sanitizzazione per l’Archiviazione nel Database”Quando archivi i dati nel database:
$myts = MyTextSanitizer::getInstance();
// Per l'archiviazione (verrà elaborato di nuovo sul display)$title = $myts->addSlashes($_POST['title']);
// Meglio: Usa query preparate (vedi Prevenzione dell'Iniezione SQL)$sql = "INSERT INTO " . $xoopsDB->prefix('mytable') . " (title) VALUES (?)";$result = $xoopsDB->query($sql, [$_POST['title']]);Sanitizzazione per la Visualizzazione
Sezione intitolata “Sanitizzazione per la Visualizzazione”Contesti diversi richiedono sfuggite diverse:
$myts = MyTextSanitizer::getInstance();
// Contesto HTMLecho $myts->htmlSpecialChars($title);
// All'interno degli attributi HTMLecho htmlspecialchars($title, ENT_QUOTES, 'UTF-8');
// Contesto JavaScriptecho json_encode($title);
// Parametro URLecho urlencode($title);
// URL completoecho htmlspecialchars($url, ENT_QUOTES, 'UTF-8');Errori Comuni
Sezione intitolata “Errori Comuni”Doppia Codifica
Sezione intitolata “Doppia Codifica”Problema: I dati vengono codificati più volte
// Sbagliato - doppia codifica$title = $myts->htmlSpecialChars($myts->htmlSpecialChars($_POST['title']));
// Giusto - codifica una volta, al momento appropriato$title = $_POST['title']; // Archivia rawecho $myts->htmlSpecialChars($title); // Codifica su outputCodifica Incoerente
Sezione intitolata “Codifica Incoerente”Problema: Alcuni output sono codificati, altri no
Soluzione: Usa sempre un approccio coerente, preferibilmente codificando su output:
// Assegnazione del template$GLOBALS['xoopsTpl']->assign('title', htmlspecialchars($title, ENT_QUOTES, 'UTF-8'));Validazione Mancante
Sezione intitolata “Validazione Mancante”Problema: Solo sanitizzazione senza validazione
Soluzione: Valida sempre prima, poi sanitizza:
// Valida primaif (!preg_match('/^[a-z0-9_]+$/', $_POST['username'])) { redirect_header('form.php', 3, 'Username contains invalid characters'); exit();}
// Poi sanitizza per l'archiviazione/visualizzazione$username = $myts->htmlSpecialChars($_POST['username']);Riassunto delle Best Practice
Sezione intitolata “Riassunto delle Best Practice”- Usa MyTextSanitizer per l’elaborazione dei contenuti di testo
- Usa filter_var() per la validazione del formato specifico
- Usa il casting dei tipi per i valori numerici
- Whitelist valori consentiti per gli input di selezione
- Valida prima di sanitizzare
- Sfuggi su output, non su input
- Usa query preparate per le query del database
- Crea classi di validazione per i moduli complessi
- Non fidarti mai della validazione lato client - valida sempre lato server
#security #sanitization #validation #xoops #MyTextSanitizer #input-handling