UTF-7
UTF-7 (от англ. 7-bit Unicode Transformation Format — «формат преобразования Юникода, 7 бит») формат кодирования текста Юникод с переменной длиной символьных слов в последовательность символов ASCII. Первоначально предназначался для кодирования текстов Юникода в сообщениях электронной почты Интернета, которые были более эффективными, чем комбинация UTF-8 с quoted-printable.
Применение
Современный стандарт формата электронной почты MIME запрещает кодирование заголовков с использованием байтовых значений выше диапазона ASCII. Хотя MIME позволяет кодировать тело сообщения из разных наборов символов (более широких, чем ASCII), базовая инфраструктура передачи (SMTP, основной стандарт передачи E-mail) по-прежнему не гарантирует 8-битную чистоту. Поэтому в случае сомнений необходимо применять нетривиальное кодирование передаваемого контента. К сожалению, Base64 имеет недостаток, заключающийся в том, что даже символы US-ASCII не читаются в не-MIME-клиентах. С другой стороны, UTF-8 в сочетании с quoted-printable представляет собой очень неэффективный формат, требующий 6—9 байт для отличных от ASCII символов из BMP (Basic Multilingual Plane), и 12 байтов для символов вне BMP.
Если во время кодирования соблюдаются определённые правила, текст в кодировке UTF-7 может быть отправлен по электронной почте без использования базовой кодировки передачи MIME, но должен быть явно помечен как набор текстовых символов. Кроме того, если они используются в заголовках электронной почты, таких как "Subject: ", UTF-7 должен содержаться в закодированных по стандарту MIME словах, идентифицирующих набор символов. Так как закодированные слова используют или quoted-printable, или Base64 наборы, UTF-7 был разработан с возможностью не использовать знак равенства = в качестве экранирующего символа, чтобы избежать двойного пропуска при его сочетании с quoted-printable (или его вариантом, в RFC 2047/1522 ?Q?-кодирование заголовков).
UTF-7, как правило, не используется в нативном виде в приложениях, так как очень неудобен при обработке. Несмотря на то, что UTF-7 имеет преимущество перед комбинациями UTF-8 с quoted-printable или Base64, ныне несуществующий Internet Mail Consortium рекомендовал не использовать кодировку UTF-7.[1]
Также был введён 8BITMIME, чтобы уменьшить необходимость кодирования тел сообщений в 7-битном формате.
Модифицированная форма UTF-7 (mUTF-7, UTF-7 IMAP) в настоящее время используется в протоколе электронной почты IMAP для поиска имён почтовых ящиков[2].
Описание
Первоначально UTF-7 был предложен в качестве экспериментального протокола в RFC 1642 «A Mail-Safe Transformation Format of Unicode». Этот RFC устарел по сравнению с RFC 2152, информационным RFC, который никогда не был стандартом. Как заявлено в RFC 2152, «RFC не определяет интернет-стандарт любого типа». Несмотря на это, RFC 2152 цитируется как определение UTF-7 в списке кодировок IANA. Также UTF-7 не является стандартом Unicode. В Unicode Standard 5.0 перечислены только UTF-8, UTF-16 и UTF-32. Существует также модифицированная версия, указанная в RFC 2060, которая иногда идентифицируется как UTF-7.
Некоторые символы могут быть представлены непосредственно в виде одиночных байтов ASCII. Они образуют группу так называемых «прямых символов» из 52 букв латиницы, 10 цифр и 9 символов пунктуации: ' ( ) , - . / : ?
. Прямые символы безопасны при их буквальном отображении. Другая основная группа, известная как «необязательные прямые символы», содержит все другие печатные символы в диапазоне U+0020—U+007E
за исключением ~ \ +
и пробела. Использование необязательных прямых символов уменьшает размер и улучшает читаемость, но также увеличивает вероятность повреждения информации такими факторами, как плохо спроектированные почтовые шлюзы, и может потребовать дополнительного экранирования при использовании необязательных прямых символов в кодированных словах для полей заголовка.
Пробел, табуляция, возврат каретки и перевод строки также могут быть представлены непосредственно в виде одиночных байтов ASCII. Однако, если кодированный текст должен использоваться в электронной почте, необходимо соблюдать осторожность, гарантирующую, что для этих символов не потребуется дополнительной кодировки передаваемого контента, подходящей для электронной почты. Знак плюса +
может быть закодирован как +-
.
Другие символы должны быть сначала закодированы в UTF-16 (символы с кодами от U+10000
и выше будут закодированы в суррогатах) big-endian (старшие биты в конце), а затем модифицированы в коды Base64. Начало таких блоков из символов, закодированных в UTF-16 и модифицированных в Base64, обозначается знаком +
. Конец блоков обозначается любым символом, который не входит в модифицирующий набор Base64. Если символ после модифицирования в Base64 является -
(дефис-минусом ASCII), то он пропускается декодером, а декодирование возобновляется со следующего символа. В противном случае декодирование возобновляется с символом после Base64.
Также был введён 8BITMIME, чтобы уменьшить необходимость кодирования тел сообщений в 7-битном формате.
Примеры
- «Hello, World!» кодируется как
Hello, World!
- «1 + 1 = 2» кодируется как
1 +- 1 +AD0 2
- «£1» кодируется как
+AKM-1
. Кодовое обозначение Unicode для знака фунта равноU+00A3
(соответствует 00A316 в UTF-16), которая преобразуется в модифицированный Base64, как в приведённой ниже таблице. Два недостающих бита дополняются 0.
Шестнадцатеричный код | 0 | 0 | A | 3 | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Двоичный код | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 1 | 1 | 0 | 0 |
Индексы | 0 | 10 | 12 | |||||||||||||||
Код Base64 | A | K | M |
Алгоритм кодирования и декодирования
Кодирование
Во-первых, кодировщик должен определить, какие символы можно представить непосредственно в формате ASCII, кроме знака плюс +, который кодируются как +-
, а какие символы нужно пометить как блоки символов Unicode. Простой кодировщик может кодировать напрямую все символы, которые он считает безопасными для прямого кодирования. Однако стоит оканчивать последовательность Unicode вводом одного символа непосредственно в ASCII, а затем начинать другую последовательность Unicode, содержащую от 3 до 3⅔ байтов. Это больше, чем 2⅔ байта, необходимых для представления символа как части последовательности Unicode.
Каждая последовательность символов Юникода должна быть закодирована с использованием следующей процедуры, а затем окружена соответствующими разделителями. Для примера используем последовательность символов £† (U+00A3 U+2020
):
- Преобразовываем символы Unicode (UTF-16) из hex-формата в двоичный формат:
0x00A3 → 0000 0000 1010 0011
0x2020 → 0010 0000 0010 0000 - Объединяем двоичные последовательности:
0000 0000 1010 0011 и 0010 0000 0010 0000 → 0000 0000 1010 0011 0010 0000 0010 0000 - Перегруппировываем двоичный код в блоки по шесть бит, начиная слева:
0000 0000 1010 0011 0010 0000 0010 0000 → 000000 001010 001100 100000 001000 00 - Если последний блок имеет менее шести бит, заполняем его нулями до получения нужной длины:
000000 001010 001100 100000 001000 00 → 000000 001010 001100 100000 001000 000000 - Заменяем каждый блок из шести бит соответствующим кодом Base64:
000000 001010 001100 100000 001000 000000 → AKMgIA
Декодирование
Сначала закодированные данные должны быть разделены на простые текстовые фрагменты ASCII (включая плюсы, за которыми следует дефис +-
) и непустые блоки Unicode, как указано в разделе описания. Как только это будет сделано, каждый блок Unicode должен быть декодирован следующей процедурой (используя результат примера кодирования выше):
- Преобразовать каждый кодовый символ Base64 в битовую последовательность, которую он представляет:
AKMgIA → 000000 001010 001100 100000 001000 000000 - Перегруппировать двоичный код в группы по 16 бит, начиная слева:
000000 001010 001100 100000 001000 000000 → 0000000010100011 0010000000100000 0000 - Если в конце осталась неполная группа, содержащая только нули, отбросить её (если неполная группа содержит сколько-либо единиц, код недействителен):
0000000010100011 0010000000100000 - Каждая группа из 16 бит является номером Unicode-символа (UTF-16) и может быть выражена в других формах:
0000 0000 1010 0011 ≡ 0x00A3 ≡ 16310
Маркер Unicode
Маркер Юникода (часто называемый «BOM» — byte-order mark) является необязательной специальной последовательностью байтов в самом начале потока или файла, который, не будучи самими данными, указывает кодировку, используемую для последующих данных; маркер используется при отсутствии метаданных, обозначающих кодировку. Для данной схемы кодирования сигнатура представляет собой представление схемы в кодовой точке Unicode U+FEFF
, так называемый BOM-символ.
Хотя маркер Unicode, как правило, представляет собой единую фиксированную последовательность байтов, специфика UTF-7 представляет 5 вариаций: последние 2 бита 4-го байта кодировки UTF-7 U+FEFF
относятся к следующему символу, что приводит к 4-м возможным битовым шаблонам и, следовательно, 4-м разным возможным байтам в 4-й позиции. Пятая вариация необходима для устранения неоднозначности случая, когда вообще никакие символы не следуют за маркером. См. Определение кодировки по маркеру последовательности байтов.
Безопасность
UTF-7 допускает множественные представления одной и той же исходной строки. В частности, символы ASCII могут быть представлены как часть блоков Unicode. Таким образом, если для строк, которые могут быть позже интерпретированы как UTF-7, используются стандартные алгоритмы экранирования или проверки подлинности на основе ASCII, то блоки Unicode могут использоваться для внедрения вредоносных строк, свободно проходящих через проверку. Чтобы устранить эту проблему, системы проверки должны выполнять декодирование перед проверкой и не должны пытаться автоматически обнаруживать UTF-7.
Старые версии Internet Explorer можно обмануть путём интерпретации страницы как UTF-7. Это можно использовать для атаки на межсайтовый скриптинг, поскольку служебные символы <
и >
могут быть закодированы как +ADw-
и +AD4-
в UTF-7, которые большинство валидаторов пропускают как простой текст.
Ссылки
- UTF-7 Decoder (англ.). ToolsWEBTOP. Дата обращения: 1 апреля 2019.
- UTF-7 Encoder (англ.). ToolsWEBTOP. Дата обращения: 1 апреля 2019.
Примечания
- ↑ Internet Mail Consortium, Using International Characters in Internet Mail Архивная копия от 7 сентября 2015 на Wayback Machine, 1 August 1998, retrieved 8 January 2009
- ↑ RFC 3501 section 5.1.3