Пожалуйста, помогите мне проследить, как обрабатываются наборы символов на каждом этапе - PullRequest
2 голосов
/ 09 октября 2009

Мы все знаем, как простые наборы символов находятся в сети , но каждый раз, когда вы думаете, что все правильно, иностранная кодировка кусает вас в задницу. Поэтому я хотел бы проследить, что происходит в вымышленном сценарии, который я опишу ниже. Я постараюсь изложить свое понимание настолько хорошо, насколько это возможно, но мой вопрос заключается в том, чтобы вы, ребята, исправили любые ошибки, которые я совершил, и заполнили все ЗАПИСИ.

При чтении этого сценария представьте, что это делается на Mac Джоном, а в Windows Джейн, и добавьте комментарии, если один ведет себя не так, как другой в любой конкретной ситуации.


Наш герой (Джон / Джейн) начинает с написания абзаца в Microsoft Word. Набор символов Word BLANK1 ( CP1252 ?).

Он / она копирует абзац, включая умные кавычки (например, «»). Копирование выполняется BLANK2 (Операционная система ... Windows / Mac?), Которая BLANK3 (определяет, какую кодировку использует приложение, и наследует кодировку?). Затем он вставляет абзац в текстовое поле в StackOverflow.

Предположим, что StackOverflow работает на Apache / PHP и что их настройка в httpd.conf не указывает AddDefaultCharset utf-8 , а их php.ini устанавливает default_charset в ISO -8859-1.

Тем не менее, ни одна из перечисленных выше кодировок не имеет значения, поскольку заголовок Stack Overflow содержит этот оператор META http-equ = "Content-Type" content = "text / html; charset = UTF-8" , поэтому даже если Вы нажали «Задать вопрос», возможно, вы видели заголовок * RESPONSE в firebug в «Content-type text / html;» ... на самом деле, Firefox / IE / Opera / Другие браузеры BLANK4 (полностью на 100% игнорируют заголовок сервера и переопределяют его с объявлением типа мета-содержимого в заголовке? Хотя он должен прочитать файл, прежде чем узнает тип контента, так как он не должен ничего делать с кодировкой, пока не отобразит тело, это ничем не отличается от браузера?).

Поскольку тип мета-содержимого страницы - UTF-8, форма ввода преобразует любые символы, введенные вами в поле, в символы UTF-8. БЛАНК5 (Если кто-то может вдаваться в мучительные подробности о том, что делает браузер на этом шаге, было бы очень полезно ... вот мое понимание ..., поскольку операционная система контролирует буфер обмена и отображение символа в форме, она вставляет символ в любой кодировке, из которой он был скопирован. И отображает его в форме, как эта кодировка ... В этом примере переопределение UTF-8).

Давайте предположим, что метод формы = GET, а не публикация, чтобы мы могли проигрывать с вводом URL-адреса браузера ... Продолжая нашу историю, форма представляется в формате UTF-8. Умные кавычки, представляющие десятичный код 147 и 148, когда браузер преобразует их в UTF-8, преобразуется в символы BLANK6.

Предположим, что после отправки Stack Overflow обнаружил ошибку в форме, поэтому вместо отображения итогового вопроса он возвращает окно ввода с вашим вопросом внутри формы. В php переменные формы экранированы с помощью htmlspecialchars ($ var) для правильного отображения данных, поскольку на этот раз это BLANK7 (браузер контролирует отображение, а не операционную систему ... поэтому кавычки должны быть представленным как его эквивалент UTF-8, иначе вы получите страшно выглядящий looking вопросительный знак?)

Однако, если вы возьмете умные кавычки, вставите их непосредственно в строку URL и нажмете клавишу ввода .... htmlspecialchars сделает BLANK8, испортит отображение формы и вставит вопросительные знаки , так как прямой запрос URL будет просто используйте кодировку в URL-адресе ... или даже BLANK9 (сочетание кодировок?), если у вас их более одного ...

При отправке запроса REQUEST браузер выводит список допустимых кодировок для браузера. Список кодировок происходит от BLANK10.

СейчасВы можете подумать, что наша история на этом заканчивается, но это не так. Потому что StackOverflow необходимо сохранить эти данные в базе данных. К счастью, люди, управляющие этим суставом, умны. Поэтому, когда их клиент MySQL подключается к базе данных, он проверяет, что клиент и сервер общаются друг с другом UTF-8, выполнив команду SET NAMES UTF-8 , как только будет установлено соединение. Кроме того, набор символов по умолчанию для MySQL установлен на UTF-8, и каждое поле установлено одинаково.

Таким образом, Stack Overflow полностью защитил свой веб-сайт от инъекций в дБ, подделок CSRF и проблем со сценариями на XSS-сайтах ... или, по крайней мере, из-за игры в кодировку.

* Обратите внимание, что это пример, а не фактический ответ этой страницы.

1 Ответ

3 голосов
/ 10 октября 2009

Я не знаю, отвечает ли это "на" ваш "вопрос", но я могу, по крайней мере, помочь вам с тем, что я считаю критическим недоразумением.

Вы говорите: «Поскольку Meta Content-тип страницы - UTF-8, форма ввода преобразует любые символы, введенные вами в поле, в символы UTF-8». Не существует такого понятия, как «символ UTF-8», и неверно или даже не имеет смысла думать о том, что форма «конвертирует» что-либо во что-либо при вставке. Символы - это абсолютно абстрактное понятие, и нет способа узнать (не читая источник), как данная программа, включая ваш веб-браузер, решает реализовать их. Поскольку в наши дни наиболее важные приложения ориентированы на Unicode, они, вероятно, имеют некоторую внутреннюю абстракцию для представления текста в виде символов Unicode - обратите внимание, это Unicode , а не UTF-8 .

Кусок текста в Юникоде (или в любом другом наборе символов) представляется в виде серии кодовых точек , целых чисел, которые однозначно присваиваются символам , которые именованные объекты в большой базе данных, каждая из которых имеет любое количество свойств (например, является ли она меткой объединения, идет ли она справа налево и т. д.). Вот часть, где резина встречается с дорогой: чтобы представлял текст в реальном компьютере, сохраняя его в файл или отправляя по проводам на другой компьютер, он должен быть закодировано как последовательность байтов. UTF-8 - это кодировка (или «формат преобразования» на языке Unicode), которая представляет каждую целочисленную кодовую точку в виде уникальной последовательности байтов. В частности, есть несколько интересных и хороших свойств UTF-8, но они не имеют отношения к пониманию того, что происходит в целом.

В описываемом вами сценарии метаданные типа содержимого сообщают браузеру, как интерпретировать отправляемые байты как последовательность символов (которые, помните, являются абсолютно абстрактными объектами, не имеющими отношения к байтам или чему-либо еще). Он также сообщает браузеру, что необходимо кодировать текстовые значения, введенные пользователем, в форму в виде UTF-8 на обратном пути к серверу.

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

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

P.S. Когда вы видите , есть две возможные причины.

1) Программе было предложено написать несколько символов с использованием некоторого набора символов (скажем, ISO-8859-1), который не содержит определенного символа, который появляется в тексте. Таким образом, если текст представлен внутри как последовательность кодовых точек Unicode, и текстовый редактор предлагается сохранить как ISO-8859-1, а текст содержит какой-то японский символ, ему придется либо отказаться от этого, либо выплюнуть некоторая произвольная последовательность байтов ISO-8859-1 для обозначения «no puedo».

2) Программа получила последовательность байтов, которая, возможно, представляет текст в некоторой кодировке, но интерпретирует эти байты, используя другую кодировку. Некоторые последовательности байтов в этой кодировке не имеют смысла, поэтому он может либо отказаться от этого, либо просто выбрать какой-либо символ (например, ) для представления каждой неразборчивой последовательности байтов.

P.P.S. Эти танцы кодирования / декодирования происходят между приложениями и буфером обмена в выбранной вами ОС. Представьте себе возможности.


В ответ на ваши комментарии:

Это неправда, что «Word использует кодировку CP1252»; он использует Unicode для внутреннего представления текста. Вы можете убедиться в этом, просто вставив какой-нибудь символ катакана, такой как サ, в Word. Windows-1252 не может представлять такой символ.

Когда вы «копируете» что-либо из какого-либо приложения, все дело за приложением, чтобы решить, что поместить в буфер обмена. Например, когда я выполняю операцию копирования в Word, я вижу 17 различных фрагментов данных, каждый из которых имеет свой формат, помещенных в буфер обмена. Один из них имеет тип CF_UNICODETEXT, который является UTF-16.

Теперь, что касается URL ... Подробности можно найти здесь . Перед отправкой HTTP-запроса браузер должен превратить URL-адрес (который может содержать любой текст) в IRI. Вы конвертируете URL-адрес в IRI, сначала кодируя его как UTF-8, затем представляя байты UTF-8 вне диапазона печати ASCII в их процентных формах. Так, например, правильная кодировка для http://foo.com/dir1/引き割り.html равна http://foo.com/dir1/%E5%BC%95%E3%81%8D%E5%89%B2%E3%82%8A.html. (Имена хостов следуют другим правилам, но все они находятся в связанном ресурсе).

Теперь, на мой взгляд, браузер должен показывать старый текст в строке адреса и выполнять все кодирование за кулисами. Но некоторые браузеры делают глупый выбор и показывают форму IRI, или некоторую химеру URL и IRI.

...