`

СПЕЦІАЛЬНІ
ПАРТНЕРИ
ПРОЕКТУ

Чи використовує ваша компанія ChatGPT в роботі?

BEST CIO

Определение наиболее профессиональных ИТ-управленцев, лидеров и экспертов в своих отраслях

Человек года

Кто внес наибольший вклад в развитие украинского ИТ-рынка.

Продукт года

Награды «Продукт года» еженедельника «Компьютерное обозрение» за наиболее выдающиеся ИТ-товары

 

IDN: проблемы создания или создание проблем

Статья опубликована в №48 (567) от 19 декабря

0 
 

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

Весьма занятный трюк времен DOS, который, кстати, остался на вооружении и у сегодняшних злоумышленников (скажем, для установки «троянского коня»), – замена в autoexec.bat команды rem (кто не помнит, от remark, т. е. для обозначения комментария) на практически аналогичную, но только с русской буквой «е» в середине. Так можно было загрузить любую резидентную программу, и, поверьте, неопытный человек вряд ли смог бы это обнаружить. Известно ведь, куда могут завести благие намерения, а поддержка на системном уровне национальных алфавитов несомненно относится к таковым...

Взлом собственного компьютера

Хакерам в изобретательности не откажешь. Среди их уловок есть и такая, которая заставляет самого владельца ПК выполнять определенные действия во благо злоумышленника. Речь идет о так называемой семантической атаке. Один из ее вариантов выглядит следующим образом. Группа хакеров (одиночке такая задача вряд ли по силам) выбирает респектабельный, отлично зарекомендовавший себя интернет-магазин, пользующийся заслуженным доверием покупателей, и в деталях воссоздает на своем сервере его Web-страницы. Затем для него регистрируется доменное имя, отличающееся от настоящего лишь одним символом (типичный прием, основанный на сходстве нуля с заглавной буквой «O» или единицы со строчной буквой «l»). Теперь остается лишь подождать, пока кто-то из пользователей невнимательно введет адрес или щелкнет по ссылке и попадет на фальшивый сервер. Там он приобретет какой-нибудь товар, сообщив номер своей платежной карточки, а именно это и надобно организаторам аферы. Кстати, чтобы подлог подольше оставался незамеченным, они действительно могут доставить товар, купив его в реальном магазине, а набрав достаточное количество невнимательных посетителей, разом снимут деньги со счетов и будут таковы.

Впрочем, кража – далеко не единственная цель семантической атаки. Подобным образом, например, часто распространяется дезинформация. Как поступит владелец ценных бумаг, если вместо сервера нужной ему организации он попадет на подложный сайт и прочтет фальшивый пресс-релиз, из которого следует, что ей угрожает финансовый крах? Наверное, постарается побыстрее избавиться от акций, пока цена на них не упала. А когда подобным образом поступят многие, то компания неизбежно понесет убытки.

Иногда подобные действия нельзя даже назвать противоправными. Если автору Web-узла удается найти доменное имя, схожее с популярным ресурсом, число пользователей, обращающихся к его узлу, неизбежно возрастет. Так, несколько лет назад автолюбители, которые не знали, как пишется слово toyota попадали прямиком на порносайт. Теперь руководство автомобильной компании, по-видимому, позаботилось о том, чтобы избавиться от нежелательного соседства. В ряде же случаев созвучие имен оказывается совершенно случайным. К примеру, адрес www.sum.com, отличающийся всего одной буквой от имени сервера Sun Microsystems, принадлежит вполне респектабельной организации Sum Group.

Но какое отношение имеют семантические атаки к заголовку статьи? Оказывается, самое прямое.

Доменное имя на родном языке

10 декабря 1996 г. сотрудник Цюрихского университета Мартин Дюэрст (Martin Duerst) опубликовал проект, в котором предложил снять ограничение, запрещающее использовать в доменных именах символы национальных алфавитов. Этот день официально считается началом работы по созданию и внедрению интернациональных доменных имен, или IDN (Internationalized domain name). В последующие полтора года разработка велась, как говорится, в тиши кабинетов, а в 1998–1999 гг. хлынула волна публикаций, совещаний и рабочих встреч, после чего стало ясно: данная идея завладела слишком многими умами и уже не может остаться нереализованной. И действительно, в декабре 1999 г. началась регистрация имен на китайском языке, а в мае 2001 г. и русскоязычные пользователи получили возможность применять кириллицу при вводе доменного имени.

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

Как и всегда практики оказались более нетерпеливыми и намного опередили теоретиков, потому что последняя «точка» в разговоре об IDN была поставлена только в мае 2003 г., когда вышел в свет RFC3490, закрепляющий основные положения, касающиеся использования интернациональных доменных имен в приложениях (Internationalizing Domain Names in Applications – IDNA). В этом документе в первом же абзаце введения сказано, что поддержка национальных кодировок должна осуществляться на уровне приложений и не затрагивать существующую структуру DNS. Следовательно, прежде чем вызывать процедуру resolve, которая взаимодействует с DNS-серверами и преобразует имя в адрес, необходимо заменить недопустимые символы, представив их ASCII-последовательностями.

Такая задача уже неоднократно решалась. В CGI для этой цели используется шестнадцатеричный код символа, предваренный знаком %, в HTML применяются последовательности, начинающиеся с &. Наконец, во многих языках программирования можно задать вместо любого символа восьмеричный код, указав перед ним обратную косую черту. Однако подобные варианты оказались непригодными для IDN. Шестнадцатеричное представление 16-разрядного Unicode-символа состоит из четырех цифр. Вообразите, как будет выглядеть в закодированном виде достаточно длинное слово, например, «интернационализация». Отбросив ведущие нули тоже не удастся сократить длину кода, так как придется воспользоваться разделителями между символами. По этой причине для представления национальных Unicode-алфавитов был принят специальный способ кодирования под названием Punicode.

Странные символы в доменном имени

Разобраться в правилах Punicode довольно сложно, поэтому, чтобы лучше понять их, рассмотрим простой пример. Пусть мы хотим преобразовать доменное имя www.сервер.com. Согласно Punicode, каждый компонент доменного имени (т. е. имя каждого домена) кодируется независимо от других компонентов, вследствие чего последовательности символов www» и «com» остаются неизменными. Остается «сервер».

Очередное правило гласит, что имя должно быть представлено в следующем формате: xn-<символы_ASCII>-<национальные_символы>. Другими словами, в начале преобразованного имени располагается префикс «xn-», за ним латинские символы (если таковые присутствуют), а далее дефис и Unicode-символы, отличные от ASCII. Предположим, мы решили максимально упростить задачу изменения имени, поэтому первые три и последние два символа представляем латинскими буквами «c», «е» и «p». (На самом деле это крайне неудачное решение. Почему? Попробуйте задать такое имя и вы обязательно собьетесь при вводе. Однако в качестве примера оно подходит как нельзя лучше.) Остается символ «в». Давайте введем имя «сервер» (буква из кириллицы, как мы уже договорились, в нем только одна) в строке адреса Mozilla Firefox, Internet Explorer 7 или любого другого браузера, поддерживающего IDN. В строке состояния мы увидим последовательность символов «xn-cepep-jwe». Вначале все понятно: «xn-» – это префикс, «cepep» – это как раз «cepвep», из которого исключена буква «в», но последние три символа вызывают недоумение. Очевидно, они отображают «в», но как?

Оказывается, jwe – это число, но не шестнадцатеричное и тем более не десятичное. В Punicode используется 35 цифр. Значения от 0 до 25 представляются буквами a–z, а цифры 0–9 обозначают соответственно 26–35. И все же это не 36-ричная система счисления, как может показаться на первый взгляд. В Punicode принят принцип кодирования обобщенными целыми переменной длины (см. врезку). Вначале идут младшие разряды – порядок следования little endian. Для первой цифры выбран порог, равный 1. В нашем примере первая цифра j, т. е. 9, она больше единицы, значит не последняя в числе. Вторая – w, или 22, она представляет значение 22×35 (вес цифры второго разряда именно 35, а не на 36: число цифр в наборе минус порог предыдущего числа). Поскольку и для второй цифры установлен порог 1, она также не последняя. Следующая цифра e, представляющая значение 4. Ее вес – 1225 (35×35) и, поскольку для третьей цифры, так же как и для всех последующих установлен порог 26 (цифра 0), то ею и заканчивается наше число. А в результате наших рассуждений оно равно 5679 (9 + + 22×35 + 4×1225) и расшифровать его можно следующим образом. Минимальное Unicode-значение символа, выраженное посредством Punicode, составляет 128. Меньшие значения имеют только ASCII-символы, кодировать которые специальным образом нет необходимости. В составе имени символ может быть расположен по-разному. В данном случае в слове пять латинских букв, поэтому дополнительный символ занимает одну из шести позиций: 0 находится перед первым символом ASCII, а позиция после последнего символа имеет номер 6. Код буквы «в» составляет 1074. Разность этого кода и минимального (128) равна 946. Данное число умножается на количество возможных позиций, т. е. на 6 (946×6 = 5676). Буква «в» располагается в третьей позиции (т. е. после первой буквы «p») с учетом чего получаем 5679 (5676 + 3). Именно такое число, как мы рассмотрели выше, и представлено последовательностью «jwe».

Теперь предположим, что в имени появилась вторая буква, отличная от ASCII, например, вместо слова «cepвер», мы хотим закодировать слово «cepверы». Использовать три цифры для этого было бы слишком расточительно (вспомним пример со словом «интернационализация»). Учтем также, что коды символов одного и того же языка незначительно отличаются друг от друга. Исходя из этих соображений, разработчики Punicode применили давно известный способ представления последовательности близких значений – дельта-кодирование. Для каждого очередного символа учитывается лишь разность его кода и кода предыдущего символа. После кодирования буквы «в» мы получили последовательность xn-cepep-jwe. Осталось добавить к ней представление буквы «ы». Ее код равен 1099. Разность между «ы» и «в» составляет 25 (1099 - 1074). Но теперь число возможных позиций возросло, так как к набору символов cepвep уже добавилась буква «в». Число 25 умножаем на количество позиций, равное 7 и получаем 175 (25×7). Таким было бы представление буквы «ы», если бы она располагалась сразу же за «в». Но между «в» и «ы» находятся еще две буквы, значит код равняется 177 (175 + 2). Учитывая, что порог для четвертой цифры в числе равен 26, формируем представление буквы «ы» – 1p (27 + 15×10). В результате имя «серверы» будет представлено как xn-cepep-jwe1p.

Осталось учесть последнюю особенность Punicode: порядок обработки букв национальных алфавитов зависит не от их позиции в имени домена, а от значения кода. Так, например, если мы изменим «cepверы» на « cepвера» (что-нибудь вроде cepвера.net), то Punicode-последовательность, представляющая это имя, будет выглядеть как xn-cepep-8vel. Вначале будет обработана буква «a» и выражена последовательностью 8ve (код 1072, номер позиции 5, (1072 – 128)×6 + + 5 = 5669), и лишь затем черед дойдет до буквы «в». Разность между кодами «а» и «в» составляет 2, но позиций в слове уже 7, стало быть 2×7 – 3 = 11, а это значение представляется одной цифрой 1.

Простор для семантических атак

Итак, интернациональные доменные имена уже стали реальностью. Вероятно, в этом явлении много положительного. Автор узла сможет зарегистрировать его имя на родном языке (насколько это важно, следует, спросить специалистов по социологии), расширится набор информативных доменных имен (так, оказывается, что последовательность символов xn–b1afb6bcb отображает вполне осмысленное русское слово «сервер»). Но любая медаль имеет две стороны, и эта – не исключение. Если в имени будут присутствовать и латинские и русские символы, с какой попытки обычный пользователь наберет его правильно? (Несмотря на то что в начале статьи мы отказались от подобных имен, это совсем на значит, что так же поступят и другие.) Какая последовательность Unicode «правильна» для имени abc, напечатанного на бумаге: 97 98 99, 1072 98 99, 97 98 1089 или 1072 98 1089? И что такое xop: музыкальный коллектив или какая-то английская аббревиатура? Конечно, после ввода имени в браузере (во избежание «шуток», сродни описанной в начале статьи) сразу же отобразится его Punicode-значение, но многие ли следят за набором? А пользователей, способных расшифровать имя, представленное в формате Punicode, и вовсе единицы.

Одним словом, с введением интернациональных доменных имен вероятность успешной семантической атаки резко возрастает. Для некоторых стран опасности практически нет (вряд ли найдется иероглиф, совпадающий по начертанию с латинским символом). Для других она довольно существенная (так, например, символ «ń» при низком разрешении дисплея легко спутать с обычной буквой «n»). И, наверное, в наихудшем положении находятся страны, использующие кириллицу, а также Греция (ведь в греческом языке многие заглавные буквы неотличимы от латинских). Вероятно, имело бы смысл при регистрации доменного имени исключать из набора свободных все похожие по начертанию и «созвучию», но подобная титаническая работа вряд ли по силам регистрирующим организациям.

Обобщенные целые переменной длины

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

Допустим, что в нашем распоряжении есть цифры от 0 до 9, и мы собираемся расположить их по возрастанию весов разрядов (порядок следования little endian). В таком случае вес первой цифры (младшего разряда) будет равен 1. (Это единственное сходство с десятичной системой.) В обобщенных целых переменной длины присутствует новое понятие – порог, не использующееся ни в одной из знакомых нам систем счисления. Если цифра меньше порогового значения, это значит, что ею заканчивается текущее число. Обычно для первой цифры выбирается порог 1 (при отсутствии веских оснований для другого решения), тогда число 0 представляется одной цифрой 0. Для записи последующих значений одной цифры недостаточно. Единица не может быть последней в числе, поэтому число 1 записывается двумя цифрами: 10. По такому же принципу представляются и другие числа 2 (20), 3 (30) и т. д. до 9 (последовательность цифр 90). Для 10 значение второго разряда не может быть равно нулю, ведь цифр всего десять. В десятичной системе мы бы увеличили второй разряд на единицу и сбросили младший разряд в ноль. Но в нашем случае так поступать нельзя: цифра 0 будет воспринята как последняя и единственная в числе 0, а 1 – как начало нового числа. Поэтому в обобщенных целых переменной длины вес второго разряда выбирается равным количеству используемых цифр минус значение порога для первого. В нашем примере – это 9. В результате число 10 приходится отображать цифрами 11 (1 + + 1×9). Достаточно ли двух цифр – зависит от порога, выбранного для второго разряда. Допустим, мы выбрали его равным 3. Тогда двумя цифрами можно будет представить число 11 (21), 12 (31) и так далее до числа 27 (92). Для следующего значения (28) потребуется ноль в третьем разряде, который будет признаком окончания числа (130). Возможности двух разрядов исчерпывает число 90 (запись 990 – 9 + 9×9 = 90). Затем придется увеличивать третий, вес его будет равен (10 - 3)×9 = 63. Таким образом за 990 последует 131 (1 + 3×9 + 1×63 = 91).

«Чем же такая мудреная запись лучше десятичной системы?» – спросит читатель. Ведь мы видим, что в большинстве случаев все равно приходится завершать число нулем, выступающим в роли разделителя! Действительно, если предположить, что все числа используются одинаково часто, то такая запись не только не имеет никаких преимуществ перед десятичной системой, но и намного хуже ее. Однако предположим, что наиболее вероятными являются числа от 100 до 300, и мы знаем об этом. Тогда для двух младших разрядов целесообразнее всего задать минимальный порог, равный 1. (Одно- и двухсимвольные числа придется завершать нулем, но это не страшно, ведь они будут встречаться сравнительно редко.) В этом случае число 100 запишется как 121 (1 + 2×9 + + 1×81), а число 300 – как 363 (3 + 6×9 + + 3×81). Каким же должен быть порог для третьего разряда? Конечно 4! (Почему не больше? Дело в том, что числа, превышающие 300, хоть и редко, но могут все же встречаться. Неоправданно повышая порог, мы уменьшим вес последующих разрядов, а, следовательно, увеличим число символов, необходимых для представления больших чисел.) Теперь наиболее вероятные значения будут выражены тремя символами, как и в десятичной системе, но мы сможем записывать их подряд друг за другом, не опасаясь путаницы: ведь ясно, что 941242 – это два числа 941 и 242. Десятичная система не может похвастаться подобной лаконичностью.

Ready, set, buy! Посібник для початківців - як придбати Copilot для Microsoft 365

0 
 

Напечатать Отправить другу

Читайте также

 

Ukraine

 

  •  Home  •  Ринок  •  IТ-директор  •  CloudComputing  •  Hard  •  Soft  •  Мережі  •  Безпека  •  Наука  •  IoT