Do not expose database ids in your URLs

When developing web apps, we often rely on fetching informations from the database. Frameworks offer a way to make this easy thanks to ORMs.

Most of the time, the ORM will find your model using the primary key as a reliable identifier. On the vast maj…


This content originally appeared on DEV Community and was authored by Khalyomede

When developing web apps, we often rely on fetching informations from the database. Frameworks offer a way to make this easy thanks to ORMs.

Most of the time, the ORM will find your model using the primary key as a reliable identifier. On the vast majority, primary keys are auto incremented integers.

Your URLs then look like this:

https://example.com/cart/12
https://example.com/user/15/post/41
...

Providing an incorrect or faulty authorization layer can create data leaks: users become able to navigate from data to data, which is something we would not want to allow if it is about sensitive data like users personal info.

Obfuscating the identifier

An easy way to mitigate this security breach is to use a key that is:

  • Hard to predict
  • Random enough to be able to create a lot of items while keeping the unicity between them
  • Easy to generate from your code and the database
  • Checkable (we can know by analyzing its integrity if it is valid or not)

Thanks for us, UUIDs are a very good candidate for it. It checks all the points above, and are very easy to use thanks to a wide range of package ready for use.

Your URLS now become harder to predict, which mitigate any developers mistake regarding authorization policies in your app:

https://example.com/cart/f6e4208f-5df4-466e-9225-01f296e2a09c
https://example.com/user/b1b44b12-34bc-4ed7-a666-9657b8b8c31b/post/e530d034-42f7-467b-91e3-1cc9313312eb

Example on a Laravel app

In order to practice developing a Laravel package, and using my first ever Github Workflow, I created a package to make this job a breeze.

Here is how you can use khalyomede/laravel-eloquent-uuid-slug in your app now.

Install the package

First, head in your console, and type this command:

composer require khalyomede/laravel-eloquent-uuid-slug

Add your slug column to your migration

Then, go to the migration of the model of your choice, or create a new one if it has already been installed, and add the slug column.

namespace Database\Migrations;

use App\Models\Cart;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

final class AddSlugColumnToCartTable extends Migration {
  public function up(): void
  {
    Schema::table('carts', function (Blueprint $table): void {
      Cart::addSlugColumn($table);
    });
  }

  public function down(): void
  {
    Schema::table('carts', function (Blueprint $table): void {
      Cart::dropSlugColumn($table); // available soon in v0.2.0
    });
  }
};

Add the trait to your model

This is the last step, which will help configure how your model is retreived in your routes using Route model binding.

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Khalyomede\EloquentUuidSlug\Sluggable;

final class Cart extends Model
{
  use Sluggable;
}

Use it in your controller

Now you are ready to take advantage of the package. The great thing with it is that your code does not change! You can keep using the route() method like you are used to.

// routes/web.php

use App\Models\Cart;
use Illuminate\Http\RedirectResponse
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use Illuminate\View\View;

Route::get("cart/{cart}", function (Cart $cart): View {
  return view("cart.show", [
    "cart" => $cart,
    "saveCartRoute" => route("cart.store", $cart),
  ])->name("cart.show");
});

Route::post("cart/{cart}", function (Request $request, Cart $cart): RedirectResponse {
  $cart->update($request->only(["name"]));

  return redirect()->route("cart.show", $cart);
})->name("cart.store");

And voilà! This package will no interfer with your existing logic as you can see. The only thing that changes is now your routes are not exposed.

route("cart.show", $cart); // https://example.com/cart/398e76a7-7c16-467c-93a8-04c06c6df703

Conclusion

While this solution is not a magic way to resolve the initial problem of data leak, I find it is a very easy actionable mecanism to reduce the possibilities for malicious users to trick your system.

This does not prevent you to add an authorization or guard mecanism, like Laravel Policies for example. For example, if a user navigates to a cart that have not been created by him/her, should not be able to view it.

Other folks here already talked about this subject, so make sure to give it a go if you want to read more about using UUIDs:

Happy URL hardening!


This content originally appeared on DEV Community and was authored by Khalyomede


Print Share Comment Cite Upload Translate Updates
APA

Khalyomede | Sciencx (2021-08-22T18:36:45+00:00) Do not expose database ids in your URLs. Retrieved from https://www.scien.cx/2021/08/22/do-not-expose-database-ids-in-your-urls/

MLA
" » Do not expose database ids in your URLs." Khalyomede | Sciencx - Sunday August 22, 2021, https://www.scien.cx/2021/08/22/do-not-expose-database-ids-in-your-urls/
HARVARD
Khalyomede | Sciencx Sunday August 22, 2021 » Do not expose database ids in your URLs., viewed ,<https://www.scien.cx/2021/08/22/do-not-expose-database-ids-in-your-urls/>
VANCOUVER
Khalyomede | Sciencx - » Do not expose database ids in your URLs. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/08/22/do-not-expose-database-ids-in-your-urls/
CHICAGO
" » Do not expose database ids in your URLs." Khalyomede | Sciencx - Accessed . https://www.scien.cx/2021/08/22/do-not-expose-database-ids-in-your-urls/
IEEE
" » Do not expose database ids in your URLs." Khalyomede | Sciencx [Online]. Available: https://www.scien.cx/2021/08/22/do-not-expose-database-ids-in-your-urls/. [Accessed: ]
rf:citation
» Do not expose database ids in your URLs | Khalyomede | Sciencx | https://www.scien.cx/2021/08/22/do-not-expose-database-ids-in-your-urls/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.