5

We've recently started working on an API, and I'm running into a philosophy issue. This is only my second API I've worked on, but the standard I've seen for retrieving a single model is always a GET, and the endpoint is something like api/model/1, with 1 being the ID. However, my coworker is REALLY adamant about not passing any data through a URL, and wants to use POST instead and send the ID through the body. His reasoning is that he feels it's a security risk.

At the same time, he wants to follow a philosophy of one POST per file. This means we need a file for UpdateModel, DeleteModel, and EditModel.

What I'm proposing is we follow this structure:

GET    /api/Model       Get all to-do items
GET    /api/Model/{id}  Get an item by ID
POST   /api/Model       Add a new item
PUT    /api/Model/{id}  Update an existing item
DELETE /api/Model/{id}  Delete an item 

But he's proposing something like this:

GET  /api/Model Get all to-do items
POST /api/Model Get an item by ID
POST /api/Model Add a new item
POST /api/Model Update an existing item 
POST /api/Model Delete an item 

Is there anything to my coworkers philosophy that I'm not understanding?

PiousVenom
  • 247
  • 2
  • 9
  • 2
    Does this answer your question? [Should backend IDs be public or not on a REST API?](https://softwareengineering.stackexchange.com/questions/346971/should-backend-ids-be-public-or-not-on-a-rest-api) – Robert Harvey Apr 17 '20 at 15:04
  • 1
    We've ran into an issue before where the route needed to accept a collection of IDs for a normal GET, and we discovered we were better served switching to a POST because there's such a bigger capacity for data in a POST than in a GET, where you're limited to the normal length of a URL. – Graham Apr 17 '20 at 17:06
  • 1
    Wouldn't the `GET /api/Model` return all the IDs? Kind of makes "security" via POST a non-issue. – user949300 Apr 19 '20 at 16:26

3 Answers3

4

Using POST and putting the actual request details in the body “works”. At least nothing will break. Except HTTP caching. But at that point you're inventing your own RPC mechanism that uses HTTP as a transport protocol, and are not building a REST API that makes use of HTTP. This is a fundamental design choice, but both can be valid. E.g. GraphQL uses precisely this POST /some-endpoint mechanism.

In a RESTful API, the URI/URL should identify the resource. If model items are a distinct resource in the context of your application, a RESTful design would give each such item a separate URL. However, it could also be that the collection of items as a whole is the finest granularity that is reasonable for your application.

Whether putting data into an URL is a security risk depends on your threat model. There are two good reasons to keep sensitive data out of URLs:

  • as a defence against shoulder-surfing
  • to keep sensitive data out of log files

There can also be XSRF considerations, but requiring POST requests and serving appropriate CSP headers is a better response.

For all other purposes, the path or query parts are exactly as safe as the body of a POST request. E.g. if your backend has an Insecure Direct Object Reference vulnerability, this is just as exploitable through a POST body as it is through an URL component – just slightly more cumbersome for an unmotivated attacker.

amon
  • 132,749
  • 27
  • 279
  • 375
  • 1
    Nice, balanced perspective. I have coworkers who won't even look at GraphQL because they've totally bought into the REST religion. – Robert Harvey Apr 17 '20 at 15:53
  • You probably shouldn't be using sensitive data as resource IDs anyway. – starflyer Apr 17 '20 at 21:21
  • 1
    To elaborate a tiny bit on the breakage of HTTP caching: The browser will usually not allow you to go to a POST url from history. At least not without nagging about whether to re-send the request data. Which can be really annoying when you're browsing cross-linked to-do items. Ignoring the security aspect for a second, the basic rule is plain and simple: GET for reads, POST for writes. – Tfry Apr 18 '20 at 06:32
2

I agree with other answers here, however I would also want to question the reasoning behind your coworkers opinion.

Using POST body over a path param won't really add any meaningful security as such. If someone can snoop on path param, he can definitely do the same with request body.

Moreover path params don't really have any sensitive data, which is true in your case too.

sasmit
  • 21
  • 1
1

Both solutions are identical. The only change is your mapping of the html protocol to your server side code.

As such you could easily implement both mappings with the same code and architecture.

The security risk from having the id in the path is not a direct one, its encoded like the rest of the data, but the path is often logged. As such including data in it is not a great idea.

I would also note that presumably the object you are sending in edit and update requests includes its own id as a property. So adding it to the path is uneeded.

Get requests with query params or paths are easy to use in a browser without a client. For this reason I would prefer them for simple queries.

But I would use the query parameter, not the path. This will make your logging eaiser. You wont have to parse the data out to find the method etc.

Ewan
  • 70,664
  • 5
  • 76
  • 161