Postel’s law states that one should be conservative in what one does, but liberal in what one accepts from others; this is great advice for life, but terrible advice for writing software. When it comes to software security, it’s better to be conservative in what one does and paranoid in what one accepts from others — and prone to freeze when surprised.
If you’re talking about a private interface between a web server and CGI script, sure. But Postel was talking about TCP, and this advice is still relevant for lots of internet-facing software. When you have a public-facing REST API that is consumed by tons of random software that you have no control over, you have to make some compromise between rejecting all bad input and making things easier for your users (and yourself, not having to field support requests from users not understanding why their shit script that was cobbled together from random Stack Overflow pages doesn’t work).
Colin benefits from writing the only client people are likely to use for the tarsnap service. I don’t think the website offers an API other than regular browser pages, either.
I feel no obligations whatsoever to users who cobbled together an awful script from random stack overflow pages. The only proper response is. “Sorry that doesn’t work. Try something else.”
Your sole responsibility is to document the API and make it as easy as possible to use. Anyone who steps outside the bounds of valid output after that is on their own. You owe them nothing not even support. Send them a link to your API documentation and call it a day.
You don’t run your own company, do you?
His rationale makes sense, but I don’t understand why he returns an HTTP 500 error instead of a 400.
His article is exactly about this: he doesn’t want to maintain the code distinguishing between the two because the distinction, while being marginally useful to the client, is also dangerous for the server. And the context of the whole exercise is that the client is expected to be evil, so there’s no point in helping it in the slightest.
More often than not the aversion to 500 errors is based on the premise that it’s a server programmer’s error and is thus embarrassing. This leads to attempts to carefully validate all inputs before any underlying framework/library code and respond with a “proper” 400. But this is just needless extra work: if you have a 500 error than something in your stack is already refusing the user input, and there’s no security hole as there’s no meaningful action arising from it.
I agree that returning a 500 isn’t a security hole.
I don’t avoid 500s because I think they’re embarrassing. I avoid them because they’re the same as returning ? to the client in that they don’t tell you anything. As others in this thread have pointed out, that’s probably fine if you’re the only client. But if I’m writing an integration, I want to be able to tell the difference between sending an invalid request and the server exploding.
The problem with 500 is that it’s misleading to the client. Anything in the 400 range means “you messed up, send me something different” where anything in the 500 range means “I messed up and someone will fix this bug.” Percival’s solution is OK when there’s only one client and he wrote it, but it’s not OK when clients will be writing their own clients because it’s misleading to them.