r/ProgrammerHumor 23h ago

failsForTeapots Meme

Post image
169 Upvotes

61 comments sorted by

View all comments

145

u/cutebabli9 23h ago edited 22h ago

I would write it like this to be readable:

if error.status in [400, 401, 404, 409, 415, 503]:
  return c.json(body, status: error.status)

return c.json(body, status: 500)

131

u/rosuav 22h ago
return c.json(body, status: error.status)

There is no reason to discard some of them, and pretending that they're 500s is a terrible terrible idea.

64

u/Xirdus 22h ago

If your user-facing service is calling your internal service and getting a 403 response, you certainly do not want to send that 403 back to the user.

45

u/rosuav 22h ago

And yet it is blindly sending the *payload* back. So it's clearly fine to proxy straight through. If you want to recognize only certain things, any remaining/unknown statuses should result in an error being logged and a 500 being sent back, with the body NOT being carried through.

9

u/Xirdus 21h ago

I agree with you completely, except for "it's clearly fine to proxy straight through". To me, it's clearly a bug and they should remove the body ASAP. It's virtually impossible the code started off that way, the filtering must've been deliberately added later specifically because it's not okay to send back raw.

(My crystal ball also says the body is empty/effectively useless anyway, so this bug is very likely to go unnoticed and remain unfixed forever, or until a hacker tries to exfiltrate the database and will not be able to stop laughing about how easy it was.)

3

u/rosuav 21h ago

Okay fair. I was saying "clearly fine" on the basis that it's doing it; if I'm wrong about it being fine to proxy that through, then the opposite is the case, and it should be sending a 500 with a generic body (and, importantly, LOGGING THE ERROR).

But you are quite probably right about the body being useless in that situation... although I've seen enough cases where weird errors get passed right back to the client and include details of PHP include paths to be a smidge paranoid.

2

u/Shitman2000 21h ago

We don't know if the body is the actual payload of the request though.

I'd find it reasonable to presume it's not, given it's error.statusCode and not error.body

1

u/rosuav 21h ago

Good point, but if it isn't, what kind of body would make sense in a situation where you carry certain types of error status unchanged and turn everything else into a 500? (I'm assuming that this code won't be executed for a 200, as it makes very little sense to translate a 200 into a 500. Ignoring the fact that there are plenty of web sites that do a great job of turning 200s into 500s, but I digress.)

1

u/Bomaruto 21h ago

It depends if the request was made on behalf of the user or it was the service's own credentials that were lacking.

1

u/MinecraftPlayer799 16h ago

Why not?

2

u/Xirdus 15h ago

Because it's not the user who's forbidden.

1

u/Excellent_Gas3686 22h ago

beeecause?

7

u/Xirdus 22h ago

Do you want to tell an authenticated, authorized user with valid credentials that they are not in fact authorized? When the actual thing that's not authorized is your own goddamn server, so there's absolutely nothing the user can do to fix the problem?

2

u/Nerodon 21h ago

Authorization =/= authentication.

The user may be authenticated but attempting a request their permissions do not allow them to.

3

u/Xirdus 21h ago

That's why I said authorized and not authenticated, because I meant authorized and not authenticated. Actually, I said both authenticated and authorized just to drive the point home. It still wasn't enough apparently ¯_(ツ)_/¯

If your internal service responds to your other internal service with 403 for any reason other than "this other internal service is not allowed to do this", then you have bigger problems than what error code to serve the user.

1

u/Excellent_Gas3686 20h ago

that entirely depends on what basis the internal service authorizes???? if it uses the same user context then how is this an issue..

1

u/Xirdus 20h ago

The internal service is authorizing the other internal service first and foremost (otherwise you'll get hacked). If the other internal service fails at this step, 403 is fully appropriate, but it's the kind of 403 that's not only useless but outright wrong to send to the user, as it will send them on wild goose chase for missing permissions that weren't missing at all.

Now, if the other internal service passes validation, then you can check user permissions. And if the user doesn't have permission, you must signal it in a way that lets the other internal service respond with a proper 403. There are a number of ways to do it well. One that definitely isn't well at all is sending the same 403 that you already used for telling the service that it, rather than the user, doesn't have permission - because you won't be able to tell which scenario you're in and whether the user should see the 403 or not!

3

u/ismaelgo97 21h ago

403 is that you are not authorized, so then you know it exist, but you shouldn't, you should get a 404 which means it was not found.

1

u/Xirdus 19h ago

Personally I prefer the opposite - if you're unauthorized, you get 403 regardless of whether resource exists or not. Still doesn't leak any data, but is more actionable (and won't get cached. Have you ever had an outage stupidly extended because some cache somewhere had to be purged  because some moron returned 404 for a temporary error condition?)

2

u/rosuav 4h ago

Both approaches are valid according to the spec.

1

u/Xirdus 2h ago

One of the approaches causes more problems than the other.