DEV Community

Cover image for Why Client-Side Permissions Aren’t Enough
Daniel Mutuku
Daniel Mutuku

Posted on

Why Client-Side Permissions Aren’t Enough

As a web developer, I often take on projects involving feature enhancements or bug fixes for existing applications. A recurring theme in these projects is the heavy reliance on pre-built applications from platforms like Codecanyon. In fact, around 80% of the projects I've worked on stem from there. While these ready-made solutions offer a quick and efficient way to deploy applications, they often come with hidden pitfalls that developers overlook. One of the most common and dangerous pitfalls is poor handling of permissions and security validation, especially when relying too much on client-side attributes.

Mistake 1: Handling Permissions with “hidden” or “disabled” Attributes

One of the most frequent mistakes I encounter is developers depending entirely on frontend attributes like hidden or disabled to control permissions. Here’s a typical example:

<button class="btn btn-primary" data-toggle="modal" 
 data-target="#add_user_modal" 
 @if(!auth()->user()->can('add.user')) disabled @endif>
</button>

<div id="add_user_modal" class="modal-dialog modal-md modal-dialog-centered" 
 @if(!auth()->user()->can('add.user')) hidden @endif>
</div>

Enter fullscreen mode Exit fullscreen mode

In this example, the intention is to prevent users without the add.user permission from accessing the button and modal. However, this method opens the door for unauthorized users to exploit the application by simply inspecting the page and using a little JavaScript to remove the disabled and hidden attributes:

let button = document.querySelector('.btn.btn-primary[data-toggle="modal"]');
let modal = document.querySelector('#add_user_modal');

// Enable the button
if (button.hasAttribute('disabled')) {
  button.removeAttribute('disabled');
}

// Show the hidden modal
if (modal.hasAttribute('hidden')) {
  modal.removeAttribute('hidden');
}
Enter fullscreen mode Exit fullscreen mode

By running the above code, even a user who isn’t authorized to add a user can bypass the frontend restrictions, gaining access to the functionality. Relying solely on these client-side restrictions is insecure and should never replace proper server-side validation.

Mistake 2: Using "readonly" or "hidden" Fields for Critical Values

Another similar mistake I often encounter is the use of readonly or hidden input fields for critical data such as total amounts in e-commerce platforms. For instance, developers may make the "Total" field read-only or hide it entirely, assuming users can't tamper with it:

<input type="number" name="total" value="100" readonly>
Enter fullscreen mode Exit fullscreen mode

The problem arises if the backend fails to revalidate this field before saving the data. An attacker can inspect the field in their browser, modify its value, and submit an altered form:

document.querySelector('input[name="total"]').value = "1";
Enter fullscreen mode Exit fullscreen mode

This kind of manipulation can lead to unauthorized changes to key data, such as lowering the total order amount in a shopping cart. As a developer, it's essential to perform all critical calculations and checks server-side to ensure the integrity of the data.

The Importance of Server-Side Validation

Both of the above examples underscore the critical need for server-side validation. While frontend attributes like hidden, disabled, and readonly can enhance user experience by hiding or disabling unauthorized elements, they must not be relied upon as security mechanisms. Client-side code can be easily manipulated by anyone with access to the browser's developer tools.

To safeguard your application, always ensure that proper permission and data validation is performed on the backend. This guarantees that even if a user attempts to bypass frontend restrictions, they won’t be able to access or alter sensitive functionalities or data.

Other Common Client-Side Security Mistakes in Pre-Built Apps

  1. Storing sensitive information in JavaScript:
    Developers sometimes store API keys, session tokens, or other sensitive data in the JavaScript code. Since this code is sent to the user's browser, it's easily accessible to anyone who inspects the code. These should always be handled on the server-side.

  2. Relying on client-side form validation:
    While using HTML5 attributes like required or pattern for form validation is convenient, never trust them for critical validation. Users can easily bypass this by disabling JavaScript or manually submitting a request. Always validate inputs on the server.

  3. Insecure AJAX requests:
    AJAX requests often expose endpoint URLs that may allow unauthorized actions if not properly secured. Ensure that each request is authenticated and authorized server-side.

Thank you for taking the time to read this article! If you'd like to see more content like this, feel free to follow me. If you need assistance with Mpesa or any other API integrations, don't hesitate to reach out via Email or connect with me on LinkedIn. I'm also building ThulaZone, a collection of free, ad-free tools designed to simplify your day-to-day tasks - things you might usually pay for elsewhere. Be sure to check it out and see what I've created for you.
Keep striving, stay inspired. Until next time - Adios!

Top comments (0)