JSON Спецификация и использование кодировки BOM / charset - PullRequest
16 голосов
/ 14 февраля 2011

Я читал спецификацию RFC-4627 и пришел к интерпретации:

При рекламе полезной нагрузки как application/json MIME-тип,

  1. там ДОЛЖНО быть не BOM s в начале правильно закодированных потоков JSON (на основе раздела "3. Кодирование") и
  2. параметры мультимедиа не поддерживаются, поэтому заголовок mime-типа application/json; charset=utf-8 не не соответствует RFC-4627 (на основании раздела «6. Соображения IANA»).

Это правильные выводы? Буду ли я сталкиваться с проблемой при реализации веб-сервисов или веб-клиентов, которые придерживаются этой интерпретации? Должны ли я сообщать об ошибках в веб-браузерах, которые нарушают два вышеуказанных свойства?

Ответы [ 2 ]

20 голосов
/ 26 июня 2016

Вы правы

  1. Символ спецификации является недопустимым в JSON (и не нужен)
  2. Кодировка MIME недопустима в JSON (и не нужна)

RFC 7159, раздел 8.1 :

Реализации НЕ ДОЛЖНЫ добавлять метку порядка байтов в начало текста JSON.

Это изложено настолько ясно, насколько это возможно. Это единственное «НЕ ДОЛЖНО» во всем RFC.

RFC 7159, раздел 11 :

Тип мультимедиа для текста JSON: application / json.
Введите имя: приложение
Название подтипа: JSON
Обязательные параметры: не указано
Необязательные параметры: нет
[...]
Примечание: Для этой регистрации не определен параметр "charset".

кодировка JSON

Единственными допустимыми кодировками JSON являются UTF-8, UTF-16 или UTF-32, и поскольку первый символ (или первые два, если имеется более одного символа), всегда будет иметь значение Unicode ниже 128 (есть нет действительного текста JSON, который может содержать более высокие значения первых двух символов) всегда можно узнать, какая из допустимых кодировок и какая порядковая последовательность использовались, просто взглянув на поток байтов.

Рекомендация RFC

JSON RFC говорит, что первые два символа всегда будут ниже 128, и вы должны проверить первые 4 байта.

Я бы сказал по-другому: поскольку строка «1» также является допустимым JSON, нет никакой гарантии, что у вас вообще два символа - не говоря уже о 4 байтах.

Моя рекомендация

Моя рекомендация по определению кодировки JSON будет несколько иной:

Быстрый метод:

  1. если у вас есть 1 байт, и это не NUL - это UTF-8
    (фактически единственным действительным символом здесь будет цифра ASCII)
  2. если у вас 2 байта и ни один из них не равен NUL - это UTF-8
    (это должны быть цифры ASCII без начальных '0', {}, [] или "")
  3. если у вас 2 байта, и только первый - NUL - это UTF-16BE
    (это должна быть цифра ASCII в кодировке UTF-16 с прямым порядком байтов)
  4. если у вас 2 байта и только второй равен NUL - это UTF-16LE
    (это должна быть цифра ASCII в кодировке UTF-16 с прямым порядком байтов)
  5. если у вас есть 3 байта и они не равны NUL - это UTF-8
    (опять же, цифры ASCII без начальных '0, "x", [1] и т. д.)
  6. если у вас есть 4 байта или больше, чем работает метод RFC:
    • 00 00 00 xx - это UTF-32BE
    • 00 xx 00 xx - это UTF-16BE
    • xx 00 00 00 - это UTF-32LE
    • xx 00 xx 00 - это UTF-16LE
    • xx xx xx xx - это UTF-8

но это работает, только если это действительно допустимая строка в любом из этих кодировок, чего не может быть. Более того, даже если у вас есть допустимая строка в одной из 5 допустимых кодировок, она все равно может быть неверным JSON.

Моя рекомендация будет состоять в том, чтобы иметь немного более жесткую проверку, чем та, которая включена в RFC, чтобы убедиться, что у вас есть:

  1. допустимая кодировка UTF-8, UTF-16 или UTF-32 (LE или BE)
  2. действительный JSON

Недостаточно искать только байты NUL.

Как уже было сказано, ни в коем случае вам не нужно иметь какие-либо символы спецификации для определения кодировки, а также вам не нужна кодировка MIME - оба из которых не нужны и недопустимы в JSON .

При использовании UTF-16 и UTF-32 необходимо использовать только двоичное кодирование передачи содержимого, поскольку они могут содержать байты NUL. UTF-8 не имеет этой проблемы, и 8-битное кодирование передачи контента прекрасно, поскольку оно не содержит NUL в строке (хотя оно все еще содержит байты> = 128, поэтому 7-битная передача не будет работать - есть UTF- 7, который будет работать для такой передачи, но это не будет действительный JSON, поскольку он не является единственной допустимой кодировкой JSON).

См. Также этот ответ для более подробной информации.

Ответы на ваши последующие вопросы

Это правильные выводы?

Да.

Буду ли я сталкиваться с проблемой при внедрении веб-сервисов или веб-клиентов, которые придерживаются этой интерпретации?

Возможно, если вы взаимодействуете с неверными реализациями. Ваша реализация МОЖЕТ игнорировать спецификацию для обеспечения совместимости с неправильными реализациями - см. RFC 7159, раздел 1.8 :

В интересах совместимости, реализации этот синтаксический анализ текстов JSON МОЖЕТ игнорировать наличие метки порядка байтов вместо того, чтобы рассматривать это как ошибку.

Кроме того, игнорирование кодировки MIME является ожидаемым поведением совместимых реализаций JSON - см. RFC 7159, Раздел 11 :

Примечание: для этой регистрации не определен параметр "charset". Добавление одного действительно не влияет на совместимых получателей.

Соображения безопасности

Я лично не убежден, что молчаливое принятие неправильных потоков JSON всегда желательно. Если вы решите принять ввод с кодировкой BOM и / или MIME, вам придется ответить на следующие вопросы:

  • Что делать в случае несоответствия между кодировкой MIME и фактической кодировкой?
  • Что делать в случае несоответствия между спецификацией и кодировкой MIME?
  • Что делать в случае несоответствия между спецификацией и фактической кодировкой?
  • Что делать, если все они различаются?
  • Что делать с кодировками, отличными от UTF-8/16/32?
  • Вы уверены, что все проверки безопасности будут работать как положено?

Определение кодировки в трех независимых местах - в самой строке JSON, в спецификации и в кодировке MIME делает вопрос неизбежным: что делать, если они не согласны. И до тех пор, пока вы не отклоните такой ввод, нет однозначного ответа.

Например, если у вас есть код, который проверяет строку JSON, чтобы увидеть, безопасно ли ее оценивать в JavaScript - это может быть введено в заблуждение кодировкой MIME или спецификацией и трактовать как кодировку, отличающуюся от фактической, и не обнаруживать строки, которые он обнаружил бы, если бы использовал правильную кодировку. (Подобная проблема с HTML в прошлом приводила к атакам XSS.)

Вы должны быть готовы ко всем этим возможностям, когда вы решаете принять неправильные строки JSON с несколькими и, возможно, конфликтующими индикаторами кодирования. Нельзя сказать, что вы никогда не должны этого делать, потому что вам может потребоваться использовать ввод, полученный в результате неправильных реализаций. Я просто говорю, что вам нужно тщательно обдумать последствия.

Несоответствующие реализации

Должен ли я сообщать об ошибках в веб-браузерах, которые нарушают два вышеуказанных свойства?

Конечно - если они называют это JSON, а реализация не соответствует JSON RFC, то это ошибка, о которой следует сообщать.

Нашли ли вы какие-либо конкретные реализации, которые не соответствуют спецификации JSON, и все же они рекламируют это?

2 голосов
/ 03 марта 2012

Я думаю, что вы правильно ответили на вопрос 1, поскольку в Разделе 3 о первых двух символах ASCII и Unicode Часто задаваемые вопросы по спецификациям , см. «Вопрос: Как мне следует обращаться с спецификациями?», Ответ часть 3. Ваш акцент на ДОЛЖЕН может быть немного сильным: часто задаваемые вопросы, как представляется, подразумевают СЛЕДУЕТ .

Не знаю ответа на вопрос 2.

...