Cross-Site Scripting (XSS) защита является критически важной для безопасности веб-интерфейса MikoPBX. Данные рекомендации основаны на применённых подходах в системе и должны соблюдаться при разработке новых модулей.
Используйте класс SecurityHelper для контекстно-зависимого экранирования:
use MikoPBX\AdminCabinet\Library\SecurityHelper;
// HTML контекст
$safeHtml = SecurityHelper::escapeHtml($userInput);
// JavaScript строки
$safeJs = SecurityHelper::escapeJs($userInput);
// URL параметры
$safeUrl = SecurityHelper::escapeUrl($userInput);
// CSS значения
$safeCss = SecurityHelper::escapeCss($userInput);
// HTML атрибуты
$safeAttr = SecurityHelper::escapeAttribute($userInput);Всегда используйте автоматическое экранирование:
{# Рекомендуется - автоматическое экранирование #}
{{ userInput|e }}
{# Для сложных случаев #}
{{ userInput|escape('html') }}
{{ userInput|escape('js') }}
{{ userInput|escape('url') }}// Проверить на наличие опасных паттернов
if (SecurityHelper::containsDangerousContent($input)) {
// Дополнительная валидация или логирование
$safeInput = SecurityHelper::escapeHtml($input);
}$safeFilename = SecurityHelper::sanitizeFilename($userFilename);Используйте глобальный класс SecurityUtils для безопасного отображения:
// Базовое экранирование HTML
const safeContent = SecurityUtils.escapeHtml(userInput);
// С разрешением безопасных иконок
const safeContentWithIcons = SecurityUtils.escapeHtml(userInput, true);
// Для атрибутов
const safeAttr = SecurityUtils.sanitizeAttribute(userInput);
// Для dropdown элементов (строгий режим)
const safeDropdownText = SecurityUtils.sanitizeForDropdown(userInput);
// Для отображения с выбором режима строгости
const safeDisplay = SecurityUtils.sanitizeForDisplay(userInput, strictMode);SecurityUtils поддерживает безопасные иконки Fomantic UI:
// Разрешённые иконки
const safeIcon = '<i class="phone icon"></i>';
const safeNestedIcon = '<i class="icons"><i class="user outline icon"></i></i>';
// Опасные иконки будут экранированы
const dangerousIcon = '<i class="phone icon" onclick="alert(1)"></i>';// Безопасные option элементы
const safeOption = SecurityUtils.createSafeOption(value, text, strictMode);
// Безопасная установка HTML содержимого
SecurityUtils.setHtmlContent($element, content, strictMode);Для контента Extensions API используйте специальный метод:
const safeExtensionContent = SecurityUtils.sanitizeExtensionsApiContent(apiContent);Для полей с системными значениями используйте SystemSanitizer:
use MikoPBX\PBXCoreREST\Lib\Common\SystemSanitizer;
// Правила санитизации для extension полей
$extensionRule = SystemSanitizer::getExtensionSanitizationRule(20, true);
// Правила для routing полей
$routingRule = SystemSanitizer::getRoutingSanitizationRule(20, true);
// Валидация
if (SystemSanitizer::isValidExtension($value)) {
// Значение корректно
}
// Санитизация
$cleanValue = SystemSanitizer::sanitizeExtension($userInput);// PHP
echo SecurityHelper::escapeHtml($data);{# Volt #}
{{ data|e }}// JavaScript
element.textContent = data; // Безопасно
// ИЛИ
$(element).text(data); // Безопасно с jQuery// PHP
echo '<div id="' . SecurityHelper::escapeAttribute($id) . '">';{# Volt #}
<div id="{{ id|escape('html_attr') }}">// PHP в JavaScript
echo 'var message = "' . SecurityHelper::escapeJs($message) . '";';// PHP
$url = 'search?q=' . SecurityHelper::escapeUrl($query);// ОПАСНО - прямой вывод
echo $userInput;
// ОПАСНО - в атрибутах
echo '<div onclick="' . $userInput . '">';{# ОПАСНО - без экранирования #}
{{ userInput|raw }}
{# ОПАСНО - в JavaScript #}
<script>var data = "{{ userInput }}";</script>// ОПАСНО - innerHTML с пользовательскими данными
element.innerHTML = userInput;
// ОПАСНО - eval или Function
eval(userInput);
new Function(userInput);
// ОПАСНО - document.write
document.write(userInput);// Проверка на опасные паттерны
const isDangerous = SecurityUtils.containsDangerousPatterns(input);
// Проверка безопасности для dropdown
const isSafeForDropdown = SecurityUtils.isSafeForDropdown(input);
// Статистика обработки
const stats = SecurityUtils.getProcessingStats(input);
console.log('Safe icons:', stats.safeSimpleIcons);
console.log('Dangerous patterns:', stats.dangerousPatterns);// В контроллерах
$data = self::sanitizeData($this->request->getPost(), $this->filter);// В представлениях
$this->view->safeData = SecurityHelper::escapeHtml($data);// В формах Phalcon
$this->add(new Text('name', [
'filters' => ['trim', 'string']
]));// Безопасная обработка AJAX
$.api({
onSuccess(response) {
const safeMessage = SecurityUtils.escapeHtml(response.message);
UserMessage.showInfo(safeMessage);
}
});// Включить отладку SecurityUtils
SecurityUtils.debug = true;
// Логи будут показывать процесс санитизацииif (SecurityHelper::containsDangerousContent($input)) {
error_log("Suspicious content detected: " . $input);
}echo "<div>" . $_POST['data'] . "</div>";$('#content').html(userInput);echo "<div>" . SecurityHelper::escapeHtml($_POST['data']) . "</div>";SecurityUtils.setHtmlContent($('#content'), userInput, true);- Все пользовательские данные экранируются перед выводом
- Используется контекстно-зависимое экранирование
- Опасные паттерны проверяются на входе
- SecurityHelper/SecurityUtils используются во всех модулях
- Тестирование с XSS payloads выполнено
- Логирование подозрительного контента настроено
Следование этим рекомендациям обеспечит надёжную защиту от XSS атак в модулях MikoPBX. Всегда помните принцип: экранировать на выходе, валидировать на входе.