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

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

при рекламе полезной нагрузки как application/json mime-type,

  1. здесь должны нет BOMs в начале правильно закодированных потоков JSON (на основе раздела " 3. Кодировка"), и
  2. параметры мультимедиа не поддерживаются, таким образом, заголовок типа mime application/json; charset=utf-8 тут не соответствуют RFC-4627 (на основании в разделе "6. IANA Considerations").

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

2 ответов


ты прав

  1. символ BOM является незаконным в JSON (и не требуется)
  2. кодировка MIME запрещена в JSON (и не нужны)

RFC 7159, раздел 8.1:

реализации не должны добавлять метку порядка байтов в начало текста JSON.

это так ясно, как это может быть. Это единственное "не должно" во всем RFC.

RFC 7159, Раздел 11:

тип носителя MIME для текста JSON-application / json.
Имя типа: приложение
Название подтипа: json
Необходимые параметры: n / a
Дополнительные параметры: n / a
[...]
Примечание:для этой регистрации параметр" charset " не определен.

в формате JSON кодировка

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

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

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

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

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

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

быстрый способ:

  1. если у вас есть 1 байт, и это не NUL-это UTF-8
    (на самом деле единственным допустимым символом здесь будет цифра ASCII)
  2. если у вас есть 2 байта, и ни один из них не равен нулю-это UTF-8
    (это должны быть ASCII-цифры без ведущего '0',{}, [] или "")
  3. если у вас есть 2 байта и только первый нуль - это UTF-16BE
    (это должна быть цифра ASCII, закодированная как UTF-16, big endian)
  4. если у вас есть 2 байта и только второй-ноль-это UTF-16LE
    (это должна быть цифра ASCII, закодированная как UTF-16, little endian)
  5. если у вас есть 3 байта, и они не нулевые-это UTF-8
    (опять же, ASCII цифры без ведущих "0","x", [1] etc.)
  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

поиск только нулевых байтов недостаточно.

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

вам нужно использовать только двоичный файл content-transfer-encoding при использовании UTF-16 и UTF-32, потому что они могут содержать нулевые байты. Кодировка UTF-8 не имеют этой проблемы и 8bit содержание-передача-кодирование-это нормально, так как он не содержит нулевой символ в строку (хотя она по-прежнему содержится байт >= 128 Т. 7-битная передача работать не будет - там кодировка UTF-7, что бы работать на такой перевод, но это не допустимый JSON, так как он не единственный допустимый JSON кодирования).

см. также ответ дополнительные подробности.

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

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

да.

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

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

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

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

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

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

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

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

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

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

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

некондиционного реализации

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

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

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


Я думаю, вы правы в вопросе 1, из-за раздела 3 о первых двух символах ASCII и unicode FAQ по BOMs, см. " Q: Как я должен иметь дело с BOMs?", ответ Часть 3. Ваш акцент на должны может быть немного сильным: FAQ, кажется, подразумевает должны.

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