Суть решения
Предложенное решение позволяет при визуальном отсутствии каких-либо раздражающих признаков в пользовательском интерфейсе и незначительном неудобстве для пользователя, сделать малоэффективым массовую рассылку спама через форму размещенную в интернете.
Пример использования
Например, у Вас есть форма обратной связи и вы не хотите её усложнять, например, капчей. Вы уже использовали все доступные способы понять, что с пользовательской стороны точно запущено нечто, похожее на браузер, что в браузере есть JavaScript, что пользователь вводит текст в форму более чем за несколько микросекунд и так далее. Но как бороться со случаем, когда практически все проверки пройдены, а спам есть?
Идея
Применить некоторую ассиметричную операцию, которая будет затратной по ресурсам для клиента и легковесна для проверки с серверной стороны. Другими словами отправка формы должна стать достаточно ресурсоёмкой операцией. Так как с точки зрения обычного польователя «повисание» браузера на 1-3 минуты является не приятной, но вполне приемлемой особенностью работы сайта, а вот для спам бота, если каждай отсылаемая форма будет «съедать» 1-3минуты 100% заргузки одного ядра процессора будет крайне неприятным сюрпризом. Также это позволит бороться со случаями, если спам рассылается именно людьми: т.е. когда и браузер настоящий и есть человек за браузером.
Причем тут Bitcoin?
Из Bitcoin взята идея Proof of work. Другими словами клиентскому браузеру нужно решить головоломку соответствющей сложности, как это делается Bitcoin майнерами: вычислить nonce + hash для некоторого поля формы, причем hash должен отвечать некоторому критерию. Операцию можно решить только перебором, который потребует существенных вычислительных ресурсов для клиента. При этом вычисленное значенеи hash + nonce можно легко проверить на сервере.
JavaScript код на стороне клиента
var isBrowserJsRuntime = (typeof exports === 'undefined');
var nonce;
if(isBrowserJsRuntime){
nonce = this['nonce']={};
} else {
jsSHA = require('./sha512');
nonce = exports;
};
nonce.nonce = function(inString){
var btc = "";
var j = 0;
var n = 0;
for( ; btc.search('123456') < 0 ; j++ ){
btc = ((new jsSHA( inString + j, 'TEXT')).getHash('SHA-512', 'HEX'));
n = j;
};
return { 'btc':btc, 'nonce':n };
};
nonce.pushButton = function(thisForm){
var fullMsg = thisForm.message.value;
var n = this.nonce(fullMsg);
thisForm.btc.value = n.btc;
thisForm.nonce.value = n.nonce;
thisForm.submit();
};
Дополнительно потреюуется любая JavaScript библиотека вычисляющая любой (ресусоёмкий) hash. Например, отлично подойдет jsSHA, в частности sha512.js
Код работает на node.js (для Unit тестирования) и в браузере Cromium. В качестве критерия подходящего hash применяется последовательность 123456. То есть nonce будет подобран таким образом, чтобы вычисленный hash содержал последовательность '123456'.
Perl код на стороне сервера
use Digest::SHA qw(sha512_hex);
sub checkProofOfWork($$$){
my $text = shift;
my $nonce = shift;
my $shaValue = shift;
if( $shaValue =~ /123456/ ){
my $digest = sha512_hex( $text . $nonce );
return $digest eq $shaValue;
};
return 0;
};
Cначала проверяем, что вычисленный hash подходит по критерию и только потом пытаемся пересчитать hash сами.
Заключение
Массовое применение подобного подхода способно существенно усложнить жизнь спамерам.
Также мне интересно мнение сообщества в отношении предложенного подхода и пути его дальнейшего совершенствования.
Автор: AxVPast