Санитизация пользовательского ввода — это процесс очистки, преобразования или нейтрализации данных, полученных от пользователя, перед их дальнейшей обработкой, отображением или сохранением. В веб-приложениях пользовательские данные считаются потенциально небезопасными независимо от источника их получения.
При использовании библиотеки Awesomplete вопрос санитизации становится особенно важным, поскольку автодополнение часто работает с текстовыми полями, динамическими списками, удалёнными источниками данных и пользовательскими запросами. Неправильно обработанный ввод способен привести к ошибкам интерфейса, некорректному отображению информации и уязвимостям безопасности.
Любое значение, вводимое в поле автодополнения, может содержать:
Пример потенциально опасного ввода:
<script>alert("XSS")</script>
Другой пример:
<img src="x" oner ror="alert('hack')">
Если такие данные попадут в DOM без обработки, злоумышленник сможет выполнить произвольный код в браузере пользователя.
Awesomplete отображает элементы списка подсказок на основе массива значений.
Базовый пример:
const awesomplete = new Awesomplete(input, {
list: [
"JavaScript",
"TypeScript",
"Python"
]
});
В таком случае список полностью контролируется разработчиком и риск минимален.
Ситуация меняется при работе с внешними данными:
fetch("/api/search")
.then(response => response.json())
.then(data => {
awesomplete.list = data;
});
Если сервер возвращает непроверенные значения, они могут содержать потенциально опасный контент.
Наиболее распространённый сценарий — очистка данных до передачи их в Awesomplete.
Исходный массив:
const data = [
"JavaScript",
"<script>alert(1)</script>",
"Python"
];
Очистка:
function sanitize(text) {
return text
.replace(/</g, "<")
.replace(/>/g, ">");
}
const safeData = data.map(sanitize);
awesomplete.list = safeData;
После обработки специальные символы перестают восприниматься как HTML-разметка.
Наиболее опасными являются следующие символы:
| Символ | Замена |
|---|---|
| < | < |
| > | > |
| ” | ” |
| ’ | ’ |
| & | & |
Пример универсальной функции:
function escapeHtml(text) {
const div = document.createElement("div");
div.textContent = text;
return div.innerHTML;
}
Использование:
const safeValue = escapeHtml(userInput);
Такой подход считается одним из наиболее надёжных.
Даже если пользователь не взаимодействует напрямую с полем ввода, опасные данные могут поступать через API.
Пример ответа сервера:
[
"JavaScript",
"<b>Python</b>",
"<script>alert('xss')</script>"
]
Перед передачей данных в Awesomplete рекомендуется выполнять фильтрацию:
const safeItems = responseData.map(item =>
item.replace(/<[^>]*>/g, "")
);
awesomplete.list = safeItems;
Результат:
[
"JavaScript",
"Python",
"alert('xss')"
]
Иногда необходимо полностью избавиться от разметки.
Простейший вариант:
function stripTags(value) {
return value.replace(/<[^>]+>/g, "");
}
Использование:
const cleanValue = stripTags(userInput);
Однако регулярные выражения не способны корректно обработать всю сложность HTML.
Более безопасный вариант:
function removeHtml(html) {
const temp = document.createElement("div");
temp.innerHTML = html;
return temp.textContent || "";
}
Awesomplete активно использует введённую строку для поиска совпадений.
Например:
input.addEventListener("input", event => {
const query = event.target.value;
});
Перед использованием запроса желательно выполнять нормализацию:
function sanitizeQuery(query) {
return query
.trim()
.replace(/\s+/g, " ");
}
Применение:
const safeQuery = sanitizeQuery(input.value);
Это позволяет устранить лишние пробелы и случайные символы форматирования.
Очень длинные строки способны вызывать проблемы производительности.
Пример ограничения:
function limitLength(text, max = 100) {
return text.substring(0, max);
}
Использование:
const query = limitLength(input.value);
Часто применяются ограничения:
Конкретное значение зависит от требований проекта.
Некоторые символы не отображаются визуально, но могут влиять на обработку данных.
Очистка:
function removeControlChars(text) {
return text.replace(/[\x00-\x1F\x7F]/g, "");
}
Использование:
const cleanText = removeControlChars(userInput);
Различные символы могут выглядеть одинаково, но иметь разные внутренние представления.
Пример:
const normalized = input.value.normalize("NFC");
Это особенно полезно при поиске совпадений в Awesomplete.
Пример:
awesomplete.list = data.map(item =>
item.normalize("NFC")
);
Нормализация обеспечивает единообразное сравнение строк.
В некоторых случаях эффективнее разрешать только определённые символы.
Например, поиск по названиям товаров:
function sanitizeProductSearch(text) {
return text.replace(/[^a-zA-Zа-яА-Я0-9\s-]/g, "");
}
Использование:
const query = sanitizeProductSearch(input.value);
Такой подход блокирует большинство потенциально опасных конструкций.
Awesomplete позволяет переопределять отображение элементов.
Пример:
awesomplete.item = function(text) {
const li = document.createElement("li");
li.innerHTML = text;
return li;
};
Такой код опасен.
Если значение содержит:
<img src=x oner ror=alert(1)>
код будет интерпретирован браузером.
Безопасный вариант:
awesomplete.item = function(text) {
const li = document.createElement("li");
li.textContent = text;
return li;
};
Здесь данные отображаются как обычный текст.
Одна из самых распространённых ошибок при интеграции Awesomplete связана с использованием innerHTML.
Небезопасный пример:
results.innerHTML = userInput;
Безопасный вариант:
results.textContent = userInput;
Либо:
results.appendChild(
document.createTextNode(userInput)
);
Использование textContent практически всегда предпочтительнее.
Для серьёзных проектов часто применяется специализированная библиотека санитизации.
Пример использования:
const safeHtml = DOMPurify.sanitize(userInput);
Интеграция с Awesomplete:
const safeItems = data.map(item =>
DOMPurify.sanitize(item)
);
awesomplete.list = safeItems;
DOMPurify эффективно обрабатывает множество сложных сценариев XSS-атак и считается одним из наиболее надёжных решений для очистки HTML.
Очистка необходима не только при отображении.
Пример:
const query = sanitizeQuery(input.value);
fetch("/search", {
method: "POST",
body: JSON.stringify({
query
})
});
Это уменьшает вероятность передачи некорректных данных в серверную часть приложения.
Практика показывает, что наиболее безопасным является многоуровневый подход.
Этапы обработки:
Схема для Awesomplete может выглядеть следующим образом:
function sanitize(text) {
return text
.trim()
.replace(/[\x00-\x1F\x7F]/g, "")
.substring(0, 100);
}
input.addEventListener("input", () => {
const value = sanitize(input.value);
fetch(`/search?q=${encodeURIComponent(value)}`)
.then(response => response.json())
.then(data => {
const safeData = data.map(item =>
escapeHtml(item)
);
awesomplete.list = safeData;
});
});
Такой подход позволяет значительно снизить риск внедрения вредоносного кода, повысить устойчивость интерфейса к ошибочным данным и обеспечить безопасную работу механизма автодополнения при взаимодействии с пользовательским вводом и внешними источниками информации.