DEV Community

loading...

Should routing go before security?

rytis profile image Rytis ・1 min read

Recently I've got into an argument with a colleague in regards to what HTTP status to return.

The way our API works right now: you need to be authenticated to call any route except the ones which are explicitly configured as public. This means that if you call any endpoint (doesn't matter if it exists or not) without a token, you will get a 401 response. If you call a non-existing endpoint with a valid token, only then it returns 404.

My colleague says that it should be the other way around and we should first check if the route exists and only then validate the token.

What's your opinion on this issue? I've seen it done both ways and I don't have a problem with either approach, but I am leaning more towards returning 401 before 404, because unauthenticated calls shouldn't reveal whether endpoint exists or not.

Discussion (11)

pic
Editor guide
Collapse
pilskalns profile image
Andžs

Let's imagine you try to implement a connection with a new API. You get your token. You read the docs, written with many sections and subresources for each large aspect of the new platform. You combine the request. You add the API version to path, headers, userID, whatnot else and finally send out the request and get back 404.

You remove the API version. You change the base to api.domain.co and again 404. Repeat and the same. You check the HTTP library docs of language/package/framework used and still no luck. You try adding and removing Content-Type: application/json, Accept etc. and still no luck.

In the end it turns out it was copy-pasta mistake since the JWT token is so long, the last part didn't copy fully and it was just auth mistake.

I would look from the point what is more valuable to the user - hey you made a mistake or GTFO.

Collapse
rytis profile image
Rytis Author

I think you misunderstood what I was trying to ask. We are not debating whether we should replace 401 with 404 for authentication errors. The question is which goes first - evaluating that the requested route exists or validating the token.

Approach 1:
If we validate the token first then any calls without a valid token will return 401, because that's the exact error - the call is unauthenticated and it doesn't matter if the route exists.

Calls with valid token:
GET /exists - 200
GET /not-exists 404

Calls without a valid token:
GET /exists - 401
GET /not-exists - 401

Approach 2:
We evaluate if route exists first and only then check for a valid token. Then API would return like this:

Calls with valid token:
GET /exists - 200
GET /not-exists - 404

Calls without a valid token:
GET /exists - 401
GET /not-exists - 404

Collapse
pilskalns profile image
Andžs

Ok, I see.

If we talk about API with auth, then there are a high chance of dynamic routing, user-specific and global resources. Maybe at some scale, there will be an API gateway first, then it forwards requests to one of the services at the backend even not knowing detailed list what backend can have.

Even more so on API with authentication then let's not forget also about authorization.
If user X can have file Y, then user Z cannot have file Y. So, the response depends on finished authentication and authorization steps.

It's like someone knocking on your door, first you want to know who he is before you let him in and let watch your TV. Not the other way around - let in, he takes the TV and on the way out you try to explain that he cannot have it.
If you don't even let him in, you get very suspicious when he asks if you have an HD TV with HDR and Dolby sound...

I believe that auth makes sense to do early as possible so it is never forgotten as middle or last step or accidentally bypassed by a cache... not that anyone could imagine possible bug scenario here...

Collapse
myzel394 profile image
Myzel394

I would go with approach 1). You shouldn't tell your enemies your endpoints.
If someone wants to e.g. Check an endpoint for security breaches, so they can hack you, they wouldn't know where to start with approach 1).

Collapse
christalib profile image
chris

Consider this: An attacker finds a way (and eventually he or she would) to walk through the entire API and find all the endpoints. Then move to craft a token and try to bypass authentication.

Or, would it be harder to first craft the authentication and then find the endpoints.

Which would, if successful, damage your product the most? Which would, if successful, be detected first?

I don't know anything about your product but those are, I believe, interesting questions to go through.

Collapse
rytis profile image
Rytis Author

I don't think API endpoints themselves are a huge secret. But if we require a valid token first, then it will be easy to see which user is trying to scan the API. Due to the nature of our business, the users are linked to real identities, so it would be easy to track which real person is doing the scanning (or who's account was compromised).

I think I kinda answered my own question here. Thank you for formulating the right questions for me to ask.

Collapse
christalib profile image
chris

My pleasure! Keep it up!

Collapse
jawil003 profile image
Jannik

I think your colleague is right, but I think it is a small security issue because you may can evaluate which routes exist but not seem like a big issue to me. At the end both works if you design your Frontend in a way that fits.

Collapse
rytis profile image
Rytis Author

My thoughts exactly on the security. Even though security through obscurity is not a good practice, if we return 401 for all unauthenticated requests, then we're hiding which routes exist if the user is not authenticated.

Collapse
jawil003 profile image
Jannik

Yeah on a security aspect it makes totally sense.

Collapse
andreidascalu profile image
Andrei Dascalu

Authentication before routing.
It makes little sense otherwise. The outcome of routing isn't to tell whether a route exists but to delegate to route handler. If you have a an authentication Middleware, it stands to reason to trigger it early (with the added benefit of not giving away route existence - mostly because there's really no upside to this, there is nothing to gain by triggering authentication late).

So unless you have a strong need to delegate authentication to specific handlers, it should go first.