Как следует дезинфицировать ненадежный JSON перед использованием JSON.parse?

Учитывая предоставленную пользователем строку JSON, как мы можем очистить ее перед запуском JSON.parse(untrustedString)?

Меня в первую очередь беспокоит загрязнение прототипа, но мне также интересно, на что еще я должен обращать внимание? Если риск представляет собой просто загрязнение прототипа, то я предполагаю, что с этим можно справиться с помощью регулярных выражений, но я подозреваю, что есть дополнительные проблемы?

Например, эта статья об опасностях анализа ненадежного JSON. а затем создать копию объекта.:

Теперь рассмотрим некоторые вредоносные данные JSON, отправленные на эту конечную точку.

{
  "user": {
    "__proto__": {
      "admin": true
    }
  }
} 

Если этот JSON отправлен, JSON.parse создаст объект со свойством __proto__. Если копирующая библиотека работает так, как описано выше, она скопирует свойство admin в прототип req.session.user!


person Slbox    schedule 16.09.2020    source источник
comment
json почти всегда должен быть безопасным для анализа.   -  person Daniel A. White    schedule 16.09.2020
comment
Это было мое первоначальное впечатление, но чем больше я читал, тем больше я становился параноиком. Нельзя ли JSON.parse() допустить загрязнение прототипа объекта?   -  person Slbox    schedule 16.09.2020
comment
я не думаю, что это возможно, но это может создать искаженный объект   -  person Daniel A. White    schedule 16.09.2020
comment
Я добавил статью с примером одной из моих проблем в текст вопроса.   -  person Slbox    schedule 16.09.2020
comment
ах, это просто говорит о том, что через __proto__ могут появиться дополнительные свойства, и вы должны остерегаться этого - ничего, что JSON.parse делает неправильно...   -  person Daniel A. White    schedule 16.09.2020


Ответы (2)


Меня больше всего беспокоит загрязнение прототипа

Обратите внимание, что JSON.parse не будет загрязнять какой-либо объект-прототип. Если в строке JSON есть ключ "__proto__", то этот ключ будет создан так же, как и любой другой ключ, и каким бы ни было соответствующее значение в этом JSON, оно в конечном итоге станет значением этого свойства, а не объектом-прототипом (Object.prototype) .

Риск заключается в том, что вы делаете с этим объектом потом. Если вы выполняете (глубокую) копию с присвоением свойств или Object.assign, тогда вы потенциально можете изменить объект-прототип.

как мы можем очистить его перед запуском JSON.parse(untrustedString)? ... Я предполагаю, что это можно было бы обработать с помощью регулярных выражений

Не используйте для этого регулярное выражение. Используйте второй аргумент JSON.parse:

const cleaner = (key, value) => key === "__proto__" ? undefined : value;

// demo
let json = '{"user":{"__proto__":{"admin": true}}}';

console.log(JSON.parse(json));
console.log(JSON.parse(json, cleaner));

person trincot    schedule 16.09.2020

Прежде чем вы что-либо с ним сделаете, userString — это просто строка, и ничто в этой строке само по себе не может нанести вред системе, если только система не делает что-то, чтобы допустить этот вред, например, обрабатывает его в небезопасном способ.

Введите JSON.parse().
JSON.parse() — это просто инструмент преобразования формата. Он не запускает какие-либо методы из данных (на которые опираются эксплойты протозагрязнения) и даже не просматривает данные, содержащиеся в самом строковом объекте, помимо содержащийся в нем структурный синтаксис и зарезервированные слова JavaScript для целей проверки (пример полифилла MDN). Здесь применяется тот же принцип, что и со строкой; если вы не сделаете ничего небезопасного с выходным объектом, это не навредит ни вам, ни вашей системе.

В заключение отметим, что решение по предотвращению злоупотреблений — это простая проверка и безопасная обработка данных.
Проверяйте объект, полученный в результате синтаксического анализа строки, и проверяйте его в рамках строгих правил. параметры, игнорируя мутации прототипа.
Используйте Object.prototype.hasOwnProperty.call().
Применяйте эти методы в своей кодовой базе с помощью инструментов как eslint (правило no-prototype-builtins).
Don не ожидайте, что пользователи отправят точные и безопасные данные.

В статье, на которую вы ссылаетесь, автор упоминает эту точную идею:

...данные, поступающие от пользователей, всегда должны фильтроваться и очищаться.

person zcoop98    schedule 16.09.2020
comment
Данные всегда безвредны; это плохо подготовленный код, который делает плохие вещи, когда подается странный ввод, — это трюизм. Тем не менее, лучше перестраховаться, чем потом сожалеть, и применять здесь также глубокую защиту (дезинфицировать рано и часто). Поэтому использование cleaner, описанного @trincot выше, является хорошей идеей. - person Marcel Waldvogel; 26.07.2021