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

老子叫甜甜 提交于 2019-12-12 10:24:20

问题


I have these like buttons in a JQuery/Django tutorial I wrote:

<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>

where color_like_link__html_snippet.txt is:

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

The following JQuery-JavaScript is the AJAX call to toggle the like button (which changes the text between "Yes" I like it and "No" I don't), and, since each click hits the database, it also prevents clicks that are too rapid/close together.

My question is how much "attack prevention" like this should be integrated on the client-side? I am guessing a true DDOS would easily get past any JavaScript protection, but a user could try to just click things rapidly, and that is arguably something worth protecting against.

Eliminating this protection would make the code significantly less complicated. I'm not sure what's best here.

/*
   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>
 */

Continued: Processor function:

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);
};

Continued: Main function:

/**
   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);
});

回答1:


You cannot do security or attack prevention from client side script

But what you are trying to do ( again not a security measure ) is a lot simpler if you use a library, underscore.js has a pretty good set of functions built into it.

you can use debounce for what you are trying to accomplish

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

The button will only execute the function 500 milliseconds after the last call to it, effectively limiting the call to once every 500 milliseconds at most...

This is not a security or a DDOS prevention measure you have to do that sort of stuff on the server




回答2:


Based on konkked's answer, this is what I came up with. Note that this only requires underscore-min.js, not 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;

Continued: Processor function

/**
   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);
};

Continued: Main function:

/**
   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"
        - https://stackoverflow.com/questions/24283006/e-handler-apply-is-not-a-function-in-jquery-table-sorter
        - https://stackoverflow.com/questions/22588794/firefox-only-error-with-jquery-handleobj-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));
});


来源:https://stackoverflow.com/questions/28309850/how-much-prevention-of-rapid-fire-form-submissions-should-be-on-the-client-side

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!