Санитизация входных данных
Никогда не доверяйте пользовательскому вводу. Всегда валидируйте и санитизируйте все входные данные перед использованием. XOOPS предоставляет класс MyTextSanitizer для санитизации текстовых входных данных и различные вспомогательные функции для валидации.
Связанная документация
Заголовок раздела «Связанная документация»- Security-Best-Practices - Комплексное руководство по безопасности
- CSRF-Protection - Система токенов и класс XoopsSecurity
- SQL-Injection-Prevention - Практики безопасности базы данных
Золотое правило
Заголовок раздела «Золотое правило»Никогда не доверяйте пользовательскому вводу. Все данные из внешних источников должны быть:
- Валидированы: Проверьте, что они соответствуют ожидаемому формату и типу
- Санитизированы: Удалите или экранируйте потенциально опасные символы
- Экранированы: При выводе экранируйте для конкретного контекста (HTML, JavaScript, SQL)
Класс MyTextSanitizer
Заголовок раздела «Класс MyTextSanitizer»XOOPS предоставляет класс MyTextSanitizer (обычно именуемый как $myts) для санитизации текста.
Получение экземпляра
Заголовок раздела «Получение экземпляра»// Получение единственного экземпляра$myts = MyTextSanitizer::getInstance();Базовая санитизация текста
Заголовок раздела «Базовая санитизация текста»$myts = MyTextSanitizer::getInstance();
// Для полей обычного текста (без HTML)$title = $myts->htmlSpecialChars($_POST['title']);
// Это преобразует:// < в <// > в >// & в &// " в "// ' в 'Обработка содержимого Textarea
Заголовок раздела «Обработка содержимого Textarea»Метод displayTarea() обеспечивает комплексную обработку textarea:
$myts = MyTextSanitizer::getInstance();
$content = $myts->displayTarea( $_POST['content'], $allowhtml = 0, // 0 = Нет HTML, 1 = HTML разрешён $allowsmiley = 1, // 1 = Смайлики включены $allowxcode = 1, // 1 = Коды XOOPS включены (BBCode) $allowimages = 1, // 1 = Изображения разрешены $allowlinebreak = 1 // 1 = Переводы строк конвертируются в <br>);Распространённые методы санитизации
Заголовок раздела «Распространённые методы санитизации»$myts = MyTextSanitizer::getInstance();
// Экранирование специальных символов HTML$safe_text = $myts->htmlSpecialChars($text);
// Удаление слешей, если магические кавычки включены$text = $myts->stripSlashesGPC($text);
// Преобразование кодов XOOPS (BBCode) в HTML$html = $myts->xoopsCodeDecode($text);
// Преобразование смайликов в изображения$html = $myts->smiley($text);
// Превращение ссылок в кликабельные$html = $myts->makeClickable($text);
// Полная обработка текста для предпросмотра$preview = $myts->previewTarea($text, $allowhtml, $allowsmiley, $allowxcode);Валидация входных данных
Заголовок раздела «Валидация входных данных»Валидация целых чисел
Заголовок раздела «Валидация целых чисел»// Валидация целого числа ID$id = isset($_REQUEST['id']) ? (int)$_REQUEST['id'] : 0;
if ($id <= 0) { redirect_header('index.php', 3, 'Invalid ID'); exit();}
// Альтернатива с 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
Заголовок раздела «Валидация URL»$url = filter_var($_POST['url'], FILTER_VALIDATE_URL);
if (!$url) { redirect_header('form.php', 3, 'Invalid URL'); exit();}
// Дополнительная проверка разрешённых протоколов$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'] ?? '';
// Валидация формата даты (YYYY-MM-DD)if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $date)) { redirect_header('form.php', 3, 'Invalid date format'); exit();}
// Валидация фактической даты$parts = explode('-', $date);if (!checkdate($parts[1], $parts[2], $parts[0])) { redirect_header('form.php', 3, 'Invalid date'); exit();}Валидация имён файлов
Заголовок раздела «Валидация имён файлов»// Удаление всех символов, кроме буквенно-цифровых, подчёркивания и дефиса$filename = preg_replace('/[^a-zA-Z0-9_-]/', '', $_POST['filename']);
// Или используйте подход с whitelist$allowed_chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-';$filename = '';foreach (str_split($_POST['filename']) as $char) { if (strpos($allowed_chars, $char) !== false) { $filename .= $char; }}Обработка различных типов входных данных
Заголовок раздела «Обработка различных типов входных данных»Текстовый ввод
Заголовок раздела «Текстовый ввод»$myts = MyTextSanitizer::getInstance();
// Короткий текст (названия, имена)$title = $myts->htmlSpecialChars(trim($_POST['title']));
// Ограничение длиныif (strlen($title) > 255) { $title = substr($title, 0, 255);}
// Проверка пустых обязательных полейif (empty($title)) { redirect_header('form.php', 3, 'Title is required'); exit();}Числовой ввод
Заголовок раздела «Числовой ввод»// Целое число$count = (int)$_POST['count'];$count = max(0, min($count, 1000)); // Убедитесь в диапазоне 0-1000
// Число с плавающей точкой$price = (float)$_POST['price'];$price = round($price, 2); // Округление до 2 десятичных знаков
// Валидация диапазонаif ($price < 0 || $price > 99999.99) { redirect_header('form.php', 3, 'Invalid price'); exit();}Булев ввод
Заголовок раздела «Булев ввод»// Значения чекбокса$is_active = isset($_POST['is_active']) ? 1 : 0;
// Или с явной проверкой значения$is_active = ($_POST['is_active'] ?? '') === '1' ? 1 : 0;Ввод массива
Заголовок раздела «Ввод массива»// Валидация ввода массива (например, несколько чекбоксов)$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; } }}Ввод Select/Option
Заголовок раздела «Ввод Select/Option»// Валидация против разрешённых значений$allowed_statuses = ['draft', 'published', 'archived'];$status = $_POST['status'] ?? '';
if (!in_array($status, $allowed_statuses)) { redirect_header('form.php', 3, 'Invalid status'); exit();}Объект Request (XMF)
Заголовок раздела «Объект Request (XMF)»При использовании XMF класс Request обеспечивает более чистую обработку входных данных:
use Xmf\Request;
// Получение целого числа$id = Request::getInt('id', 0);
// Получение строки$title = Request::getString('title', '');
// Получение массива$ids = Request::getArray('ids', []);
// Получение с указанием метода$id = Request::getInt('id', 0, 'POST');$search = Request::getString('q', '', 'GET');
// Проверка метода запросаif (Request::getMethod() !== 'POST') { redirect_header('form.php', 3, 'Invalid request method'); exit();}Создание класса валидации
Заголовок раздела «Создание класса валидации»Для сложных форм создайте специальный класс валидации:
<?phpnamespace XoopsModules\MyModule;
class Validator{ private $errors = [];
public function validateItem(array $data): bool { $this->errors = [];
// Валидация названия 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'; }
// Валидация электронной почты if (!empty($data['email'])) { if (!filter_var($data['email'], FILTER_VALIDATE_EMAIL)) { $this->errors['email'] = 'Invalid email format'; } }
// Валидация статуса $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; }}Использование:
$validator = new Validator();$data = [ 'title' => $_POST['title'], 'email' => $_POST['email'], 'status' => $_POST['status'],];
if (!$validator->validateItem($data)) { $errors = $validator->getErrors(); // Отображение ошибок пользователю}Санитизация для сохранения в базе данных
Заголовок раздела «Санитизация для сохранения в базе данных»При сохранении данных в базе данных:
$myts = MyTextSanitizer::getInstance();
// Для сохранения (будет обработана снова при отображении)$title = $myts->addSlashes($_POST['title']);
// Лучше: используйте параметризованные выражения (см. Предотвращение SQL инъекций)$sql = "INSERT INTO " . $xoopsDB->prefix('mytable') . " (title) VALUES (?)";$result = $xoopsDB->query($sql, [$_POST['title']]);Санитизация для отображения
Заголовок раздела «Санитизация для отображения»Различные контексты требуют различного экранирования:
$myts = MyTextSanitizer::getInstance();
// Контекст HTMLecho $myts->htmlSpecialChars($title);
// Внутри HTML атрибутовecho htmlspecialchars($title, ENT_QUOTES, 'UTF-8');
// Контекст JavaScriptecho json_encode($title);
// Параметр URLecho urlencode($title);
// Полный URLecho htmlspecialchars($url, ENT_QUOTES, 'UTF-8');Распространённые ошибки
Заголовок раздела «Распространённые ошибки»Двойное кодирование
Заголовок раздела «Двойное кодирование»Проблема: Данные кодируются несколько раз
// Неправильно - двойное кодирование$title = $myts->htmlSpecialChars($myts->htmlSpecialChars($_POST['title']));
// Правильно - кодируйте один раз в подходящее время$title = $_POST['title']; // Сохраняйте в исходном видеecho $myts->htmlSpecialChars($title); // Кодируйте при выводеНепостоянное кодирование
Заголовок раздела «Непостоянное кодирование»Проблема: Некоторые выходы кодируются, некоторые нет
Решение: Всегда используйте последовательный подход, предпочтительно кодирование при выводе:
// Назначение шаблону$GLOBALS['xoopsTpl']->assign('title', htmlspecialchars($title, ENT_QUOTES, 'UTF-8'));Отсутствующая валидация
Заголовок раздела «Отсутствующая валидация»Проблема: Только санитизация без валидации
Решение: Всегда валидируйте сначала, затем санитизируйте:
// Сначала валидируйтеif (!preg_match('/^[a-z0-9_]+$/', $_POST['username'])) { redirect_header('form.php', 3, 'Username contains invalid characters'); exit();}
// Затем санитизируйте для сохранения/отображения$username = $myts->htmlSpecialChars($_POST['username']);Резюме лучших практик
Заголовок раздела «Резюме лучших практик»- Используйте MyTextSanitizer для обработки текстового контента
- Используйте filter_var() для валидации конкретного формата
- Используйте приведение типов для числовых значений
- Используйте whitelist разрешённых значений для инпутов select
- Валидируйте перед санитизацией
- Экранируйте при выводе, не при вводе
- Используйте параметризованные выражения для запросов к базе данных
- Создавайте классы валидации для сложных форм
- Никогда не доверяйте валидации на стороне клиента - всегда валидируйте на стороне сервера
#security #sanitization #validation #xoops #MyTextSanitizer #input-handling