Защита от спама с помощью JavaScript?

Мне было интересно, можно ли реализовать какую-то грубую защиту от флуда на JavaScript. Мой код получает события с сервера через AJAX, но иногда эти события могут быть довольно частыми (я ими не управляю).

Я попытался придумать способ борьбы с этим и написал небольшой скрипт: http://jsfiddle.net/Ry5k9/

var puts = {};

function receiverFunction(id, text) {
       if ( !puts[id] ) {
           puts = {};
           puts[id] = {};
       }

       puts[id].start = puts[id].start || new Date();
       var count = puts[id].count = puts[id].count + 1 || 0;
       var time = (new Date() - puts[id].start) * 0.001;

       $("text").set("text", (count / time.toFixed()).toString() + " lines/second");

       doSomethingWithTextIfNotSpam(text);
   }
};

который, я думаю, может оказаться эффективным против таких атак, но мне интересно, можно ли его улучшить или, возможно, переписать?

До сих пор я думаю, что все, что превышает 3 или 2,5 строки в секунду, кажется спамом, но по мере того, как время идет вперед (потому что начальная отметка была установлена ​​... ну ... в начале), злоумышленник мог просто какое-то время бездействовать и затем начать флуд, фактически никогда не передавая 1 строку в минуту.

Кроме того, я хотел бы добавить, что я использую библиотеки Mootools и Lo-Dash (возможно, они предоставляют некоторые интересные методы), но было бы предпочтительнее, если бы это можно было сделать с помощью собственного JS.

Любое понимание очень ценится!


person VariousThings    schedule 17.05.2013    source источник
comment
Скорее всего, если кто-то спамит сайт, он не использует для этого браузер (т. Е. Полностью обходит JavaScript). И в любом случае, если кто-то скопирует текст в поле ввода, ваш метод либо сломается, либо подумает, что они пытаются залить сайт.   -  person JJJ    schedule 17.05.2013
comment
@Juhana: Но я получаю события с сервера (который я не могу контролировать).   -  person VariousThings    schedule 17.05.2013
comment
Тогда я не совсем понимаю, что вы пытаетесь сделать, извините. Если события поступают с сервера, какое событие нажатия клавиши пытается захватить?   -  person JJJ    schedule 17.05.2013
comment
Я использовал keydown, чтобы продемонстрировать, что имел в виду, это могла быть простая функция (на самом деле это функция onSuccess в Mootools). Возможно, я не совсем понял это и должен это изменить.   -  person VariousThings    schedule 17.05.2013
comment
Если вы используете AJAX, вы ЗАПРОСИТЕ события, а не получите их. О каком флуде ты говоришь?   -  person Oleg V. Volkov    schedule 17.05.2013
comment
@ OlegV.Volkov: Это модель Comet, сервер отправляет события в браузер, по сути, длинный опрос XMLHttpRequest.   -  person VariousThings    schedule 17.05.2013
comment
@VariousThings, в таком случае я бы рекомендовал выполнить легкую агрегацию входящих данных и при выполнении тяжелых задач (например, перерисовки пользовательского интерфейса) только с определенным порогом, используя ранее агрегированные данные.   -  person Oleg V. Volkov    schedule 17.05.2013


Ответы (3)


Если вас беспокоит частота срабатывания той или иной функции javascript, вы можете debounce эту функцию.

В вашем примере, я думаю, это будет примерно так:

onSuccess: function(){ _.debounce(someOtherFunction, timeOut)}; 

где timeout - максимальная частота вызова someOtherFunction.

person RYFN    schedule 17.05.2013
comment
onSuccess функция, которую я использую, довольно сложна и зависит от возвращаемых выходных данных каждой отдельной функции (типы событий, например, подключено, отключено и т. Д.). Проверяя исходный код, кажется, что его устранение вернет результат последнего вызова функции, который может сломать и без того хрупкий код. - person VariousThings; 17.05.2013
comment
Уже хрупкий код? - похоже, пора рефакторинга ... :) - person milgner; 17.05.2013
comment
@ma_il: Ха-ха, может быть. Мне пришлось бы все заново изобрести, и если это сработает, не чините, это вроде как применимо здесь. - person VariousThings; 17.05.2013
comment
честно говоря, вы могли бы потенциально отклонять каждое событие по типу отдельно? - person RYFN; 17.05.2013

Я знаю, что вы спрашивали о собственном JavaScript, но, возможно, взгляните на RxJS.

RxJS или Reactive Extensions для JavaScript - это библиотека для преобразования, составления и запроса потоков данных. Мы также имеем в виду все виды данных, от простых массивов значений до серий событий (неудачных или нет) до сложных потоков данных.

На этой странице есть пример, который использует метод throttle для «игнорирования значений из наблюдаемой последовательности, за которыми следует другое значение до времени выполнения» (см. source).

keyup = Rx.Observable.fromEvent(input, 'keyup').select(function(ev) {
            return ev.target.value;
        }).where(function(text) {
            return text.length > 2;
        }).throttle(500)
        .distinctUntilChanged()

Может быть аналогичный способ получить 2,5–3 секунды в секунду и игнорировать остальные события до следующей секунды.

person Kevin Hakanson    schedule 17.05.2013

Я много дней размышлял об эффективных мерах по предотвращению переполнения сообщений, пока не наткнулся на решение, реализованное где-то еще.

Во-первых, нам нужны три вещи: переменные штрафа и счета, а также момент времени, когда произошло последнее действие:

var score = 0;
var penalty = 200; // Penalty can be fine-tuned.
var lastact = new Date();

Далее мы уменьшаем оценку на расстояние между предыдущим сообщением и текущим во времени.

/* The smaller the distance, more time has to pass in order
 * to negate the score penalty cause{d,s}.
 */
score -= (new Date() - lastact) * 0.05; 

// Score shouldn't be less than zero.
score = (score < 0) ? 0 : score;

Затем мы добавляем штраф за сообщение и проверяем, не превышает ли оно пороговое значение:

if ( (score += penalty) > 1000 ) {
   // Do things.
}

Не забудьте потом обновить последнее действие:

lastact = new Date();
person VariousThings    schedule 17.06.2013