1 min read

URL Aesthetics vs. Security: `/users/101` vs `/users/cuid`

Balancing clean URLs with the security risk of ID enumeration
Street photograph by Stalin Pereira
Photo by Stalin Pereira

Vanity URLs Are Overrated

Why ugly IDs make for secure APIs.

The 'Peeping Tom' Attack

  • The Scenario — You sign up for a new service. Your profile URL is /users/1050.
  • The Curiosity — What happens if you change that number to /users/1049?
  • The Breach — If the API returns someone else's data, you have an IDOR vulnerability.

The Threat: ID Enumeration

Scraping your entire business in 10 minutes.

  • The Script — Write a loop from 1 to 10,000. Send a GET request for every number.
  • The Leak — Now I have your entire customer database. Names, emails, activity.
  • Business Intel — I can track exactly how many users you gain per day by watching the ID count rise.

The Fix: Use Ugly IDs

  • UUID / CUID — Instead of 1050, use clj2k... or a0eebc99....
  • Unguessable — There is no 'next' number. You can't guess the ID of another user.
  • Anti-Scraping — Enumeration becomes mathematically impossible.

But... Ugly URLs are Ugly?

  • The Compromise — Users love pretty URLs. APIs love secure IDs.
  • The Strategy — Use 'Slugs' for public pages, but keep IDs for the API logic.

Architecture: The Slug Pattern

site.com/u/john-doe

  • Public Face — The URL shows john-doe (The Slug).
  • Internal Look up — Database maps slug: john-doe -> id: a0ee-bc99.
  • API Calls — Frontend API calls still use the UUID: GET /api/users/a0ee-bc99.

Defense in Depth

  • Authorization — Even with UUIDs, you MUST check: 'Does Current User own this ID?'
  • Rate Limiting — Block IPs that try to access 100 different profiles in 1 minute.

Summary: Obscurity + Auth

Sequential IDs are a feature for your competitors.

Don't make it easy for scrapers. Hide your primary keys.

Check your browser URL bar right now. Is it an ID or a hash?