33

I have had this discussion a couple of times in my career. In my view it is perfectly okay to expose the ids that are stored in the database to the client in your REST API response. But some people I've worked with think this is really one of the first lesson in security: "Never expose your database IDs to the client."

Then they come with all kind of complexity to avoid this. For example, in one job I had to hash every ID in my rest response, and then unhash all the ids in the request.

Now in my new job we have the following pattern. A table has an auto incrementing "id", but we don't expose that, next to that we have a uuid "code", and that is the one we expose to the client. So essentially we have 2 ids, both stored in the DB, but one we can expose, the other we can, because:

"Never expose your database IDs to the client."

Does this even slightly make sense? We still expose an "identifier" to the client. If the problem is that someone can see how many rows we have in a table, because that "id" is auto incrementing, I would just make the "id" an uuid, and expose that to the client.

If you look at examples of other public rest API's, it always seem to me that they expose the database id, without problem. For example, gitlab:

GET /projects/:id/users

[
  {
    "id": 1,
    "username": "john_smith",
    "name": "John Smith",
    "state": "active",
    "avatar_url": "http://localhost:3000/uploads/user/avatar/1/cd8.jpeg",
    "web_url": "http://localhost:3000/john_smith"
  },
  {
    "id": 2,
    "username": "jack_smith",
    "name": "Jack Smith",
    "state": "blocked",
    "avatar_url": "http://gravatar.com/../e32131cd8.jpeg",
    "web_url": "http://localhost:3000/jack_smith"
  }
]

Twitter: https://api.twitter.com/1.1/statuses/show.json?id={id}

But even stackoverflow: https://stackoverflow.com/questions/{id} https://stackoverflow.com/users/{id}

I would bet that 2188707 in the url https://stackoverflow.com/users/2188707 is just my user id in the stackoverflow database.

Kasper
  • 12,594
  • 12
  • 41
  • 63

6 Answers6

18

I don't see any security reasons to expose the plain database ID in your API. If your database is exposed you have lost anyways. Security through obscurity is never a solution.

However, there are some other reasons to consider:

  • Exposing the database ID creates a coupling to your database. Imagine merging data from different databases (sharing the same schema), or applying backup data to an already in use database. There will be no guarantee that the same ID's will still be available.

  • Designing a proper Resource based API requires you to expose universally unique ids (UUID) or a technical composite key for the simple reason that there is no other way to ensure uniqueness across different systems/databases.

Kasper
  • 12,594
  • 12
  • 41
  • 63
Abaddon666
  • 1,533
  • 15
  • 31
  • Well, what if you have an SQL injection hole in the app? Having internal IDs could make it even worse. Also, it could allow with a good analysis to rebuild data structures. – LMC Jun 13 '19 at 14:53
  • 2
    In my experience as soon as you are open to SQL injection you anyways can pretty much iterate the whole database. Do you have an example that actually only works when having the id available? Next to that I would like to emphasize that I am against using db identifiers in REST API's. Just for different reasons. – Abaddon666 Jun 13 '19 at 15:03
  • Don't have one right now but I'm sure it's possible. My point is that id could make the situation worse since ids could allow to infer FKs and help to correlate data between API operations. – LMC Jun 13 '19 at 15:19
  • 3
    what if you are offering a multi tenant service that share the tables between tenants (discrimination column), and the ID in the path is the primary key of the table, so it increase proportionally to the number or row in that table, you are exposing an information about the growth of that business to clients that shouldn't know this. Yes of course often who cares.. but you have to know that you are violating Information Hiding and decide if it's acceptable. – Glabler Nov 19 '19 at 20:19
14

Not a security issue, but it let the user know some information about the size of your data as a company. and some companies don't prefer to expose this kind of information

M.Elkady
  • 1,093
  • 7
  • 13
  • If you use DB managed ID sequences usually reserve blocks for a single client. SO in those cases the ID's can actually be considerably bigger than the actual amount of data. But other than that, I totally agree with your point – Abaddon666 Jun 13 '19 at 09:24
6

There are a few issues with sequential primary keys:

  1. They show your volume (for example: if you create an object and the API returns ID 10,001, it gives a rough estimate of how many objects of that kind you have on your DB, which might be interesting to hackers or to the competition)
  2. Hackers could exploit "Insecure Direct Object References" (link)
  3. Hackers could use it for XSS attacks (link)

Source: adapted from Two Scoops of Django 1.11

steamdragon
  • 1,052
  • 13
  • 15
  • Why does it help for XSS attacks? – stoper Jun 21 '22 at 15:07
  • 1
    The "Insecure Direct Object References" is only if this ID is used for CRUD operations since other IDs are enumerable or easily guessable. If your response returns an integer ID but that ID is not enough to create/read/update/delete objects what's the issue? – Paul Nogas Jan 12 '23 at 20:40
2

by exposing the ids for exemple in API users, if someone can create a new user, then call your user API, he can automatically know how many users you do have in your database, and in many busnisses this is not the kind of information that you want your concurrence to know.

Waali
  • 21
  • 1
1

This question is very old but can response now in case the answer is useful to someone new.

'I would just make the "id" an uuid, and expose that to the client.'.

The reason why numeric id is hiden and expose other with uuid is because for the DB Systems have bad performance with index for uuid fields, too with foreign keys with uuid type increase storage, depending of uuid version and index type of course. For this reason many systems set autoincremental numeric in primary key but hide that in expose information, with uuid field have the same prevent expose.

0

I wouldn't expose if the ID somehow relates to the database you are using, for example ObjectID in Mongodb. I think it should be kept internally.