6 ms·
Advice for Operating a Public-Facing API
- butz 3y agoWhat about CORS and CSP headers? Should public/open APIs use them and prevent building client side only apps?
- gwbas1c 3y agoWhy would you want to block that?
- butz 3y agoI have stumbled upon several "open" APIs that had such "security measures" implemented, thus making them rather unusable. It would be a useful advice of what not to do, for anyone building public facing APIs.
- JimDabell 3y agoYou don’t use CORS to prevent client-side only apps, you use CORS to allow them. CORS reduces security restrictions, it doesn’t add them.
- wizofaus 3y agoThat last suggestion (of returning 200 but with a message explaining that usage limit has been reached) seems odd to me - I'm not saying I haven't seen code that simply retries on any error but that could just as well include an error trying to parse the response and extract meaningful values from it. What I have observed is that client code often logs or relays HTTP status response codes (and 429 explicitly exists for this case) but rarely bothers doing the same for unexpected message content, which at best might be logged or conveyed to an end user as some sort of "failed to parse" exception. Surely a better option to avoid getting hammered is to return 429 after a 15-20 second delay?
- whartung 3y agoI think the premise here is that a 4xx is an “expected” server issue, which the code may be able to handle (i.e. retry) whereas a 200 followed by a parse error is an “application problem” that they’re not prepared to handle. A 200 may mean the payload has changed, and how would an app handle an arbitrary format change? This could well fall into the “don’t test for something you can’t handle”. At a minimum it’ll ideally get the app to quiet down.
- capableweb 3y ago> I think the premise here is that a 4xx is an “expected” server issue That premise is incorrect, as 4xx is client errors, as in the client formatted the request wrong or anything else, and therefore it couldn't be responded to. Rate-limiting is the client hitting the server too much, and it's up the client to handle this. 5xx is for server issues. 2xx should be success in any shape or form, so clearly 2xx shouldn't be used in this case either. I agree that 429 should just be used for it's intended purpose here, handling rate-limiting requests/responses. You can still add a body if you want, with the current quotas.
- bbkane 3y agoFrom my reading, this "hand out a 2xx and an error message" advice is for badly behaved clients who are retrying when they get 4xx. It's not what "should" be used, it's what the author found to be effective.
- istjohn 3y agoI'd rather my request fail with an error than have it be silently truncated.
- catsarebetter 3y agoAgreed, any kind of error message is better than nothing. Makes my code calling the API really hard to read and debug
- aiisjustanif 3y agoWhile a developer might like that, but an end user expecting a notification that gets nothing now will be asking, “Why do I not get notifications?”.
- pugworthy 3y agoCurious to straw/iron man this from the perspective of Reddit and their API "conversations" lately.
- sverhagen 3y ago> Be descriptive in your error responses > Assume a human will read them Yes, but... on the flip-side, make sure there's also some sort of code that the machines can read. Depending on the framework you started with, one or the other may be the more-obvious one to default to. But if you don't have both, you either have humans looking at cryptic codes (the point the article was making) or you have machines parsing through human-readable error messages with the risk of breaking backward-compatibility if you try to fix a typo in an error message or later decide to reword it or include more pointers.
- Jean-Papoulos 3y ago> Pushover's API has a message size limitation of 1,024 characters. If the message parameter is larger than that, I could reject the request because it's not correct, but then the user's message is lost and they may not have any error handling. In this case, I truncate the message to 1,024 characters and process it anyway This guy should not be designing APIs.
- cuu508 3y agoHow would you design it? Accept messages of any length, reject messages over maximum length?
- xctr94 3y agoHTTP 413 Payload Too Large is the appropriate response, not silently truncating content because you wanted to be ‘optimistic’ in your replies to clients.
- madsbuch 3y ago> Pushover's API might be unusual in that it is used by a wide range of devices (embedded IoT things ... If you did that, and no error handling was implemented in the IoT device, it would merely result in a non-event that no one knows about. In this specific instance, the author is doing the right thing. The developer will see truncated messages running through. In the end it is a question on desired semantics. The semantics of the operation in question is obviously to truncate and process rather than fail.
- flir 3y agoPostel's Law? (I actually agree with you, I think it's a bad rule of thumb. I prefer Fail Fast (and loudly)).
- JimDabell 3y agoPostel’s Law is bad and has been the cause of countless bugs, including many security vulnerabilities. Some discussion here: https://news.ycombinator.com/item?id=9824638 https://news.ycombinator.com/item?id=9824638
- whirlwin 3y ago> Serve your API at api.example.com, never at example.com/api. As your API's usage grows, it will expand beyond your website/dashboard server and need to move to a separate server or many separate servers. You'll want to be able to move things around by just pointing its IP somewhere else rather than trying to proxy things from your dashboard server. This makes a rather specific assumption that there is no L7 load balancer or the like in front.
- pledess 3y agoAdding more structure to prefixed tokens could help avoid false positives when someone signs up for GitHub secret scanning. I notice that Pushover is apparently not signed up: https://docs.github.com/en/code-security/secret-scanning/secret-scanning-patterns https://docs.github.com/en/code-security/secret-scanning/sec...
- mattbee 3y agoDid this page just turn into flying toasters when I wasn't looking?
- esafak 3y agoYes. https://jcs.org/js/afterdark-min.js https://jcs.org/js/afterdark-min.js https://en.wikipedia.org/wiki/After_Dark_(software) https://en.wikipedia.org/wiki/After_Dark_(software)
- smallnix 3y agoThe token prefix is a nice hack, but users will find it out and then it becomes part of the informal API.
- deleted 3y ago[deleted]
- 8organicbits 3y agoI don't think the AKIA/ASIA prefix for AWS access keys is formalized, which may be a good example of this: https://github.com/localstack/localstack/blob/6f846a8278e4396d7f52980ca5d5db756a703f9f/localstack/aws/accounts.py#L119 https://github.com/localstack/localstack/blob/6f846a8278e439...
- supriyo-biswas 3y agoIt is formalized though: https://docs.aws.amazon.com/STS/latest/APIReference/API_GetAccessKeyInfo.html https://docs.aws.amazon.com/STS/latest/APIReference/API_GetA...
- theamk 3y agoAnd that's fine. In fact, I would document the prefixes in the docs and make ot official.
- smackeyacky 3y agoIts the kind of thing I would rather see a base64 coded bit of json for. Easy to understand for support and easy for clients debugging.
- brendoncarroll 3y agoIt's amazing how far adrift the industry has gone with authentication. This post is saying to avoid OAuth and use bearer tokens because OAuth is too complicated. I agree with OAuth being too complicated, but I don't really think bearer tokens are the solution either. Now there are jwts, and passkeys, and all these other solutions, which from where I'm standing, just look like someone else's resume-builder that I'm going to have to understand in a few years in order to do something simple and unrelated. We are already connecting over TLS, just have the client authenticate with a long lived asymmetric key. Let me see that key in whatever web framework; I should have access to it, same as an HTTP header. Then I'll stick it in the database, maybe hash it first, if it's big. It doesn't have to be harder than that, your identity is (the hash of) your public key.
- AlphaSite 3y agoJWTS (and related token type approaches) are a solution to the whole: how do I avoid spending time doing authn on every request?
- dilyevsky 3y agoIf you use mTLS client identity is proven cryptographically (normally via /CN x509 field) - no need to exchange the key during authentication. You still need to generate it and distribute it to the user and manage its lifecycle which gets you to the same place as OAuth except with worse library support
- brendoncarroll 3y ago> no need to exchange the key during authentication The public key does need to be exchanged, along with a signature relating it to the current session. This is all handled by TLS, there is no need for the client to send the key in the application data. > You still need to generate it and distribute it to the user This approach avoids distributing secret key material at all. Private keys should ideally never move. They are generated randomly, used to derive the corresponding public key, and then persisted as appropriate. The public key is sent around to other parties.