HTML, chmod, контейнеры и cron
Обоснование четырех утилит: почему редактору HTML нужен список разрешений и песочница, почему важна заглавная буква S в строке chmod, что команда запуска docker не может выразить в Compose, а также два правила cron, которые ловят всех.
Редактор HTML: список разрешений, а не фильтр
Редактор создает HTML, а HTML, полученный из текстового поля, является самым старым вектором внедрения. Здесь путаются два разных вопроса, поэтому стоит их разделить. Первый вопрос: «Можно ли обманом заставить этот редактор создать разметку, которая запускает код на странице, которая его отображает?» Второй вопрос: «Это безопасный способ очистить вредоносный HTML из ненадежного источника?» Этот инструмент отвечает «да» на первый вопрос и «нет» на второй, и он говорит об этом на панели, а не позволяет вам предположить обратное.
Механизм представляет собой список разрешенных. Допускается список элементов; каждый второй элемент разворачивается, поэтому его текст сохраняется, а тег — нет. Для каждого элемента допускается список атрибутов; все остальное отбрасывается, что делает каждый обработчик событий невозможным, а не просто блокируемым. Перед этой проверкой имена атрибутов пишутся строчными буквами, поэтому oNeRrOr и ONERROR — это то же отвергаемое имя, что и onerror. Элементы, содержимое которых анализатор HTML обрабатывает как необработанный текст — скрипт, стиль, текстовая область, iframe, заголовок — удаляются вместе с их содержимым, поскольку их развертывание вставит исходный код скрипта в документ как разметку.
Адреса ссылок проходят собственную проверку. Значение декодируется с помощью объекта и удаляется из пробелов и управляющих символов перед чтением его схемы, потому что именно это делает браузер при навигации: javasкрипт: предупреждение(1) и java ascript:alert(1) оба достигают одного и того же места. Сохраняются только адреса http, https, mailto, tel, ftp и относительные. Ссылка на символ, которую инструмент не может разрешить — : является классическим — приводит к тому, что весь адрес отклоняется, а не проходит, потому что фильтр, который понимает меньшую часть входных данных, чем браузер, — это фильтр с дырой в нем.
Кнопки изображения нет, а img нет в белом списке. Разрешенный тег изображения — это исходящий запрос, откуда бы ни находился документ, и поверхность ошибки. Для редактора, выпускающего прозу, это тоже не стоит.
Защита, которая не зависит от совершенства всего этого, — это предварительный просмотр. Он отображается в iframe с атрибутом песочницы, который вообще ничего не предоставляет — ни скриптов, ни форм, ни доступа к тому же источнику. Если полезная нагрузка когда-либо попадет в список разрешенных, браузер все равно откажется выполнять ее там. Это структурная гарантия, а не обещание относительно нашего кода.
Честное ограничение: это средство очистки на основе строк, а не полноценный анализатор HTML5. Дифференциалы парсера — входные данные, при которых браузер строит другое дерево, чем этот токенизатор — являются известной слабостью каждого дезинфицирующего средства, построенного таким образом. Для вывода, который вы создаете сами в этом редакторе, это нормально. Для очистки HTML, пришедшего от незнакомца, используйте дезинфицирующее средство, работающее с реальным парсером на сервере, который вы контролируете.
Chmod: заглавная буква — это все сообщение
Файловый режим Unix состоит из двенадцати битов: по три бита разрешения для каждого владельца, группы и других, плюс setuid, setgid и бит липкости. Восьмеричная форма представляет собой прямое чтение этих битов, поэтому 4 + 2 + 1 = 7 означает чтение, запись и выполнение.
Символическая форма, которую печатает ls, представляет интерес для специальных битов, поскольку они не имеют собственного столбца. setuid заменяет исполняемый символ владельца, setgid заменяет исполняемый символ группы, а Sticky заменяет другой исполняемый символ. Буква в нижнем регистре, если базовый бит выполнения также установлен, и в случае UPPER, если он не установлен.
Таким образом, 4755 — это rwsr-xr-x — программа с setuid, которую можно выполнить, а 4644 — это rwSr--r--, файл с setuid, который никто не может запустить. Заглавная буква S — это система, говорящая вам, что бит инертный, и это почти всегда ошибка, а не выбор. То же самое относится и к 1644, который показывает rw-r--r-T: липкий бит в обычном файле, где бит другого выполнения пуст, что в современном ядре совершенно ничего не делает.
Еще два различия, на которые стоит обратить внимание. Строка из девяти символов, которую выводит ls, не является аргументом, который принимает chmod: chmod нужен список назначений, например u=rwx,g=rx,o=rx,u+s. И одни и те же биты означают разные вещи в каталоге, чем в файле: выполнение означает «может входить и перемещаться», setgid означает «новые файлы наследуют эту группу», а бит липкости означает «любой может создавать, только владелец может удалять», что является причиной того, что /tmp имеет значение 1777.
docker run to compose: парсинг, а что не конвертирует
Конвертер разделяет команду с помощью токенизатора с поддержкой кавычек, написанного для этого инструмента. Ничего не выполняется, не оценивается и не передается в оболочку. Команда, содержащая обратные кавычки, $(...) или точку с запятой, читается как буквальные символы, поскольку единственное, что этот инструмент делает с вашими входными данными, — это читает их.
Большинство флагов сопоставляются четко: порты, тома, среда, метки, политика перезапуска, возможности, проверки работоспособности, ограничения ресурсов, DNS и дополнительные хосты — все они имеют ключи создания с одинаковым значением. Именованные тома и пользовательские сети нуждаются в объявлении верхнего уровня, а также в ссылке на службу, поэтому выходные данные содержат одно значение — с external: true в сетях, поскольку запуск сетевого докера может присоединиться к уже существующему.
Некоторые флаги не имеют составного эквивалента, и именно здесь конвертеры обычно терпят неудачу. --rm не является свойством службы: служба создания не удаляется при выходе. -d описывает, как вы вызвали CLI, а не что это за служба. --link является устаревшим, --mount требует длинной формы, которую этот инструмент не записывает, --gpus зависит от вашего драйвера. Каждое из них вместо исчезновения выдает именованное предупреждение. Неизвестный флаг также выдает предупреждение и рассматривается как не имеющий значения, поскольку догадка о том, что он принял его, превратит имя вашего изображения в аргумент и создаст заведомо неправильный файл.
В выводе отсутствует версия верхнего уровня: ключ. Compose v2 игнорирует это, а текущие версии предупреждают об этом; он устарел с тех пор, как Спецификация Compose заменила старые версии формата файла.
Цитирование не носит косметического характера. Сопоставление портов, записанное как 8080:80 без кавычек, читается как число анализаторами YAML 1.1, и да, нет, on и off — это логические значения на том же диалекте. Все, что может быть неверно истолковано, цитируется; все, что читается как строка, остается в покое, поэтому файл остается читаемым.
Крон: два правила, которые цепляют всех
Первое – это правило дня. Если для дня месяца и дня недели установлено значение, отличное от *, cron запускает задание, когда EITHER соответствует, а не когда оба совпадают. Итак, 0 0 13 * 5 — это «полночь 13-го числа и полночь каждую пятницу», то есть примерно пять раз в месяц, а не «пятница 13-го», которая бывает один или два раза в год. Генератор предупреждает, когда оба поля ограничены, и в написанном им предложении говорится «или», а не «и».
Второе — часовой пояс. Cron использует зону машины, на которой он работает, которая часто является UTC на сервере и почти никогда не является зоной человека, написавшего crontab. Поэтому при следующем предварительном просмотре будет задан вопрос, какую зону использовать, а не ваша. Время вычисляется как время на настенных часах в этой зоне, поэтому ежедневное задание остается в одном и том же местном времени при переходе на летнее время, а не смещается на час - и местное время, которое не существует, в часе, пропущенном каждую весну, исключается из списка, потому что cron тогда тоже не запустится.
Сам синтаксис небольшой: звездочка, число, диапазон a-b, список a,b,c, шаг */n или a-b/n,, а также названия месяца и дня JAN-DEC и SUN-SAT. Оба 0 и 7 означают воскресенье. Простое значение с шагом, например 5/15 в поле минут, означает «от 5 до конца диапазона каждые 15», что соответствует минутам 5, 20, 35 и 50.
Проверка намеренно строгая. 60 * * * * отклоняется, поскольку минуты заканчиваются на 59; * * * * 8 отклоняется, поскольку поле дня заканчивается на 7; */0 * * * * отклоняется, поскольку нулевой шаг ничему не соответствует. Шесть полей обычно означают выражение Quartz или systemd, первое поле которого — секунды, поэтому ошибка говорит об этом, а не только о подсчете. Расписание, которое синтаксически допустимо, но никогда не может быть запущено — 0 0 30 2 * запрашивает 30 февраля — принимается и помечается, поскольку отказываться от него было бы неправильно, а молчать было бы еще хуже.
Что происходит с тем, что вы вставляете
- Каждое преобразование, хеширование, декодирование и различие выполняются на вкладке вашего браузера. Никакие входные данные не загружаются, не регистрируются и не сохраняются на сервере, поскольку после загрузки страницы сервер не задействован.
- Хэши берутся из собственной реализации Web Crypto в браузере, а UUID — из криптографически безопасного генератора случайных чисел. Ни один из них не предполагает сетевой вызов.
- Ничего из того, что вы вводите, не записывается в локальное хранилище или файл cookie. Перезагрузка страницы удаляет ее; закрытие вкладки отменяет ее.
- Аналитика в масштабе всего сайта выполняется только на настроенном каноническом рабочем хосте и описана в Политике конфиденциальности; локальные и предварительные хосты отказываются от этого. Вставленные значения, токены, URL-адреса и содержимое файлов исключаются из собственных аналитических событий ToolAcre. Реклама отключена в текущей конфигурации.
- Тем не менее: ключ JWT или API — это действующие учетные данные. Безопасная привычка — никогда не вставлять его на веб-страницу, которую вы не писали, какими бы заслуживающими доверия ни были его утверждения, включая эту.
Вопросы
Могу ли я вставить враждебный HTML в редактор, чтобы очистить его?
Вы можете вставить его, и ничего не произойдет: обработчик вставки очищает полезную нагрузку буфера обмена перед тем, как что-либо будет вставлено, а предварительный просмотр представляет собой изолированный iframe без разрешающих сценариев. Но не используйте результат в качестве средства контроля безопасности для ненадежного ввода. Это строковый список разрешений для собственных результатов одного редактора, а не фильтр общего назначения XSS, и анализатор браузера может обращаться к другому дереву, чем токенизатор, подобный этому. Ненадежный контент необходимо очистить на сервере с помощью настоящего анализатора HTML5.
Почему редактор удаляет мои изображения и таблицы?
Потому что их нет в белом списке. Изображения — это исходящий запрос и поверхность ошибки; таблицы просто выходят за рамки того, для чего предназначен этот редактор. Их текстовое содержимое сохраняется, а теги — нет. Это работающий список разрешений, а не ошибка, но это означает, что это неправильный инструмент для редактирования сложного существующего документа.
Почему chmod 4644 показывает заглавную букву S?
Потому что setuid установлен, а бит выполнения владельца — нет. Заглавная буква означает, что специальный бит не на что воздействовать: это файл setuid, который не может быть выполнен. Нижний регистр s означает, что оба бита установлены. То же правило дает вам S для setgid и T для липкого бита, и получение его наоборот — самая распространенная ошибка в калькуляторах режимов.
Конвертер докеров выполняет мою команду?
Нет, и не может. Команда разделяется токенизатором, который понимает цитирование и ничего больше. Здесь нет ни eval, ни оболочки, ни дочернего процесса — страница не имеет возможности его запустить. Все, что вы вставляете, остается на вкладке.
Почему конвертер предупреждает, а не просто сбрасывает флаг, с которым он не может справиться?
Потому что файл компоновки, который молча делает меньше, чем команда, из которой он был получен, хуже, чем вообще отсутствие вывода: вы узнаете это в производстве. Каждому флагу, который не представлен, присвоено имя и указано, что с ним делать. Если вы не видите предупреждений, ничего не потеряно.
Почему следующий запуск cron отличается от того, что делает мой сервер?
Почти всегда часовой пояс. Cron использует зону машины, на которой он работает; при предварительном просмотре используется зона, которую вы выбрали в раскрывающемся списке. Установите его в зону вашего сервера — часто UTC — и они должны согласиться. Другим кандидатом является правило дня: если установлены и день месяца, и день недели, cron запускается в любом из них, что происходит чаще, чем предполагает большинство людей.
Ограничения
- Санитайзер HTML — это список разрешений для собственного вывода этого редактора, реализованный как строковый токенизатор, а не полный синтаксический анализатор HTML5. Это не универсальный фильтр XSS, и его нельзя использовать в качестве такового.
- В редакторе нет изображений, таблиц, цветов и элементов управления шрифтами, а также нет возможности их добавлять: все, что находится за пределами белого списка, удаляется.
- Область редактирования использует document.execCommand, который устарел и не имеет реализованной замены. Браузеры по-прежнему поддерживают его; поведение между ними немного различается, особенно в отношении вложенности списков.
- Калькулятор chmod охватывает только двенадцать битов разрешения. Списки контроля доступа, расширенные атрибуты, контексты SELinux, арифметика umask и списки управления доступом Windows — все это выходит за рамки.
- Конвертер Docker преобразует одну команду запуска Docker в один сервис. Он не читает файлы Dockerfile, не разрешает изображения и не может выражать --mount, --gpus, --device, --link или --volumes-from; каждый из них вместо этого выдает именованное предупреждение.
- Флаги, которые преобразователь не распознает, считаются не имеющими значения. Если такой флаг все-таки принял один, значение будет неправильно прочитано — об этом говорится в предупреждении, и удаление флага — это исправление.
- Генератор cron читает только формат crontab из пяти полей. Шестиполевые выражения Quartz и systemd, @reboot и нестандартные L, W, # и ? операторам отказывают, а не догадываются.
- Время следующего запуска берется из собственной базы данных часовых поясов браузера через Intl. Это предварительный просмотр, а не гарантия: на машине, на которой запущен cron, может быть другая зона, другая версия базы данных или демон, который не работал, когда пришло время.