Безопасный анализ строки JSON с ключами без кавычек

json2.js требует, чтобы все ключи объектов заключались в двойные кавычки. Однако в синтаксисе Javascript {"foo":"bar"} эквивалентно {foo:"bar"}.

У меня есть текстовая область, которая принимает ввод JSON от пользователя и хотела бы «ослабить» ограничение на двойное цитирование ключей. Я рассмотрел, как json2.js проверяет строку JSON в четыре этапа перед ее оценкой. Я смог добавить 5-й этап, чтобы разрешить ключи без кавычек, и хотел бы знать, есть ли какие-либо последствия для безопасности этой логики.

var data = '{name:"hello", age:"23"}';

// Make sure the incoming data is actual JSON
// Logic borrowed from http://json.org/json2.js
if ( /^[\],:{}\s]*$/.test(data.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, "@")
     .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, "]")
     .replace(/(?:^|:|,)(?:\s*\[)+/g, ":") // EDITED: allow key:[array] by replacing with safe char ":"
     /** everything up to this point is json2.js **/

     /** this is the 5th stage where it accepts unquoted keys **/         
     .replace(/\w+\s*\:/g, ":")) ) { // EDITED: allow any alphanumeric key

  console.log( (new Function("return " + data))() );
}
else {
  throw( "Invalid JSON: " + data );
}

person daepark    schedule 17.11.2010    source источник
comment
Вы предполагаете, что литерал объекта JavaScript эквивалентен JSON, а это не так.   -  person Stephen    schedule 18.11.2010
comment
{name:"Joe"} является действительным Javascript, но это недопустимый JSON. Кроме того, вы не хотите взломать json2.js, потому что это просто отражает то, как работает встроенная поддержка JSON в браузерах. В Chrome, например, JSON.parse() без json2.js тоже задохнется. Но хуже то, что json2.js ничего не загрузит, если в браузере есть встроенная поддержка JSON. Таким образом, вы окажетесь в ситуации, когда браузеры с собственной поддержкой JSON никогда не увидят этот хак, потому что вместо этого он использует собственный код для его анализа.   -  person Alex Wayne    schedule 18.11.2010
comment
@Стивен Ты прав. Может быть, мне следует перефразировать вопрос как «Безопасный анализ JavaScript Object Literal и преобразование в JSON»?   -  person daepark    schedule 18.11.2010
comment
Тогда это будет правильное преследование.   -  person Stephen    schedule 18.11.2010
comment
@Squeegy Я не предлагал перезаписать JSON.parse, реализованный браузером или json2.js. Я просто предложил безопасный синтаксический анализатор Javascript Object Literal, основанный на мерах предосторожности синтаксического анализатора json2.js.   -  person daepark    schedule 18.11.2010
comment
Старая поговорка «будь либеральным в том, что ты принимаешь», в моей книге — плохая идея. Отклонение неверных входных данных информативным сообщением об ошибке может научить пользователей, которые могут не осознавать, что создают недопустимый JSON. Принятие его без предупреждения может дать пользователям ложное представление о том, что то, что они делают, является допустимым JSON, когда это не так, и их код не будет работать с другими анализаторами JSON.   -  person thomasrutter    schedule 10.08.2017


Ответы (5)


data.replace(/(['"])?([a-zA-Z0-9]+)(['"])?:/g, '"$2":');

Это заменит любые одинарные кавычки в имени параметра и добавит недостающие.

person Anthony Corbelli    schedule 18.11.2010
comment
Кажется, это работает. За исключением того, что вы не смогли справиться с подчеркиванием. Вот обновленное регулярное выражение: hash.replace(/(['"])?([a-zA-Z0-9_]+)(['"])?:/g, '"$2":'); - person Martin Drapeau; 14.03.2011
comment
Этот ответ далек от совершенства. Попробуйте {a: ['b', 'c']} или {a: "Note: something happened."} - person powerboy; 26.08.2012
comment
Имейте в виду, что, хотя это регулярное выражение может работать в некоторых очень специфических сценариях, оно не будет работать с более сложными вещами, такими как: { location: 'http://www.google.com' }, вы получите недопустимый JSON: {"location": "http"://www.google.com'} - person Marcos Dimitrio; 30.06.2015
comment
Не забывайте также о знаке доллара и пробелах между именем и двоеточием. replace(/(['"])?([a-zA-Z0-9_\$]+)(['"])?\s*:/g, '"$2":') - person Steven Spungin; 02.01.2017

Я подумал, что было бы полезно иметь реальные тестовые примеры, чтобы устранить любые проблемы с этой реализацией. Я добавил проект github под названием JSOL с некоторыми тестами. Пожалуйста, заполните бесплатно, чтобы добавить к нему и найти проблемы. Спасибо.

https://github.com/daepark/JSOL

person daepark    schedule 18.11.2010

JSON не допускает использование ключей без кавычек. JSON — это подмножество нотации JavaScript, в которое не входят ключи без кавычек. Передача ключей без кавычек практически любому анализатору JSON, скорее всего, вызовет ошибку или вернет «неожиданные» результаты.

Надеюсь это поможет

person mattbasta    schedule 18.11.2010
comment
Конечно, это правда о JSON, но JavaScript разрешает использование ключей без кавычек в литералах объектов. Это немного проблематично, так как вы не можете использовать тире или зарезервированные слова без кавычек. Однако я думаю, что спрашивающий уже знает это. - person JAL; 18.11.2010

Используйте 1_

JSON5 — это надмножество JSON, допускающее синтаксис ES5, включая ключи свойств без кавычек. Эталонная реализация JSON5 (json5 пакет npm) предоставляет объект JSON5, который имеет те же методы, что и те же аргументы и семантика, что и у встроенного объекта JSON.

person Inigo    schedule 04.05.2020

JSON с комментариями на самом деле является допустимым javascript, поэтому в среде javascript самый простой собственный способ его анализа - просто оценить его следующим образом.

function evalJs(js) {
    let fn = new Function("return (" + js + ")"),
        res = fn()
    return res;
}

let json5 = "{\n" +
    "//////\n" +
    "key: 5," +
    "}"

let data = evalJs(json5)
console.info(data)

Выход

{ key: 5 }
person Xtra Coder    schedule 16.12.2020