Кстати, Минкомсвязь до сих пор исключает ЛЮБУЮ возможность утечки паспортных данных избирателей
Между тем распределение серий паспортов выглядит вот так:
Давайте воспроизведем события и попробуем понять как всего этого можно было избежать
Что произошло?
9 июля появляется материал Медузы Власти фактически выложили в открытый доступ персональные данные всех интернет-избирателей где они рассказали про архив degvoter.zip.
Как найти архив degvoter.zip?
Я нашел так. Внимательный поиск через Yandex привел меня к странице:
vudu7.vuduwiki.duckdns.org/mk.ru/https_check.ege.edu.ru.html
Там был найден текст «Https checkvoter.gosuslugi.ru degvoter.zip». Датировка на тот момент была 7.7.2020 (до публикации Медузы!), сейчас этот текст уже «переехал» на начало страницы и датировка изменилась.
Сам архив был убран с сайта госуслуги, но его копия сохранилась в web.archive.org, откуда его скачали все заинтересованные в исследовании лица в том числе и я. Чтобы понять почему так произошло рекомендую обратиться к первоисточнику — файлу robots.txt на сайте ГосУслуги.
Что внутри degvoter.exe?
Сама программа degvoter написана на C# и представляет из себя написанное «на коленке» WinForms приложение, которое работает с sqlite базой данных. Файлы в архиве датированы 2020-06-30 22:17 (30 июня 2020 года). Видно, что приложение писалось в кратчайшие сроки, ибо на Камчатке в этот момент уже было 1 июля 7:17, а тот факт, что участки открывались там в 8:00 говорит о том, что дедлайн был как никогда близок (хорошо что электронно голосовали только Москва и Нижний Новгород).
Код проверки паспорта:
Приложение как с архитектурной точки зрения, так и с криптографической — адовейший говнокод. И вот почему:
Описание просчетов архитектуры и принципа атаки на восстановление индентификаторов паспортов
В комплекте с программой находилась локальная БД в которой находилась таблица passports с двумя полями num и used. Где num было SHA256(<серия>+<номер>).
Очень часто, когда программист без соответствующего опыта подходит к вопросам криптографии, он делает кучу однотипных ошибок. С одной из таких ошибок относится применение хэш-фукнции без какой либо обвески. Идентификатор паспорта состоит из 4-ех циферной серии и 6-циферного номера [xxxx xxxxxx]. Т.е. у нас 10^10 вариантов. Номер телефона, к слову, состоит также из 10 цифр [+7(xxx)xxx-xx-xx]. В масштабах современного цифрового мира это не такие большие цифры. Так один Гбайт – это больше 10^9 байт, т.е. 100Гбайт хватит чтобы записать все варианты. Вполне вероятно что их банально можно перебрать. Я измерил что в однопоточном режиме современный Intel Core i5 процессор перебирает все sha256 хеши для одной серии паспорта за 5 секунд (000000-999999). И это на стандартной реализации sha256 без каких либо дополнительных ухищрений. Т.е. полный перебор всего пространства на обычном компьютере займет меньше дня. Если же учесть, что перебор можно вести в несколько потоков, то средненький процессор справится с такой задачей за несколько часов. Это является демонстрацией факта непонимания разработчиком системы принципов использования хеш-функций. Но даже правильное применение хэш-функций при такой архитектуре не спасает паспортные данные от раскрытия, если противник имеет неограниченные ресурсы. Ведь человек получивший доступ к БД может за конечное время получить идентификаторы паспортов, т.к. проверка одного паспорта должна проходить конечное время. Весь вопрос только в ресурсах (хотя если бы здесь просто применили хэширование в пару миллионов раундов, даже такое спорное архитектурное решение, как распространение БД вместе с приложением, не привело бы к такому громкому эффекту, т.к. позволило бы защититься хотя бы от журналистов). Медуза всего лишь продемонстрировала некомпетентность людей, проектировавших эту часть системы.
Давайте попробуем придумать, как сделать с одной стороны сильно лучше, с другой стороны уложиться также в одну ночь разработки.
Архитектура на коленке
Предположим, что у нас вообще нет времени и надо написать решение в течении ночи.
Очевидным требованием является то, что БД с хешами паспортов должна находиться на сервере и это обязательно должно быть клиент-серверное приложение. Сразу же возникнет вопрос, а что делать если вдруг на участке сломается Интернет? Для этих целей нужно сделать Android-версию клиентского приложения, которую нужно также дать скачать членам УИК. В местах, где нет ни интернета, ни сотовой связи на этом голосовании люди не голосовали.
Хэш в базе не должен вычисляться непосредственно из идентификатора паспорта. Это делается для того, чтобы хэши в базе нельзя было подобрать, используя существующие таблицы для перебора. Во-первых, нужно использовать стойкую-хеш функцию. Главный вопрос в том, КАК её нужно использовать. Возможных реализаций тут много, но по сути всё сводится к применению алгоритма в котором будут три параметров: тип хеш-функции, количество итераций, а также значение(я) которое нужно использовать для подмешивания к хэшу (оно будет общее для всех хешей). Конечное требование – внутри каждой итерации должен быть использована стойкая хеш-функция, а скорость вычисления хэша должна быть несколько единиц в секунду. Даже завладев БД с сервера злоумышленнику в этом случае потребовалось бы значительное время на восстановление всех данных.
Каждое из клиентских приложений будет представлять из себя просто поле ввода + Http-клиент, которые отправляет запрос на сервер.
Сервер работает только по HTTPS и только во время голосования и имеет ограничение в 1 RPS с IP. В качестве ограничителя RPS используем Redis, куда пишем в качестве ключа IP-адрес и TTL в одну секунду. Есть значение – запрос с IP не разрешен, нет значения – запрос с IP разрешен. Это даст возможность избежать перебора извне.
Написанное таким образом наше, буквально из говна и палок, решение окажется на порядок более защищенным чем текущее degvoter. При этом разница во времени написания невелика и с сам процесс написания кода может быть распараллелен на 3 человек (сервер, win-client,android-client).
Разберем возможные сценарии утечек.
У нас есть следующие точки где можно получить информацию о системе
- Исходный код серверной части
- Скомпилированные файлы серверной части
- Серверная БД
- Клиентские приложения
Клиентские приложения в этом случае не несут никакой информации, при этом к ним имеет доступ максимальное число людей и именно здесь максимальная вероятность утечек (что и произошло).
Для того чтобы восстановить информацию потребуется получить доступ к информации из точек (1,2) или (1,3). Если есть только база, то без известного метода хеширования восстановить что-то будет невозможно.
Выводы
- Каждый раз, когда нужно в каком-то виде работать с персональными данными — привлекайте архитектора
- Каждый раз, когда нужно в каком-то виде работать с персональными данными — привлекайте разработчика с опытом/образованием в сфере криптографии или информационной безопасности
Эти два простых правила помогут избежать позора, который мы наблюдали на примере с приложением degvoter, (Помните, что обычный разработчик может и не разбираться в нюансах применения хэш-функций)
Утилита для демонстрации возможности восстановления персональных данных DegvoterDecoder находится в репозитории, посвященном анализу данных голосования. По-умолчанию она настроена на 8 потоков. В случае если вы уже скачали архив degvoter.zip и вы программируете на C# – вы без труда разберетесь в принципе её работы.
github.com/AlexeiScherbakov/Voting2020
Iqorek
А вот тут проблема, где хранить это общее значение? Как минимум сервер в нем нуждается и если соль утекла, останется вычислить хеши все тех же 10^10 вариантов.
VolCh
С самим номером и хранить соль. В чём суть — на каждый номер нужно будет полный перебор запускать, на каждый 10^10 вариантов проверить
Iqorek
Если соль уникальная для каждого номера, тогда ок.
wataru
Я тоже так сначала подумал. Но уникальная соль в этой схеме ничем не лучше одной для всей таблицы. Ведь для проверки паспорта надо как-то по номеру взять нужную уникальную соль. А значит это же можно делать и при переборе.
Уникальная соль работает, когда она уникальная для какого-то одного идентификатора (логин), а перебирать надо другой (пароль).
Iqorek
Подведу итоги:
1. Уникальную соль на базе номера нельзя сделать, потому что это принципиально ничего не меняет
2. Уникальную соль не на базе номера, например гуид или время, тоже нельзя, потому что как потом идентифицировать?
3. Не уникальная соль может утечь с базой.
Какие варианты остались?
wataru
Неуникальная соль для борьбы с радужными таблицами + сложный долгий хеш.
Kolonist
Ну да, какой-нибудь bcrypt/scrypt или PBKDF2.
Kolonist
В качестве уникальной соли можно использовать, например, ФИО или дату выдачи паспорта.
tyomitch
А найти её там как, если нехешированный номер паспорта не хранится?
Kolonist
Да-да, пока вы отвечали, я уже понял, в чем тут проблема.
Wyrd
Спросить у пользователя? Он ведь знает свое ФИО и дату рождения…
jerky
Да, да. Просто взять из паспорта любое поле в качестве соли. Дату рождения, выдачи, имя, фамилию, все вместе. Член УИК при проверке должен видеть паспорт перед собой по процедуре.
gecube
или не паспорт....
http://cikrf.ru/izbiratel/interesting/labzin/otv.html
jerky
Справедливо, но авторы (менеджеры проекта) вот этого всего (судя по результату) то же не предусматривали.
Serge3leo
Во-вторых, действительный номер паспорта, в обезличенном виде, «персональными данными» не является (по крайней мере, МВД предоставляет сервис по проверке номера). Но, совместно с именем и фамилией, это уже точно не обезличенные, и это уж гарантировано «персональные данные», поэтому приложение обязано удовлетворять требованиям соответствующего закона.
Наверное, оставаясь в сравнительно “обезличенном” виде, можно было бы добавить собственно номера паспорта: дата выдачи, код подразделения, номер ранее выданного паспорта, но смысл такого добавления всё равно неясен.
tyomitch
Тогда зачем Минкомсвязи устроило истерику «у нас там не номера, а непонятные значки» и «мы ничего не публиковали, кто устроил утечку, тот и виноват»?
Если бы они хранили номера открытым текстом, а саму программу держали на виду — то Медузе даже писать было бы не о чем.
Serge3leo
Истерике закон не писан, но формально:
Если в той или иной модели нарушителя есть способ сопоставить номер и лицо, то это персональные данные, если у нарушителя нет таковой возможности, то данные обезличенные.У Минкомсвязи (в истерике) и МВД могут быть разные мнения на сей счёт. А уж Медуза? Ну Медуза, уж придумает о чём написать, причём на любую тему, это ж её хлеб с маслом.
jerky
Вы абсолютно правы, написал не очень подумав. Более, как мне кажется, хорошая схема решения.
Serge3leo
Да, там, термин «соль» применён корректно.
В той схеме неплохо, что и рабочий код, и код подбора, могут работать в одинаковых условиях, т.е. многопоточно, векторно, и т.п. (с точностью до коэффициента, рабочий код проверяет ~1/2 базы, код опробования всю базу, но, вероятно, код опробования более оптимизирован)
Но назвать «ту схему» «решением» — нельзя.
Замечу, что, по моему личному мнению, «обезличенный» номер паспорта, если его нельзя связать с какими-либо «личными» реквизитами, не требует защиты, поэтому как не сделай, всё неплохо. Однако, в контексте оценки «той схемы», как «решения», предположим что требуется «защитить номера паспортов от раскрытия неким нарушителем».
Как бы, если взглянуть на возможности потенциальных нарушителей к опробованию номеров по сравнению с возможностью компьютеров избирокома или наблюдателей:
При этом, если взглянуть на график распределение серий паспортов, можно заметить, что для раскрытия 80..90% номеров паспортов требуется осуществить не более 107 опробований. Т.е. если член избиркома или наблюдатель проверяет номер паспорта за ?1 секунду, то более менее крутой нарушитель раскроет 80% номеров за ?200 секунд.
Таким образом, задачу защиты собственно номера паспорта «та схема» не решает.
Мало того, «та схема» не решает и задачу защиты от критики со стороны пристрастных аудиторов. В самом деле, с точки зрения аудитора безопасности даже уже один раскрытый номер паспорта это уже вполне себе результат. Но, учётом того, что доля удалённо голосующих ? 5...10%, то каждые 10...20 опробований будут выдавать очередной номер паспорта (т.е. каждые 20...40 с даже для точно такой же машинки, как в УИКах).
Лично я бы, за «решение» гипотетической задачи «защитить номера паспортов от раскрытия» мог бы начать думать бы, если бы потенциальный нарушитель мог бы восстановить номер паспорта с вероятностью не выше 10-2 в течении нескольких лет, как минимум миниморум. Ну, а поскольку, все мы люди, все ошибаемся, то для надёжного «решения» наши оценки сроков и вероятностей должны быть на много порядков лучше. Однако, ни в самой этой статье, ни в комментариях, увы, как мне кажется, нет ничего и близко к «решению» сей гипотетической «задачи».
Tab10id
Суть в том что мы хэшируем не просто номер паспорта, а номер паспорта + что-то еще, чем усложняем перебор.
symbix
Неуникальная соль — это вообще не соль, а перец.
Соль хранится вместе с хэшем. Откройте /etc/shadow на любом линуксе и посмотрите: там знаком $ разделены идентификатор типа хэш-функции, соль и сам хэш.
Смысл соли не в том, что она секретная — ровно наоборот. Смысл в том, чтобы удлиннить плейнтекст случайными данными настолько, чтобы rainbow tables ничего не дали.
Возможных номеров паспортов, конечно, совсем немного по сравнению с возможными паролями, потому соль поможет не сильно — на современном оборудовании перебрать тот же sha-256 даже с каждой конкретной солью 10^10 комбинаций не так долго (а учитывая, что известны невалидные номера серий, и того меньше) — ну, вместо того, чтобы расшифровать всю базу на подручном ноутбуке, арендовали бы кластер в амазоне на денек, вот и все.
Потому в дополнение к соли еще надо ооочень медленную и memory hard хэш-функцию. Argon2i, например. Этого бы вполне хватило, чтобы расшифровать было достаточно дорого и бессмысленно — в данном конкретном случае (нафиг нужны голые номера паспортов через три месяца, и зачем тратить десятки тысяч долларов на их расшифровку)?
А по-хорошему, конечно, если исходить из необходимости работать офлайн, надо еще дополнительно каждому УИКу зашифровать данные его публичным ключом. Но такая инфраструктура за пару дней не развертывается, конечно.
tyomitch
Смысл соли — в том, чтобы перебирать номера паспортов приходилось для каждого хэша по отдельности, т.е. увеличить пространство перебора в миллион раз — по числу записей в базе.
symbix
Да, разумеется, в том числе и это, упустил в цепочке рассуждений как очевидное. На хабре образца 2020 года надо все разжевывать, да. Все никак не привыкну.
khim
С этого момента поподробнее. Как это у вас будет работать, извините?
Либо вы в миллион раз замедлите также и проверку каждого номера в приложении, либо ничего не замедлится и у переборщика…
tyomitch
Применительно к degvoter — никак не будет работать без требования впридачу к номеру паспорта ещё каких-нибудь данных для поиска соли в базе.
Вы про это?
khim
Я про то, что если в техзадании написано что вводится только лишь номер паспорта, то «ещё каких-нибудь данных» у вас нету. То есть придётся тупо перебирать уже в самой программе все варианты.
tyomitch
Претензии к тому, кто составлял такое ТЗ.
symbix
А в чем проблема с тем, что проверка номера паспорта в приложении займет пару секунд?
khim
Если соль будет своя для каждой строчки, а не для всей базы, то там речь будет идти не о паре секунд, а о паре часов.
Это если сделать много раундов. Если же делать один — то код усложнится, а устойчивость к взлому — не возрастёт. Зачем такое нужно?
symbix
Для нормальной проверки из приложения какая разница, какая там соль?
Как раз один хэш должен вычисляться 2-4 секунды на среднестатистическом современном CPU. Для проверки конкретного паспорта это вполне приемлемая задержка. А отбрутфорсить хэш уже будет настолько дорого, что это теряет всякий смысл.
khim
Алё, алё, алё! Для тех кто, в танке: типичный случай для данной программы — это не ситуация, когда паспорт в базе есть, а как раз наоборот — вариант, когда его там нет!
И чтобы в этом убедиться вам нужно будет для каждой строчки рассчитать хеш-сумму (раз уж вы засолили их по разному) и убедиться что она не совпадает.
А вы тут накрутили раундов столько, что у вас одна проверка две секунды занимает. Миллион раз по две секунды — это нифига не «приемлемое время для выдачи бюллютеня».
symbix
А, ну да, туплю :-)
Ну тогда действительно в качестве соли надо взять что-то известное из паспорта, например, хэш от даты выдачи и кода подразделения.
khim
Радикальное решение — блум-фильтр, который можно настроить так, чтобы повторно проголосовать могли, скажем, 0.01% (или даже 1%: тут же важно, что блум-фильтр не даст вам простого способа определить кто именно может повторго головать, если у вас нет базы со всеми проголосовавшими, так что реальное влияние на результаты будет пренебрежимо мало).
Но это требует обратной связи от разработчиков к постановщикам задач, что… в косконторе… нереально, увы.
symbix
Блум-фильтр — красивая идея, но всегда может возникнуть подозрение, что он настроен уж слишком специально. :-)
khim
Это вообще большая проблема ещё с античных времён.
Но лучше всего её описывает Мерфи: Любая, даже самая сложная, проблема обязательно имеет простое, легкое для понимания, неправильное решение.
И дальше у вас дилемма: сделать то, что реально решает проблему — и получить полный ушат… ммм… «критики в прессе». Либо применить вот то самое… а потом ваши потомки будут вас проклинать «за развал страны».
tyomitch
Это не так: отметка о том, что человек зарегистрирован на электронное голосование (или откреплён на другой участок), у УИКа уже есть в бумажных списках. Незарегистрированных нет никакого смысла проверять программой.
gecube
приемлемое. Думаете сотрудник УИК быстрее вписывает данные в реестр избирателей? Или давайте поговорим об эффективности "голосования на дому"?
К тому же каждый участок формируется так, чтобы на нем было вполне внятное количество избирателей. Я не помню точных значений. Но вряд ли участок — это больше 10-20 тыс. избирателей, а скорее даже попросту несколько тысяч. На 5-6 членов УИК. Можете посчитать пропускную способность )
tyomitch
По закону — не больше трёх тысяч избирателей на одном участке.
alexeishch Автор
А как вы в таком случае по базе будете искать?
Это если вам нужно хешировать пароли, то, действительно, правильное решение это хеширование конкатенации соль+пароль. Но в данном случае нам нужно искать по полученному набору, поэтому разная соль для каждого паспорта не подходит. В данном случае нужно нестандартное применение алгоритма хеширования (не имеющее в данный момент таблиц подбора) + математическое замедление вычисления хеша.
authoris
Я не безопасник, но уникальную соль можно получить из того что имеем.
В паспорте помимо номера есть и другие данные.
Солью может быть
sha256(Последняя буква имени + Последняя буква фамилии)
Тогда итоговый хеш будет таким:
sha256(Номер паспорта + sha256(Последняя буква имени + Последняя буква фамилии))
Но я думаю самым разумным решением было бы не хранить эти данные дольше чем нужно (как и любые другие данные)
UPD: Уникальную в том смысле, что не общую соль для всех.
alexeishch Автор
Не, смотрите. Там член УИК вводит именно номер паспорта и больше ничего. Никаких других данных.
Iqorek
Сгенерировать соль из номера, будет достаточно.
alexeishch Автор
Так это и есть нестандартное применение хеша. Но этого недостаточно. Нужно чтобы хеширование шло в миллион раз медленней, чем просто вычисление одного sha256 хеша
Iqorek
Уязвимость не в том что sha256 слишком быстрый, уязвимость в том, что количество возможных вариантов конечно и не такое большое — 10^10. Нужно увеличить количество этих вариантов.
Я бы взял хеш от номера, разбил бы его на 2 части, первую часть склеил с началом номера, вторую с концом и вычислил бы хеш от того, что получилось.
tmin10
Разве вы не изобрели просто новую хеш функцию?
alexeishch Автор
Посмотрите внимательно у вас всё равно количество входных данных осталось то же — 10^10. Просто усложнилась хеш-функция, которая стала составной. В этом как раз суть проблемы — соль неприменима в этом режиме использования.
Iqorek
Да, вы правы. Проблема достаточно интересная, глубже, чем кажется на первый взгляд.
alexeishch Автор
Это как раз к вопросу почему при таких задачах нужны люди с опытом по криптографии/ИБ
Правильно решить эту задачу может человек, который знаком не только с тем как работает хэш-функция, но и с методами атак на них.
Вы же постепенно шаг за шагом задумываетесь о тех вещах, которые разработчик с соответствующим опытом уже знает :-)
khim
Проблема стара как мир и имеет решение тривиальное до безумия. Тупо берёте произвольную соль и считаете SHA512(соль+номер) — миллион раз. Подбираете число повторений, чтобы вся ваша таблица обработалась за пару часов. Всё.
Соль нужна большая и случайная — она защищает вас от того, что кто-то вложится в суперкомьютер и научится все таблицы во всех программах, так устроенных, проверять одновременно. Тратить миллион часов машинного времени на одну единственную табличку — никто не будет.
GomboTs
Простое же решение — солью должна быть фамилия избирателя (производное от нее).
khim
В программу вводится только номер паспорта.
И да — возможно это не самое лучшее решение, да, но у исполнителей точно не было возможности на него влиять.
wolfer
как раз в замедлении весь цимес. Если у вас скорость алгоритма 1 хэш в секунду, то вам на 1 паспорт понадобится 10^10 секунд, то бишь более 300 лет. Сверху все это солится как защита от радужных таблиц.
Iqorek
В замедлении свои минусы, нужно подобрать такое замедление, которое не задушит свой сервис, но при этом перебирать было бы достаточно долго.
Допустим одна секунда на хэш это многовато, допустим есть 100 миллионов избирателей с правом голоса, чтобы высчитать хеши для всех их нужно потратить более 1000 дней процессорного времени. Тогда чтобы уложиться в один день выборов, нужно не менее 1000 серверов только на вычисление хешей. Такие вот расчеты на коленке.
wolfer
нужна 1000 потоков, а не серверов. Задержка не обязательно же лочит весь сервер. Поток вполне может отдавать управление на время ожидания
Iqorek
Мне не известны хеш алгоритмы, которые в процессе вычисления чего то ожидают и процессор простаивает.
anonymous
Думаю, из Rip van Winkle cipher можно сделать!
blog.valerieaurora.org/2007/10/24/amusing-cryptography-apocrypha-the-rip-van-winkle-cipher
:)
wolfer
а кто мешает после отработки алгоритма подождать перед возвратом результата
result = sha512(input)
sleep 1
return result
условно
tyomitch
Переборщик-то не будет ждать.
wolfer
а, вы об этом кейсе. Я просто рассуждал в контексте того что предлагал ТС, когда вычисления и база на стороне сервера и требования к защите от перебора самих значений меньше.
В этом случае да, только раунды
Maksclub
Это тоже можно менять, например регламентом заставить вводить дату рождения
anonymous
Полный перебор не нужен т.к:
— номера паспортов не уникальны (не спрашивайте меня, я не отвечу), просто посмотрите на портал госуслуг и вспомните что там СНИЛС, а не номер паспорта. Подробностей тут не расскажу
— в отличие от других кодов у него нет проверочного номера
— первые 2 цифры серии паспорта — это код субъекта федерации(коды по ОКАТО), следующие 2 цифры серии — это номер года печати бланка, как правило соответствует или предшествует дате выдачи паспорта.
— остальные цифры инкрементальны, но нет какого-то известного алгоритма как они распределялись по УФМС/ОВД для выдачи поэтому нельзя оценить по номерам паспортов, например, общее число выданных паспортов за год или дату выдачи конкретного.
Об этом очень подробно написал Иван Бегтин у себя в ТГ канале.
Rsa97
Сочетание «серия + номер» паспорта — уникально и однозначно определяет бланк паспорта. Но паспорт подлежит замене по возрасту, при утере, при смене имени и/или фамилии. При этом новый паспорт выдаётся на новом бланке, с другими серией и номером.
СНИЛС же выдаётся один раз и не меняется, поэтому может служить уникальным идентификатором.
WinLin2
У человека может быть два СНИЛС. Так как Пенсионный фонд большой и неповоротливый, то разные его отделения используют разные СНИЛС. Это из практики и общения с ПФР.
khim
Странно. У меня практика ровно противоположная. Мне оформляли первый раз СНИЛС в школе, где я подрабатывал. Потом я закончил универ и устроился на фуллтайм. Бухгалтер, не зная о школе, оформила СНИЛС ещё раз.
В результате я получил две карточки, где были разные регионы (Москва и Московская область) — но одинаковый номер.
И это было много лет назад, больше 10… у них там регресс случился, что ли?
Tyusha
Насчёт порядка нумерации паспортов надо наших солсберецких Петрова и Баширова спрашивать.
K0styan
Похоже у меня бланк из будущего.
alexeishch Автор
Оно зашито в исполняемом коде сервера.