Is your website’s URL properly secured?

May 15, 2020 Karol Joński

Introduction

Every computer system has been created to process data and websites are not an exception. You can experience data processing every day – while scrolling your favorite social media or checking invoices from your electricity supplier.
Many systems have data storage solutions, and in many cases they rely on a database with auto-incrementing IDs on almost every table.
Websites are accessible under URL addresses and which may cause a security problem…

The Problem

URL is often an integral part of the service’s API and is used as an interface to the service’s data. Some simple examples include:

- GET /invoices/47833
- GET /articles/7983
- GET /users/9908

Can you see any problems here? Yes – data exposition!

If you are a company, your competitors may now discover your internal data – at least the size of your business. By looking at the GET /users/9908 URL (/users/{id}), they can easily change it to GET /users/1 and if that shows data, they can assume that there are at least 9908 users in your system. With an easy script/Postman assistance it is possible to iterate* over the given URL (++id) and count every 200 response to get the total number of users.
Besides unveiling the number of users or invoices, your finite resources may become another problem. Imagine you have an e-commerce website with some custom/unique photos of articles that can be easily downloaded by iterating over URLs related to the specific article.

*skipped possible usage of security mechanisms (count/limit possible URLs calls from one client/IP address etc.)

The Solution

What can you do to avoid data exposition or outright database download?
One of possible solutions is ID obfuscation – you can hide your predictable 1, 2, 3, … IDs as less predictable strings, e.g. 216 -> X46dBNxd79 or 315 -> 4w9aA11avM. This will hinder a simple id++ operation.
How?
One of my first findings was the hashids library, available for JavaScript, Ruby, Python, Java, Scala, PHP, and more. As I am a PHP and Symfony developer, I created a HashId bundle to simplify the obfuscation process of URL parameters with hashids as default encoder/decoder (obfuscator).
My first requirement was to not modify calls of URLs generation methods in Twig templates or controllers. This requirement has been fulfilled by running
{{ url('route_name', {'id': 1}) }} in the twig template or
$this->generateUrl('route_name', ['id' => 1]); in the controller.
The hashids library will be enough for some projects but it is not so secure; it can be easily replaced with e.g. Tiny obfuscator or a custom-made one.
Another possible solution that leads to hiding your sensitive data is the usage of UUID – universally unique identifier. It will be the favoured solution in some scenarios, but it requires additional database changes that introduce new columns to store UUIDs.

Summary

Businesses grow, their competitors grow, and everybody wants or needs to hide some information. In many cases it is enough to change the URL format of your website to obscure some of the sensitive data, and in many cases it could be the first step.
And what about you? Does your website leak?

GitHub project
PGS Software / HashId – https://github.com/PGSSoft/HashId

Last posts