Если вы специалист по объектам и прототипам JavaScript, вы можете двигаться дальше и узнать больше о загрязнении прототипов с реальным примером и мерами защиты здесь.
Понимание того, что такое прототипы JavaScript (часть 1)
Загрязнение прототипа, вероятно, является знакомой категорией уязвимостей, связанных с JavaScript, в большинстве программ вознаграждения за обнаружение ошибок. Однако она не очень хорошо задокументирована, как и другие распространенные уязвимости, такие как SQLi, XSS, внедрение команд и т. д. Эта конкретная уязвимость может привести к серьезным последствиям, таким как компрометация сервера и клиента. Prototype Pollution влияет на языки, основанные на прототипах (но в первую очередь на JavaScript). Весьма вероятно, что по крайней мере один из продуктов создан с использованием JavaScript; следовательно, важно убедиться, что приложения свободны от этой уязвимости.
История загрязнения прототипа:
Эта уязвимость была обнаружена исследователями безопасности только после 2017 года и первоначально наблюдалась в Lodash, пакете NPM и этой DOS-атаке. Мы знаем, что Lodash имеет очень высокую популярность, поскольку он используется многими приложениями и, следовательно, представляет огромную угрозу.
Объекты JavaScript:
Прежде чем углубляться в загрязнение прототипов, давайте разберемся, что такое и как работают объекты JavaScript. Подобно другим языкам программирования, javascript также содержит примитивные типы данных, такие как числа, массивы, строки и, кроме того, объекты. Рассмотрим пример объекта — человека. Мы можем создать объект,
вар человек = {}
Если мы хотим добавить некоторые свойства к этому объекту,
var person = {имя: «Алекс»}
Мы можем получить доступ к этому свойству, используя один из двух способов ниже:
человек.имя
or
человек ["имя"]
Мы можем продолжать добавлять свойства к объекту «человек»,
человек.возраст = «27»
Давайте рассмотрим еще одну концепцию под названием Функции-конструкторы. Они похожи на обычные функции javascript с точки зрения синтаксиса. На рисунке ниже показано, как выглядит функция-конструктор.
Эти функции-конструкторы используются для создания новых объектов, в отличие от обычных функций, и выполняются с помощью ключевого слова «new». Это похоже на «var person = {name: name, age: age}», которое мы видели ранее.
Каждая переменная, используемая вместе с ключевым словом «this» внутри функций-конструкторов, является свойствами, которые добавляются к созданным объектам.
человек1 = новый человек («Алекс», 27);
Здесь объект person1 будет содержать два свойства — имя и возраст с соответствующими значениями.
человек2 = новый человек («Боб», 20);
Объект person2 также будет содержать те же свойства, что и person1, но значения зависят от того, что передается. Здесь имя Боб и возраст 20.
Свойства конструктора — это ссылка на функции конструктора, которые мы использовали для создания объектов. Чтобы получить доступ к функции конструктора объекта person1,
человек1.конструктор
Это вернет функцию-конструктор объекта person1.
Теперь, если мы хотим добавить больше свойств к нашему объекту person1,
Поскольку новый пол свойства создается для человека1, он неприменим для человека2.
В таких случаях на помощь приходят прототипы!
Свойства, к которым мы хотим получить доступ всеми созданными объектами, могут быть добавлены в прототип. См. следующие два примера:
«пол» теперь добавлен в прототип функции-конструктора и, следовательно, теперь доступен для всех объектов (даже для вновь созданных).
Другой способ добавления новых свойств в прототип объекта показан ниже.
Новый объект person4 теперь имеет доступ к обоим свойствам — State и gender.
Прототип цепи:
Давайте посмотрим дальше на объект person4:
Помимо определенных свойств возраста и имени, у нас есть еще одно свойство под названием «[[Prototype]]».
Если мы расширим прототип, он будет содержать внутри себя как свойства пола, так и свойства состояния, как мы и определили. Мы можем получить доступ к прототипам любого объекта с помощью переменной с именем «__proto__». Поскольку объекты — person1, person2, person3 и person4 и любые объекты, созданные с помощью person, создаются из одной и той же функции-конструктора, все они имеют общие прототипы.
Мы используем «Object.getOwnPropertyNames(object)» для просмотра свойств, связанных с каждым объектом. Так как мы определили свойства gender и State непосредственно для объектов person1 и person2 соответственно, они отображаются напрямую. Но для person3 и person4, поскольку они сами по себе не обладают свойствами, они далее спускаются на уровень своего прототипа и проверяют те же свойства.
Это называется цепочкой прототипов. Так продолжается до тех пор, пока не будет найден ни один прототип. Это означает, что мы находимся на вершине цепочки прототипов, и в таком случае возвращается null.
С нашим пониманием, основанным на всех вышеизложенных концепциях, теперь можно сделать следующее присвоение прототипу любого объекта.
Любое новое свойство можно добавить прямо в глобальный прототип. Теперь мы создадим новый объект под названием «автомобиль» и попытаемся получить доступ к этому свойству.
Поскольку это свойство присутствует в глобальном прототипе, каждый объект может получить к нему доступ. Вот как работает прототип загрязнения.
Во второй части мы более подробно рассмотрим, как можно использовать это свойство прототипа в режиме реального времени.
Спасибо за прочтение! Дайте мне знать ваши ценные комментарии, если я пропустил что-то добавить здесь :)
Хорошей охоты :)