客户端应在多大程度上防止快速提交表单(JavaScript/JQuery)?

How much prevention of rapid-fire form submissions should be on the client-side (with JavaScript/JQuery)?

我有 these like buttons in a JQuery/Django tutorial 我写了:

<td id="toggle_color_like_cell_{{ color.id }}" class="td__toggle_color_like_button" data-color_id="{{ color.id }}">
    {% include "color_liker/color_like_link__html_snippet.txt" %}
</td>

其中 color_like_link__html_snippet.txt 是:

<button class="button_{% if not color.is_favorited %}un{% endif %}liked"
   >{% if color.is_favorited %}Yes{% else %}No{% endif %}</button>

The following JQuery-JavaScript 是切换点赞按钮的 AJAX 调用(它会在 "Yes" 我喜欢它和 "No" 我没有),而且,由于每次点击都会访问数据库,因此它还可以防止点击次数太 rapid/close 在一起。

我的问题是应该在客户端集成多少这样的 "attack prevention"?我猜想真正的 DDOS 很容易越过任何 JavaScript 保护,但用户可能会尝试快速单击内容,这可以说是值得防范的事情。

消除这种保护将使代码的复杂性大大降低。我不确定这里有什么最好的。

/*
   This file must be imported immediately-before the close-</body> tag,
   and after JQuery is imported.
 */
/**
   The number of milliseconds to ignore clicks on the *same* like
   button, after a button *that was not ignored* was clicked. Used by
   <link to processLike>

   Equal to <code>500</code>.

   The disabling and re-enabling is logged to the console.
 */
var MILLS_TO_IGNORE_LIKES = 500;
/**
   Executes a like click. Triggered by clicks on the various yes/no
   links.

   The disabling and re-enabling is logged to the console.

   See <link to MILLS_TO_IGNORE_LIKES>
 */

续:处理器功能:

var processLike = function()  {
   //The click listener is no longer attached to THIS button

   //In this scope, "this" is the button just clicked on.
    //The "this" in processLikeInner is *not* the button just clicked on.
   var $button_just_clicked_on = $(this);

   //The value of the "data-color_id" attribute.
   var color_id = $button_just_clicked_on.data('color_id');

    var processLikeInner = function(data, textStatus_ignored, jqXHR_ignored)  {
      //alert("sf data='" + data + "', textStatus_ignored='" + textStatus_ignored + "', jqXHR_ignored='" + jqXHR_ignored + "', color_id='" + color_id + "'");
      $('#toggle_color_like_cell_' + color_id).html(data);

      //Attack prevention. Dont process requests too close together.

      console.log('Like disabled for: ' + MILLS_TO_IGNORE_LIKES);

      setTimeout(function() {
         $button_just_clicked_on.one('click', processLike);
         console.log('Like re-enabled for color_id ' + color_id + ' ');
      }, MILLS_TO_IGNORE_LIKES);
    }

   var config = {
      url: LIKE_URL_PRE_ID + color_id + '/',
      dataType: 'html',
      success: processLikeInner
   };
   $.ajax(config);
};

续:主要功能:

/**
   The Ajax "main" function. Attaches the listeners to the elements on
   page load.
 */
$(document).ready(function()  {
   /*
      There are many buttons having the class

         td__toggle_color_like_button

      This attaches a listener to *every one*. Calling this again
      would attach a *second* listener to every button, meaning each
      click would be processed twice.

      When a button is clicked, the listener for that *single button*
      is disabled. It's re-enabled in processLikeInner with

         $button_just_clicked_on.one('click', processLike);
    */
   $('.td__toggle_color_like_button').one('click', processLike);
});

您不能从客户端脚本进行安全或攻击预防

但是如果您使用库,您尝试做的事情(同样不是安全措施)会简单得多,underscore.js 有一套很好的内置功能。

你可以使用 debounce 来完成你想要完成的事情

$('#mybtn').click(_.debounce(function(e){
    //do stuff
},500));

该按钮只会在最后一次调用它后 500 毫秒执行该函数,有效地将调用限制为最多每 500 毫秒一次...

这不是安全措施或 DDOS 预防措施您必须在服务器上执行此类操作

基于,这就是我想出的。请注意,这只需要 underscore-min.js,而不是 underscore-min.map

/**
    The number of milliseconds to ignore clicks on the *same* like
    button, after a button *that was not ignored* was clicked. Used by
    `$(document).ready()`.

    Equal to <code>500</code>.

    The disabling and re-enabling is logged to the console.
 */
var MILLS_TO_IGNORE_LIKES = 500;

续:处理器功能

/**
   Executes a like click. Triggered by clicks on the various yes/no
   links.

   The disabling and re-enabling is logged to the console.

   See <link to MILLS_TO_IGNORE_LIKES>
 */
var processLike = function()  {

   //In this scope, "this" is the button just clicked on.
   //The "this" in processServerResponse is *not* the button just clicked
   //on.
   var $button_just_clicked_on = $(this);

   //The value of the "data-color_id" attribute.
   var color_id = $button_just_clicked_on.data('color_id');

   var processServerResponse = function(sersverResponse_data, textStatus_ignored,
                                        jqXHR_ignored)  {
       //alert("sf sersverResponse_data='" + sersverResponse_data + "', textStatus_ignored='" + textStatus_ignored + "', jqXHR_ignored='" + jqXHR_ignored + "', color_id='" + color_id + "'");
       $('#toggle_color_like_cell_' + color_id).html(sersverResponse_data);
   }

   var config = {
       url: LIKE_URL_PRE_ID + color_id + '/',
       dataType: 'html',
       success: processServerResponse
       //Should probably include a "fail" call, too.
   };
   $.ajax(config);
};

续:主要功能:

/**
   The Ajax "main" function. Attaches the listeners to the elements on
   page load.
 */
$(document).ready(function()  {
    /*
        There are many buttons having the class

            td__toggle_color_like_button

        This attaches a listener to *every one*. Calling this again
        would attach a *second* listener to every button, meaning each
        click would be processed twice.

        ---

        Warning: Placing the true parameter outside of the debounce call:

        $('#color_search_text').keyup(_.debounce(processSearch,
            MILLS_TO_IGNORE_SEARCH), true);

        results in "TypeError: e.handler.apply is not a function"
        - 
        - 
    */
    // API: http://jashkenas.github.io/underscore/#debounce
    $('.td__toggle_color_like_button').click(_.debounce(processLike,
            MILLS_TO_IGNORE_LIKES, true));
});