Как стать автором
Обновить

Разбираем KCaptcha, собираем заново… под .NET

Время на прочтение 4 мин
Количество просмотров 3K
KCaptcha – довольно распространенная PHP библиотека для генерации CAPTCHA. Я довольно давно знаком с этим проектом, и так же давно меня не покидает одна мысль: «как там внутри все работает, как оно все устроено»? Да, бывает такое: мозг выделяет что-то, на первый взгляд крайне неприметное и непритязательное, но затем долгое время не упускает это что-то из головы. Так было с программированием, когда я впервые увидел кусочек кода на JavaScript, так стало и с библиотекой от Сергея Круглова, которую я и решил изучить.

Но обо всем по порядку. Не буду скрывать, разобрать и понять KCaptcha я пытался много раз. Мои попытки заканчивались неудачей. Этому способствовали, и минимум свободного времени, и очень малое количество комментариев в коде, и проблемы с мотивацией (она держалась только на интересе), но главным образом, конечно, отсутствие хоть какого-то опыта за плечами.

Шло время, я то брался за KCaptcha, то опять бросал. Но раз за разом, по маленьким шажочкам приходило понимание кода. Общая картина постепенно вырисовывалась. Возможно, кому-то это покажется смешным: подумаешь, генерация случайного ключа плюс вывод на изображение! Мне так не казалось. Сейчас я смотрю на данные алгоритмы немного свысока, но память о попытках понять, казолось бы запутанный и временами не поддающийся осмыслению код, не дает возможности посмеяться над собой.

А зачем вообще ковыряться в коде? Подключил, и используй себе на здоровье! Благо, библиотека позволяет легко абстрагироваться от ненужных деталей. Этот вопрос я задавал и себе, пока мне не пришлось работать над одним ASP.NET проектом. Тогда возникла необходимость в защите некоторых страниц от спаммеров. Думаю, не нужно объяснять, что самый простой и распространенный способ защититься от ботов это каптча.

Раньше я не использовал в работе ничего кроме PHP и, рузумеется, никогда не видел CAPTCHA-решений под .NET. Быстрый поиск в гугле ничего кроме оберток ReCaptcha на C# не дал. Более глубокий анализ хостингов для opensource проктов привел к некоторым результатам, но то были давно заброшенные, незаконченные поделки. Они даже отдаленно не напоминали знакомую и уже частично изученную KCaptcha.

За все предыдущее врямя я немножко поднабрался опыта, да и с мотивацией теперь был полный порядок. Решено! Мне предстоит перенос KCaptcha с PHP на .NET.

Генерация ключа


Самая первая часть нашей программы. Именно от нее будет отталкиваться всё остальное. Алгоритм довольно простой и, может, даже типичный для своей области применения. Имеется алфавит-массив, состоящий из букв, используемых для генерации ключа. Из него случайным образом извлекаются n элементов, где n – длина ключа. Все элементарно.

Однако, даже в таком простом месте мы идем дальше! Во-первых, отбрасываем все похожие символы: Вам когда-нибудь приходилось разгадывать каптчу где присутствует 0 (цифра) или О (буква)? Приходилось? Тогда вы без труда поймете для чего это делается. Во-вторых, во время генерации следим за сочетаниями букв/цифр: некоторые символы при частичном наложении друг на друга образуют трудночитаемые комбинации. Для примера можно привести буквы r и n. Легко понять, что вместе они могут трактоваться как m.



Отрисовка


И так, строковый ключ у нас есть. Настала пора перенести его на изображение.

Тут KCaptcha оригинальна. Вместо векторных шрифтов, ставших стандартом де-факто, используется набор растровых изображений, содержащих символы алфавита. Изображения особым способом размечены. Это сделано для того, чтобы распознать обасти на которых располагаются значащие пикселы (попросту говоря – буквы).



Здесь полоса шириной в один пиксель вверху изображения – разметка, черные пикселы – значащие области, белые – пробелы между символами.

На самом деле растровые шрифты имеют некоторые преимущества: мы можем точнее позиционировать результат, обеспечивая лучшую склейку букв между собой. Кроме того – растр должен дать прирост в производительности по сравнению с вектором и обеспечить независимость от установленных шрифтов, тем самым сделав библиотеку кроссплатформенной. Однако и недостатки тоже есть: слабая масштабируемость (сильная потеря качества при изменении размеров) и предрасположенность к распознаванию (см. ниже).

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

Искажение


С этого момента мы имеем вполне пригодную для использования библиотеку. Однако, есть одно но! Результат может отфильтровать только совсем уж слабых ботов. Целенапрвленная атака такой каптчи даст очень приличный процент распознаных изображений. Все дело в том, что, при наличии у злоумышленника используемых шрифтов, взлом превратится просто в попиксельный перебор всей каптчи и сравнение его с оригинальными шрифтовыми файлами.

Но выход есть – искажающий фильтр. KCaptcha использует для этого искажение по синусу, вернее даже наложение нескольких синусоид друг на друга. Это дает гораздо более устойчивый к восстановлению результат. Итоги действия одной волны можно свести на нет по косвенным признакам, а вот с двумя и более – будет труднее.

Для сглаживания работы фильтра применяется линейная интерполяция.



Итог


Я так и не применил на практике результат своей работы из-за несостоявшегося сайта на ASP.NET. Но после доработки все вылилось в небольшой opensource проект. Внутренняя структура, алгоритмы, да и сам код достаточно отличаются от оригинала, чтобы иметь теперь свое собственное имя (над которым, впрочем, я не долго думал). Прошу не пинать сильно – NCaptcha.

Теги:
Хабы:
+23
Комментарии 24
Комментарии Комментарии 24

Публикации

Истории

Работа

.NET разработчик
68 вакансий

Ближайшие события

PG Bootcamp 2024
Дата 16 апреля
Время 09:30 – 21:00
Место
Минск Онлайн
EvaConf 2024
Дата 16 апреля
Время 11:00 – 16:00
Место
Москва Онлайн
Weekend Offer в AliExpress
Дата 20 – 21 апреля
Время 10:00 – 20:00
Место
Онлайн