Обновление анализа неуязвимости Koa.js
Не так давно я писал об уязвимости , которая затронула Koa.js в 2018 году. Я был разочарован тем, что мне пришлось иметь дело с проблемой из 2018 года, а дата была 2022 года, и я использовал последнюю версию Koa. Прошло 4 года. Это долго. Проблема точно не в нем!? И было и не было одновременно. Значит, я ошибался и был прав одновременно. Итак, вот обновление к предыдущему посту, чтобы рассказать вам, как:
- Я неправомерно обвинил Sonatype и Dependency Track в том, что они не работают с информацией о версии в определенных случаях.
- Я могу быть прав и не прав одновременно относительно уязвимости
Индекс OSS содержит информацию о версии
Если вы читали мой предыдущий пост, вы, вероятно, помните, что я пришел к выводу, что проблема не повлияла на меня. Хорошая новость в том, что я был прав. Плохая новость заключается в том, что я ошибочно обвинил Sonatype в отсутствии номеров версий в данных, предоставленных OSS Index для работы с Dependency Track. Оказывается, у них есть информация. Его просто не было видно там, где я ожидал, что оно должно быть видно. Смотрите скриншот ниже, сделанный 22.11.2022.

Вполне вероятно, что Dependency Track (DT) не работает именно с тем, что отображается на странице выше, но я не стал проверять, как выглядят данные, которые DT извлекает из индекса OSS. DT только что показал ссылку на индекс OSS, где я мог бы узнать больше. Я нажал и попал на эту страницу.
Сегодня Sonatype обратила мое внимание на то, что номера версий доступны; Я должен искать в другом месте. Действительно, если вы войдете в свою учетную запись и либо выполните поиск Koa, либо нажмете кнопку «Посмотреть подробности для koa» на приведенном выше снимке экрана, вы сможете ее найти. Смотрите скриншот ниже.

Так что я был неправ. У Sonatype есть информация в базе данных. Значит, проблема в уровне представления. Было бы лучше, если бы уязвимые версии были перечислены на странице, где фактически обсуждается уязвимость, чтобы мы могли увидеть и проверить, если это необходимо.
Я ошибочно обвинил Sonatype OSS Index в отсутствии информации о версии. Я также неправомерно обвинил Dependency Track в том, что он готов сообщать исключительно на основе имени зависимости, если информация о версии недоступна. (Мне еще нужно выяснить, верно последнее или нет, я не проверял.)
Не сдавайтесь пока! Более интересными вещами для обсуждения являются фактическая уязвимость и (надеюсь) предстоящие изменения в отчете об уязвимостях в OSS Index. Начнем с уязвимости.
Межсайтовый скриптинг
Sonatype приписала XSS Koa, основываясь на приведенном ниже мыслительном процессе.
Koa — это объект, который записывает URL-адрес в ответ HTML, а не разработчик, использующий Koa.
Определенно разумно ожидать, что разработчик проверит предоставленный URL-адрес, вероятно, по списку разрешений, чтобы предотвратить открытое перенаправление, а не Koa, поскольку Koa не будет знать, какие URL-адреса вы хотите разрешить или нет. Однако, как разработчик, я не думаю, что мне нужно беспокоиться о очистке XSS для URL-адреса, который я передаю методу redirect().
Koa, кажется, заботится о XSS в этом контексте, поскольку у них уже есть код, чтобы предотвратить это, объект HTML, кодирующий URL-адрес, когда они записывают его в HTML
Я согласен до некоторой степени. Я не согласен со следующим, например.
Я не думаю, что мне нужно беспокоиться о санации XSS для URL-адреса, который я передаю методу redirect()
Если вы передаете действительный безопасный URL-адрес методу перенаправления, который вы (разработчик) предоставили, вам не нужно беспокоиться о XSS (очевидно). Если вы полностью или частично передаете предоставленные пользователем данные, об этом всегда следует беспокоиться, независимо от того, являетесь ли вы разработчиком или специалистом по безопасности. Тем не менее, можно ожидать, что Koa поможет разработчику.
Позвольте мне привести вам отличный пример, который, надеюсь, поможет понять, откуда я пришел. В приведенном ниже примере я передаю предоставленные пользователем данные обратно в браузер в теле ответа. Я делаю это без какой-либо проверки, очистки или кодирования.
const Koa = require('koa');
const app = new Koa();
app.use(async ctx => {
ctx.body = ctx.query.payload;
});
app.listen(4444);
* Trying 127.0.0.1:4444...
* Connected to 127.0.0.1 (127.0.0.1) port 4444 (#0)
> GET /?payload=<img%20src=x%20onerror=alert(1)> HTTP/1.1
> Host: 127.0.0.1:4444
> User-Agent: curl/7.79.1
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Content-Type: text/html; charset=utf-8
< Content-Length: 28
< Date: Wed, 23 Nov 2022 10:59:17 GMT
< Connection: keep-alive
< Keep-Alive: timeout=5
<
* Connection #0 to host 127.0.0.1 left intact
<img src=x onerror=alert(1)>%
- Подумайте, что и как я передаю браузеру в теле ответа
- Учитывайте (и, вероятно, лучше всего явно контролировать!) значение заголовка Content-Type для ответа.
- Знайте, что Koa по умолчанию автоматически корректирует значение заголовка Content-Type на основе значения, переданного в
ctx.body
. (Попробуйте передать, напримерaaa
, и посмотрите, как это изменится)
Учитывая приведенный выше ctx.body
пример «XSS», все звучит так, как будто мы обвиняли Koa в реализации конкретных мер по предотвращению катастрофы при использовании ctx.redirect()
. Снова цитирую Sonatype:
Koa, кажется, заботится о XSS в этом контексте, поскольку у них уже есть код.
Означает ли это, что если бы Koa не заботилась о XSS в этом контексте, точно так же, как они не заботились (и не должны) об этом, когда дело доходит до ctx.body
, никто бы не пометил это как уязвимость XSS? Это довольно забавно. Я заметил некоторое сходство с моим более ранним анализом о Formidable, задокументированным здесь и здесь .
Сказав все, что я сказал до сих пор, XSS оказался там… и не в то же время. Как это возможно? Простой! Он есть, но вы не можете использовать его, если:
- Жертва использует старый веб-браузер, И
- Существует открытое перенаправление, реализованное разработчиком с использованием Koa
ctx.redirect()
, И - Разработчик полностью доверяет всем предоставленным пользователем данным и дословно передает их
ctx.redirect()
На странице отчета Sonatype сказано, как вы можете видеть на сегодняшнем снимке экрана: «Открыть перенаправление, ведущее к межсайтовому скриптингу». В моем предыдущем посте была поставлена под сомнение часть «открытого перенаправления»:
Во-первых, не было открытого редиректа. Он открывается только в том случае, если вы его открываете, и разница между двумя PoC (оригинальным и моим) ясно показывает это.
Sonatype также соглашается с тем, что Koa не несет ответственности за предотвращение открытых перенаправлений. Их забота, моя забота и главная забота всех остальных — это XSS. Использование открытого перенаправления было просто запутанным. В то же время технически это не было необоснованным, как мы увидим позже. (Это также повлияет на оценку уязвимости.)
Как упоминалось ранее, для успешного использования поведения Koa требуется открытая переадресация. Но:
- Koa не несет ответственности за предотвращение открытых перенаправлений (как было сказано ранее)
- Koa не будет выполняться
ctx.redirect()
без разрешения разработчика - Koa не заставляет разработчиков использовать редиректы
Итак, есть еще один уровень защиты: варианты использования. Насколько вероятно, что разработчик не захочет контролировать, куда перенаправляется браузер? Очень маловероятно. Это означает, что, скорее всего, разработчики будут передавать данные, контролируемые пользователем, в ctx.redirect()
добавление к другому фрагменту строки. Таким образом, скорее всего, произойдет что-то похожее на примеры, показанные ниже:
ctx.redirect(`http://website.example.org/search?q=${userInput}`);
ctx.redirect(`/search?topic=${userInput}`);
Оценка уязвимостей
Чтобы ошибку можно было использовать, должны быть соблюдены три (3) условия, как обсуждалось в конце предыдущего раздела.
- Какая версия браузера используется, зависит от конечного пользователя
- Использование метода перенаправления и то, как он используется, зависит от разработчика.
Что также требует особого внимания, так это то, что небезопасное использование метода перенаправления является вектором атаки. Для успешной эксплуатации необходим вектор атаки. Koa не предоставляет вектор атаки; разработчик делает.
Сопоставим это с определением «уязвимости программного обеспечения», предоставленным NIST:

Часть, которую я хотел бы выделить, «может быть использована». Возьмите Koa в качестве библиотеки программного обеспечения. Можно ли использовать его без предварительного создания необходимого вектора атаки? Нет. Итак, с точки зрения Koa, программной библиотеки, вектор атаки не представлен; без этого эксплуатация невозможна. Если бы мы строго интерпретировали определение (что я и делаю), мы не могли бы назвать поведение Коа уязвимостью.
Давайте попробуем рассчитать оценку CVSS без вектора атаки:

Нет очков, если нет вектора атаки. Я бы сказал, что это соответствует определению уязвимости программного обеспечения, предоставленному NIST.
Давайте поэкспериментируем и создадим воображаемый сценарий, в котором существует вектор атаки.

Здесь есть еще несколько проблем, кроме воображаемого вектора атаки. Сложность атаки была установлена на «Высокая», поскольку для успешной эксплуатации требуется старый браузер. Злоумышленник должен убедить жертв загрузить и установить старый браузер.
В этом смысле требуется взаимодействие с пользователем, хотя базовые показатели взаимодействия с пользователем на самом деле не об этом. В этом сценарии то, требует ли использование XSS взаимодействия с пользователем, зависит от того, как веб-приложение использовало перенаправления, а не от Koa. Также стоит упомянуть, что внедренный JavaScript не будет выполняться сам по себе, поскольку в первую очередь требуется взаимодействие с пользователем: щелчок по ссылке в ответе HTML.
Итак, что мы можем сделать, чтобы принудительно присвоить этому показателю уязвимость? Мы должны что-то выбрать. Принятие желаемого за действительное, предполагая худшее, что вы предпочитаете. Одно можно сказать наверняка: вы делаете вычисления, которые не должны делать изначально, и результат настолько далек от реальности, что я даже не могу подобрать для него слов.
Следующая важная вещь — это Impact Metrics. Вы должны знать, что веб-приложение собирается сказать о влиянии. Но мы не рассчитываем оценку уязвимости для веб-приложения… Учитывая контекст, этот XSS не оказывает никакого влияния на Koa. Koa не обрабатывает и не обрабатывает конфиденциальную информацию самостоятельно. Ошибка не влияет на доступность или целостность. Это оставляет нас с окончательным счетом 0,0, даже после принудительного включения вектора атаки в расчет.

Итак, вопрос в том, сообщаем ли мы факты или вымысел?
Sonatype обратила мое внимание на официальное руководство по подсчету уязвимостей в программных библиотеках , которое было выпущено в 2019 году вместе с CVSSv3.1. Признаюсь, я не знал об этом, что и хорошо, и плохо. Хорошо, потому что это привело бы к разглагольствованию, плохо, потому что, возможно, если бы я увидел это раньше, я потерял бы всякую надежду, прежде чем приложил бы столько усилий, пытаясь объяснить, что это неправильный способ. Итак, что говорит официальное руководство?
При оценке воздействия уязвимости в библиотеке… Аналитик должен оценивать разумный наихудший сценарий реализации. Когда это возможно, информация CVSS должна детализировать эти предположения.
Таким образом, ответ заключается в том, что оценка уязвимости основана на вымысле.
Кроме того, что такое « разумный наихудший сценарий реализации»? Если мы проанализируем множество проектов, использующих Koa, и обнаружим, что большинство разработчиков реализовали открытые перенаправления с использованием ctx.redirect()
метода Koa, было бы разумно предположить худшее. Я сделал быстрый поиск кода в проектах JavaScript ctx.redirect(
на GitHub. Я получил 16 827 результатов кода. При поиске context.redirect(
я получил 15 751 результат кода. Это будет 32 578 результатов кода для анализа. Некоторые из них будут использовать Koa, некоторые Express, а некоторые могут быть чем-то еще. (Конечно, контекст может быть вызван любым именем, а не только ctx
или context
, так что может быть еще больше кода для просмотра.)
Возникает вопрос: так ли часто бездумно передаются предоставленные пользователем данные для перенаправления? Я применил полуавтоматический подход к анализу, написав небольшой скрипт для проверки всех проектов, соответствующих критериям поиска. К сожалению, я не смог пройти первую тысячу обращений, так как GitHub отклонил дальнейшие запросы:
{
"message":"Only the first 1000 search results are available",
"documentation_url":"https://docs.github.com/v3/search/"
}
Основываясь на том, что я видел, и принимая во внимание то, что обсуждается в следующем разделе («Старый веб-браузер»), я не думаю, что было бы разумно предполагать наихудшую реализацию. Не в этом конкретном случае.
В официальном руководстве также говорится, что:
При оценке уязвимости в данной реализации с использованием затронутой библиотеки оценка должна быть пересчитана для этой конкретной реализации.
Это разумно и несколько смягчает научно-фантастический аспект ситуации. Вот как проблема Koa с оценкой уязвимости 9,8 в нашем случае оказалась равной 0,0.
Хорошо, что Sonatype согласилась с тем, что оценка уязвимости 9,8 была необоснованной, и они готовы ее снизить. Я ценю это, и, вероятно, многие другие тоже.
Кроме того, представители Sonatype сказали мне, что, добавляя проблему в свою систему, они считали, что будет лучше, если их клиенты узнают об этой потенциально неожиданной ситуации. Они сказали: «Лучше предупредить, чем игнорировать то, что мы видели, и потенциально иметь негативный результат». И, конечно же, они были правы.
Я никогда не задавался вопросом, следует ли сообщать о проблемах безопасности или нет. Да, проблемы безопасности должны быть видны. Что меня беспокоит, так это то, как эти проблемы сообщаются:
- Уместно ли называть что-то уязвимостью или более уместно называть это слабостью безопасности или небезопасным поведением по умолчанию и так далее?
- Является ли присвоенная оценка уязвимости разумной?
- Достаточно ли подробностей и контекста предоставлено?
Теперь давайте немного поговорим о старых веб-браузерах.
Старый веб-браузер
Без добрых людей из Sonatype я бы и не подумал о старых веб-браузерах, возможно, когда-нибудь снова.
Я продолжу не рассматривать старые браузеры и в будущем. Во-первых, нужно помнить слишком много вещей; Я не могу беспокоиться о старых веб-браузерах. Во- вторых, сколько лет ( не нажимайте на ссылку, если у вас нет чувства юмора! ) старому веб-браузеру? Что на самом деле означает «старый»? Если кто-то использует браузер возрастом около 1 года, вполне вероятно, что у него уже есть гораздо более серьезные проблемы, чем XSS.
Тем не менее, я немного покопался и обнаружил, что:
- Google Chrome 48.0.2564.109 (64-разрядная версия) 2016 года (!) даже не отображал тело ответа. Поскольку проблема с Koa была обнаружена в 2018 году, я подумал, что достаточно вернуться к 2016 году, но оказалось, что это не так.
- Firefox 4.0 2011 года действительно отображал тело ответа, но для выполнения полезной нагрузки JavaScript требовалось, чтобы пользователи щелкнули ссылку. (Конечно, это ссылка!)
- Firefox 52.0 от 2017 года, за 1 год до сообщения о проблеме Koa XSS, уже не отображал тело ответа с полезной нагрузкой JavaScript. Firefox только что выдал ошибку «Ошибка поврежденного содержимого» из-за «нарушения сетевого протокола».
Koa 0.0.1 был выпущен в 2013 году, поэтому было несколько лет, когда эту проблему можно было использовать. На данный момент, вероятно, было бы приемлемо отметить эту проблему (все еще не с оценкой 9,8) до Koa 2.5.0 в 2018 году. Однако после этого ничто не оправдывает ничего выше 1.0.
Пока копался, нашел кое-что интересное в Википедии . Позвольте мне процитировать:
Firefox 15 был выпущен 28 августа 2012 года… В Firefox 15 были представлены автоматические обновления, автоматическое обновление, которое обновит Firefox до последней версии без уведомления пользователя, [65] функция, которую имеют веб-браузеры Google Chrome и Internet Explorer 8 и выше . уже реализовано
Таким образом, все основные веб-браузеры имели функцию автоматического обновления до того, как была выпущена первая версия Koa, а это означает, что есть вероятность, что большинство пользователей использовали современный веб-браузер. Посмотрим состояние на момент «большого взрыва»: 2013 год.
- Firefox 15 : вернул сообщение об ошибке «Ошибка поврежденного содержимого», означающее, что текст ответа не был показан пользователю.
- Chrome 24.0.1312 (WebKit 537.17) : тело ответа не отображалось. При просмотре вкладки сети инструментов разработчика почти ничего не было видно, поэтому мне пришлось запустить Wireshark, чтобы увидеть, выполнил ли браузер запрос в первую очередь. В Wireshark было видно, что Chrome обратился к моему PoC-сервису и получил ответ с полезной нагрузкой JavaScript. Он не отображал тело ответа. Даже лучше, ничего не произошло.
- Internet Explorer 11 (11.0.9600.19180) : он получил ответ от моей службы PoC, которую я проверил с помощью Wireshark. Он не показывал тело ответа пользователю. Он вернулся с классической встроенной страницей ошибки, которая гласит: «Эта страница не может быть отображена».
Проведя вышеуказанное исследование, давайте на секунду вернемся к цитате из Sonatype:
Koa, кажется, заботится о XSS в этом контексте, поскольку у них уже есть код, чтобы предотвратить это, объект HTML, кодирующий URL-адрес, когда они записывают его в HTML
Хотя это утверждение верно, тот факт, что ни один из основных браузеров не допускал эксплуатации ко времени выпуска первой версии Koa, цитирует нечто интересное, нечто иное, чем то, на что намекает данное предложение. Обратите внимание, что я собираюсь написать предположение, поскольку я не могу точно знать, как думали разработчики Koa. Я легко могу себе представить, что разработчик(ы) проверял рассматриваемое поведение с помощью современного веб-браузера. Возможно, они обнаружили, что HTML-кодировка подходит, потому что уже было невозможно внедрить код JavaScript, выполняемый из href
свойства объекта.a
тег. Это поднимает серьезный вопрос. Потратив последние пять лет больше на разработку программного обеспечения, это также относится и ко мне: как к разработчику, если я собираюсь создать новую веб-технологию для серверной части, должен ли я заботиться о старых веб-браузерах? И если я должен, какова официальная рекомендация сообщества безопасности относительно того, насколько далеко назад во времени я должен рассматривать старые веб-браузеры? Разве мы не должны учитывать, что лучшая практика безопасности для конечных пользователей заключается в том, чтобы поддерживать свои браузеры в актуальном состоянии, и функция автоматического обновления также помогает в этом? Кроме того, если мы ожидаем, что разработчики будут иметь в виду и тестировать старые браузеры, можем ли мы ожидать, что специалисты по безопасности будут делать то же самое и называть все веб-браузеры и их версии, которые способствуют возникновению конкретной проблемы, вместо того, чтобы просто ссылаться на «старые браузеры». ”? Это было бы справедливо.
Одно можно сказать наверняка, уже много лет не о чем беспокоиться…
Современный браузер
В своем анализе, используя веб-браузер, я проверил тело ответа и обнаружил, что оно пусто. Я не проверял, имел ли ответ, отправленный по сети, тело. Оказывается, только Google Chrome полностью проигнорировал тело ответа; поэтому и не показывал. Этого было достаточно для меня. Разумно, должен добавить.
С тех пор я просматривал ответ своего тестового веб-сервиса, используя последнюю версию Koa. Ниже мы видим, что там было тело ответа HTML с внедренным кодом JavaScript:
* Trying 127.0.0.1:4444...
* Connected to 127.0.0.1 (127.0.0.1) port 4444 (#0)
> GET /?payload=javascript:alert(1); HTTP/1.1
> Host: 127.0.0.1:4444
> User-Agent: curl/7.79.1
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 302 Found
< Location: javascript:alert(1);
< Content-Type: text/html; charset=utf-8
< Content-Length: 71
< Date: Tue, 22 Nov 2022 17:55:12 GMT
< Connection: keep-alive
< Keep-Alive: timeout=5
<
* Connection #0 to host 127.0.0.1 left intact
Redirecting to <a href="javascript:alert(1);">javascript:alert(1);</a>.
* Trying 127.0.0.1:4444...
* Connected to 127.0.0.1 (127.0.0.1) port 4444 (#0)
> GET /?payload=%22><%2f HTTP/1.1
> Host: 127.0.0.1:4444
> User-Agent: curl/7.79.1
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 302 Found
< Location: %22%3E%3C/
< Content-Type: text/html; charset=utf-8
< Content-Length: 61
< Date: Tue, 22 Nov 2022 22:18:49 GMT
< Connection: keep-alive
< Keep-Alive: timeout=5
<
* Connection #0 to host 127.0.0.1 left intact
Redirecting to <a href=""></">"></</a>.
Предстоящие изменения
Ниже приведен список обновлений, которые Sonatype планирует внедрить в связи с этой проблемой:
- Обновление строки Summary/Title для устранения недоразумений (уже произошло)
- Снижение оценки уязвимости до 4,7 (уже произошло)
- Упомяните, что уязвимость может быть использована только в том случае, если пользователь использует более старый браузер.
Дополнительные изменения, которые я хотел бы увидеть
Помимо изменений, упомянутых в предыдущем разделе, можно было бы улучшить еще несколько вещей. Эти:
- Дальнейшее снижение оценки уязвимости, особенно для версий Koa, выпущенных после 2018 года.
- Включая номер версии по крайней мере основных веб-браузеров и даты их выпуска, включенные в отчет, когда речь идет о «старых браузерах». Это значительно поможет любому при «оценке уязвимости в данной реализации с использованием затронутой библиотеки». Например, если бы я увидел, что пользователю пришлось использовать браузер 2011 года, я бы в течение секунды отметил проблему как «не затронутую» в SCA. Сэкономлено много времени.
- Уязвимые версии Koa должны быть перечислены на странице уязвимости .
Кстати, Sonatype также упомянула, что в их коммерческом предложении есть несколько интересных проверок, которые, например, выполняют фактические проверки на уровне кода, чтобы увидеть, не пострадало ли приложение из-за обнаруженных уязвимостей. Звучит неплохо, и, учитывая научно-фантастический характер того, как вычисляются оценки уязвимостей для библиотек, такие проверки просто необходимы, чтобы снизить нагрузку на команды инженеров, особенно если так будет продолжаться.
Заключение
Это почти все обновления, которые у меня есть. Я рад, что связался с Sonatype, потому что они очень профессиональны и дружелюбны. Было приятно работать с ними над этим.
Что касается XSS в Koa: это то, о чем никто из нас не должен был беспокоиться уже несколько лет.