DEV Community

Atena Dadkhah
Atena Dadkhah

Posted on

Preventing users from manipulating my form

Forms are HTML tags that we use in a variety of ways to send the data they hold from one place to another, and then possibly store them somewhere like a database.


Do you know how many different forms we have?

In my opinion we have got two different type of forms.

  1. The usual ones like login or register

  2. Some forms (I call the mysterious ones 😜) like add to cart or instant logout with a button or even edit and delete buttons in a list of items.

For the first type, using AJAX doesn't really matter but for the second one, it's essential; because we expect instant response from the website not reloading again and again every time we send a request.

We some times need to send some sensitive data like user ID or the ID of a product ...etc, this happens mostly in the second type of forms, so my main focus in this post is on this type.

Imagine we have a list of products that we've already added it to our cart.
Image description

As you see there is a tiny multiplication sign next to each item (delete) and a quantity button which should change whenever we reduce or increase the number (update).

To implement these options (delete & update) we need to know which option is being deleted or updated; in other words, we should recognize them.

How?

Well, there is just one way (as far as I know) that is specifying the ID of each item and send it along with other values to the server.
You can hash this ID or whatever you want. But there must be a value to identify which item you are operating on.

I usually do that using hidden type inputs.

<input type="hidden" name="product-id" value='1'>
Enter fullscreen mode Exit fullscreen mode

And then send it to the server.

$('form').submit(function(){
     $.ajax({
       url : url,
       type: 'POST',
       data: $(this).serialize(),
       success: function(){ alert('Success') },
       error: function(){ alert('Error') }
     })
})
Enter fullscreen mode Exit fullscreen mode

I used jQuery but you can use either pure JavaScript for AJAX request.

This process continues well and happily, but imagine the user manipulate the ID (By inspecting or developer tools in browsers) that we're sending to the server; We may then operate on the wrong item and what if the ID doesn't exist in our database? Then it will cause an error 😁

The solution is that to simply put a condition in your back-end to check if that ID exists, then do the operation.

But my purpose is to prevent users from manipulating the sensitive data of a form before submitting the form.

My idea is to reset all sensitive data before sending to the server, right after the user submits the form. In this case you can always send true data to the server (although you should keep server-side checks for sure.)

In jQuery when we want to reload child elements inside a parent element we should give an id to the parent element.

HTML:

<section id="parent">  
    <span>Banana</span>
    <span>Apple</span>
    <span>Orange</span>
</section>
Enter fullscreen mode Exit fullscreen mode

JS:

$('#parent').load(document.URL + ' #parent > *')
Enter fullscreen mode Exit fullscreen mode

By that you're resetting child elements without reloading the whole page and the user will never understand that.

Notice you should keep the space before element ID when concating to document.URL

Now let's bring this idea back to our previous example about user cart.

Imagine you have a div tag called #cart-item-{index} like this for each cart item.
(it's not necessary to have form tag when using AJAX)

<section id="manage-cart">
   <div id="cart-item-1">
        <span class="close" data-product-id="20">&times;</span>
        <div class="product-details">
          ...
        </div>
   </div>
   <div id="cart-item-2">
        <span class="close" data-product-id="23">&times;</span>
        <div class="product-details">
          ...
        </div>
   </div>
</section>
Enter fullscreen mode Exit fullscreen mode

Here data-product-id attribute shows the ID of the product (which you can hash then)

The structure is when user clicks on .close element to delete that cart item we should instantly get the ID from it's attribute, and the point is to prevent user from changing that ID and finally send the exact true value to the server server.

Lets implement it right now. πŸ˜‰

AJAX:

    $('.close').click(function(){
        const parentID = '#' + $(this).parent().attr('id')
        $(parentID).load(document.URL + ` ${parentID} > *`, function(){
            const pID = $(this).find('.close').attr('data-product-id')
            console.log(pID)
            $.ajax({
                url:url,
                type:'POST',
                data: pID,
                success:function(){alert('Success')},
                error:function(){alert('Error')},
            })
        })
    })
Enter fullscreen mode Exit fullscreen mode

As an explanation to this code I have to say, after the user clicks on the .click element we get it's parent ID which is unique. Then before the AJAX request, we reset all elements inside this cart-item then as a callback function we request to a URL and send the same product ID each time.

You see, even if we change data-product-id by inspecting the element in the browser, the console shows the same ID it was in the source code. (I console.log() the ID)

But Wait! there is a tiny bug in this code.

As we reset the .close element in jQuery after clicking on it, JavaScript actually creates this element again dynamically so we can't click on it over again.

The solution is to involve the document, in this case this problem is easily solved.

    $(document).on('click', '.close',function(){
        const parentID = '#' + $(this).parent().attr('id')
        $(parentID).load(document.URL + ` ${parentID} > *`, function(){
            const pID = $(this).find('.close').attr('data-product-id')
            console.log(pID)
            $.ajax({
                url:'index.html',
                type:'POST',
                data: pID,
                success:function(){alert('Success')},
                error:function(){alert('Error')},
            })
        })
    })

Enter fullscreen mode Exit fullscreen mode

I hope you enjoyed this post.
Have fun! 😊

Top comments (0)