PoW вместо капчи

ca4b1c44504c646981d66d06b40e9863

Для чего обычно используется капча? Для защиты от автоматических регистраций (либо автоматической отправки сообщений на форумах, в чатах, через форму обратной связи и т. п.) и для предотвращения брутфорса пары логин/пароль при аутентификации. Более экзотические случаи ее использования достаточно редки.

Сказать, что капча всем надоела и очень многих раздражает — значит ничего не сказать. Проблема еще в том, что очень и очень многие используют «облачную» капчу от одной всемирно известной корпорации… и в случае проблем с доступом к такой капче (тьфу-тьфу-тьфу) львиная доля использующих ее сайтов просто перестанет работать.

Ниже — простейший альтернативный вариант защиты от автоматической отправки сообщений и от брутфорса логина/пароля, основанный на идее PoW (proof of work, доказательство выполнения работы).

Что такое PoW

Идея PoW хорошо знакома разработчикам и пользователям криптовалютных систем и впервые была предложена, по-видимому, в 1993 году профессором Гарвардского университета, сотрудницей Microsoft Синтией Дворк (Cynthia Dwork) и израильским профессором Мони Наором (Moni Naor). Идея чрезвычайно проста: мы придумываем задачу, требующую значительных вычислительных ресурсов и процессорного времени на клиенте, но такую, что результат ее решения легко проверяется на сервере. Тем самым хакеру, от которого требуется отправить на сервер этот самый результат для получения определенных прав, потребуется существенное время, что сведет его хакерские усилия к нулю.

Идеи подобных задач (значительные ресурсы для решения — легкость проверки результата) за прошедшие 28 лет накоплены в достаточном количестве. Мы возьмем самую простейшую идею: перебор вариантов «соли», используемой для хеширования входных данных, для достижения определенного вида полученного хеша. Если алгоритм хеширования достаточно надежен, эта задача может быть решена только перебором, что и соответствует нашей цели: значительным затратам времени на клиентской стороне.

Реализация

Нам потребуется реализация алгоритма sha1 на javascript; соответствующий скрипт (в разных вариантах) можно с легкостью найти на GitHub. Далее мы пишем совсем простенький собственный скриптик:

const pow16 = str => {
   let res = '', n = 0;
   while(res != "abcd") {
      res = sha1(sha1(n.toString()) + str).substr(15, 4);
      n++;
      if (n > 1e6) return;
   }
   return n - 1;
}

Для проверки его работоспособности и временнЫх характеристик можно использовать, например, вот такую демо-страничку (pow16.js — файл с нашим самодельным скриптом):



Определенная в скрипте функция pow16(str) хеширует входную строку str сначала с солью sha1('0'), затем с солью sha1('1') и так далее до тех пор, пока 15–18-е цифры (всего 16 бит, отсюда и название функции) полученного хеша не станут равны 'abcd'. Конечно, можно взять и любой другой участок хеша, а не обязательно 15–18-е цифры (и не обязательно 'abcd', конечно). Величина 16 бит (четыре цифры хеша) получена опытным путем: 3 цифры это мало (такой скрипт выполняется практически мгновенно), а 5 цифр уже много (браузер просто виснет). Желающие, безусловно, могут поэкспериментировать с количеством бит, не кратным 4.

Функция возвращает натуральное число — количество итераций, потребовавшихся для достижения результата. В случае, если за миллион итераций результат не достигнут, возвращается undefined. Демо-страничка позволяет протестировать скрипт, показывая количество затраченного на его выполнение времени при различных входных строках.

Использование вместо капчи

Идея использования приведенной выше реализации идеи PoW вместо капчи очень проста. При отправке данных формы (например, с парой логин/пароль, с сообщением чата и т. п.) мы на клиенте вычисляем pow16 от отправляемых данных (назовем эту величину контрольным числом) и вместе с этими данными посылаем на сервер. На серверной стороне (ниже приведен пример на php) мы проверяем соответствие контрольного числа $n пришедшим данным $str и в случае несоответствия отказываем в авторизации (в приеме сообщения форума и т. п.):

if (substr(sha1(sha1($n).$str), 15, 4) != "abcd") {
   // отказываем в авторизации или ином действии
}

Замечательно, что такая реализация «антихакерской» защиты, в отличие от капчи, не требует от пользователя никаких действий и практически незаметна для него. Разумно сделать кнопку отправки формы по умолчанию неактивной, активизируя ее только после окончания вычисления контрольного числа.

Тестирование и проблемы

Приведенный выше скрипт тестировался в браузере Firefox 78.12.0esr из-под ОС Debian 10 (4.19.194–3×86_64) на компьютере с процессором Intel Core m3–7Y30 CPU 1 GHz и оперативной памятью 4 ГБ. Среднее время выполнения скрипта составило около 1 с; разброс — от 50 мс до 4 с в зависимости от входной строки. Такое время задержки решает поставленную задачу: позволяет значительно снизить эффективность брутфорса логина и пароля либо отправку автоматических сообщений в чатах или на форумах. Тестировать скрипт в других браузерах из-под других ОС и на других компьютерах мне было лень :)

Конечно, скажет въедливый читатель, хакер может взять суперкомпьютер, выполняющий этот скрипт за доли миллисекунды, и с легкостью преодолеть всю эту вашу технологию PoW. Это, безусловно, так; справедливости ради лишь замечу, что на суперкомпьютере и практически любая капча ломается достаточно быстро. Понятно, что предложенный способ замены капчи на менее раздражающую пользователя технологию PoW годится лишь для некритичных случаев, когда взлом защиты не является фатальным.

© Habrahabr.ru