
API Security Checklist for developers - eslamsalem
https://github.com/shieldfy/API-Security-Checklist
======
tptacek
There's some OK stuff here, but the list on the whole isn't very coherent. If
this is a guide specifically for "APIs" that are driven almost entirely from
browser Javascript SPA's, it makes sense. Otherwise, a lot of these
recommendations are a little weak; for instance, most of the HTTP option
headers this list recommends won't be honored by typical HTTP clients.

Further, the list succumbs to the cardinal sin of software security advice:
"validate input so you don't have X, Y, and Z vulnerabilities". Simply
describing X, Y, and Z vulnerabilities provides the same level of advice for
developers (that is to say: not much). What developers really need is advice
about how to structure their programs to foreclose on the possibility of
having those bugs. For instance: rather than sprinkling authentication checks
on every endpoint, have the handlers of all endpoints inherit from a base
class that performs the check automatically. Stuff like that.

Finally: don't use JWT. JWT terrifies me, and it terrifies all the crypto
engineers I know. As a security standard, it is a series of own-goals
foreseeable even 10 years ago based on the history of crypto standard
vulnerabilities. Almost every application I've seen that uses JWT would be
better off with simple bearer tokens.

JWT might be the one case in all of practical computing where you might be
better off rolling your own crypto token standard than adopting the existing
standard.

~~~
zimbatm
no JWT but "simple bearer token" is not a good advice as I have no idea how to
implement that. I'd rather use JWT with restricted crypto (make sure "noop" is
not allowed).

~~~
schoen
In tptacek's other post from two months ago:

> For almost every use I've seen in the real world, JWT is drastic overkill;
> often it's just an gussied-up means of expressing a trivial bearer token,
> the kind that could be expressed securely with virtually no risk of
> implementation flaws simply by hexifying 20 bytes of urandom.

This is then to say "generate a random number, give it to the client, accept
that same random number in the future as evidence of the client's
authorization". A familiar form of that would be a session cookie whose
content was generated by a cryptographic random number generator. The session
cookie is an index into a database that indicates the properties and
authorities that that particular session does or does not have.

Now I guess the reason people may like JWT is that they don't have to have a
database or store of tokens that they're issued and what authority each one
connotes, because they can verify the signatures on the JWT and then believe
the payload. And one system can issue authorizations that another system can
consume without direct communication between the two. I think these believing-
the-payload properties are a part of what Thomas _doesn 't_ like.

~~~
tptacek
On rare occasions there might be a good reason for stateless auth. I think
stateless auth is overused (it's especially funny to see it used on sites that
are otherwise dependent on HTTP cookies), but not intrinsically evil.

But there can be no reasonable argument for a standard conceived of in the
last 10 years to allow users to deploy something for which _the payload
chooses the cryptographic interpretation of the payload_. _No_ application
anyone on HN is deploying needs user-selectable cryptography. This is never a
feature; it's only ever an invitation to horrible vulnerabilities.

~~~
qyv
> But there can be no reasonable argument for a standard conceived of in the
> last 10 years to allow users to deploy something for which the payload
> chooses the cryptographic interpretation of the payload. No application
> anyone on HN is deploying needs user-selectable cryptography. This is never
> a feature; it's only ever an invitation to horrible vulnerabilities.

When I read about JWT's I saw the alg fields to a simple indicator of the
algorithm being used on the JWT, not that it is allowing the token to select
whatever algorithm it wants for the server to run. Granted, this is a semantic
difference, but if you treat the alg field as such it then becomes the servers
choice of what algorithms to support. The practical solution is simple: Only
support one algorithm, and if the token's alg does not match what the server
is expecting, do not authorize. Sure this is a weakness in the JWT spec, but
the real underlying issue is dev's not understanding the security mechanisms
and libraries they are deploying. That is bad news no matter what tech they
are using.

~~~
stouset
If you leave the `alg` field out, the _exact same scenario_ occurs: someone
sends you a token, and you fail to authorize using the server-side configured
algorithm. Having this field adds nothing of real value.

The only thing having an `alg` field does is make the standard trivially
misusable by well-intentioned developers.

------
Kiro
> Don't use Basic Auth

Why not? If it's an API meant to be consumed by a server I don't see what the
problem is.

~~~
ams6110
Was going to ask the same question. Assuming https of course, what is the
matter with basic auth?

~~~
daliwali
I think that the main issue is the client must send what is essentially the
plaintext password on every request, meaning the client also must store the
password. It might be short-lived, might not, but is a security risk to keep
the password around on the client side for the duration of the session.

~~~
vbsteven
I like to use Basic Auth for API's with clientid/secret pairs. So it's not the
user password and individual credentials can be revoked while it's much
simpler to implement than full OAuth

If I'm not mistaken Twilio does this too for their API

------
tiffanyh
I don't bookmark many links but here's [1] a good one for all to keep on a
similar topic.

It's a SO article on security for web transactions.

[1] [https://stackoverflow.com/questions/549/the-definitive-
guide...](https://stackoverflow.com/questions/549/the-definitive-guide-to-
form-based-website-authentication)

------
moxious
No amount of checklisting and best practices substitutes for hiring someone
smart to break your stuff and tell you how they did it. You can check all the
boxes and still get pwned.

You can learn and run automated tools for 6 months and end up knowing 1/3rd of
what a great pentester knows.

If you want to know you can resist an attack from an adversary, you need an
adversary. If you want to know that you followed best practices so as to
achieve CYA when something bad happens, that's a different story.

But honestly the security picture is so depressing. Most people are saved only
because they don't have an active or competent adversary. The defender must
get 1,000 things right, the attacker only needs you to mess up one thing.

And then, even when the defender gets everything right, a user inside the
organization clicks a bad PDF and now your API is taking fully authenticated
requests from an attacker. Good luck with that.

Security, what a situation.

~~~
lucb1e
> No amount of checklisting and best practices substitutes for hiring someone
> smart to break your stuff and tell you how they did it.

Which is not to say that it doesn't help.

As a pen tester, I'd much rather they tick all the boxes and save money
because now I don't have to report all the low hanging fruit (which is fun the
first two times you pwn an application but gets boring quickly -- I'd rather
have something interesting to test).

------
bodhi
What are peoples thoughts on using TLS client certificates for authentication?

Given we're talking about APIs, we avoid many of the UX problems, but it feels
like taking on a different set of problems than just using a bearer token. It
does provide baked in solutions for things like revocation and expiry though.

~~~
tofflos
I'm not that familiar with TLS client certificates so I'm not qualified to
say, but if you consider other developers as your users, then the UX problem
remains.

Web developers in general are more familiar with other forms of authentication
so unless you have a strong reason for picking TLS client certificates I would
suggest picking something else.

In other words: I would be more likely to try out an API if it was based on
Basic Authentication. ;-)

------
drdaeman
> Always try to exchange for code not tokens (don't allow
> response_type=token).

There is absolutely nothing wrong with the implicit flow if the application
(including in-browser ones) is requesting the token for itself (and not for
some server or any third party). In case of a standalone app that would be
just an extra meaningless step.

There is a slight difference in presence/absence of refresh token, though, but
that would make implicit flow _more_ secure (because, if standard-compliant,
there won't be any refresh tokens at all), not less.

In case of a browser, the token would end up in the browser's history, but
given that a) if browser itself is compromised game is already over, and b)
that it's not possible for other parties to access the history (besides some
guesswork that doesn't work for tokens), paired with a fact that c) such
tokens should be short-lived, it's not a big deal.

> User own resource id should be avoided. Use /me/orders instead of
> /user/654321/orders

This has absolutely nothing to do with security. TBH, I don't see any issue if
/me/ would be a redirect or an alias for /user/654321/. That may make perfect
sense if a conceptual purity is desirable ("for each object there is one and
only one URL - the canonical one"), with its pros and cons.

> Don't use auto increment id's use UUID instead.

Similarly, that barely has anything to do with security. One just has to
understand that sequential IDs are trivially enumerable (and an obvious
consequence of this fact - that API consumers would be able to enumerate all
the resources or, at the very least, estimate their cardinality).

And as for the security - it should've probably said UUIDv4, because if one
accidentally uses e.g. UUIDv1 their IDs would lose the unguessability.

------
philip1209
> User own resource id should be avoided. Use /me/orders instead of
> /user/654321/orders

Can somebody explain this?

~~~
s_m_t
what happens if I type in /user/654322/orders instead of /user/654321/orders?
Did I just access someone else's account?

~~~
icebraining
Yes, if you're a supervisor or parent account or something like that.

Preventing flexibility at the URL level rather than performing proper
authentication strikes me as a poor decision.

~~~
kpcyrd
I think this is a rather special usecase, this makes sense with inhouse
applications where something like this might be common, but probably not
something you want on the public api of a shop.

~~~
icebraining
I disagree. What about the support rep, who needs to look at the customer's
orders? What if it's a e.g. digital games store, and you want to have kids
accounts which can be reviewed by their parents' ? What if you sell to
businesses, and you want to let employees purchase stuff without having access
to the address and billing info, which is configured by a master account?

You're just tying yourself down for no good reason.

------
ikeboy
So I'm developing a simple SAAS with little to no private info and where
failure isn't critical.

For initial release I build a page that uses html buttons and basic javascript
to GET pages, passes a key as a parameter, and uses web.py on the backend.

It seems like it would be a lot of work to implement the suggestions here. At
what point does it make sense?

------
EGreg
There is a lot more you can do.

For example you can sign session IDs or API tokens when you issue them. That
way you can check them and refuse requests that present invalid tokens without
doing any I/O.

~~~
PetahNZ
JWT does that.

------
baybal2
The guy forgets the main thing here: length, type and range checks!

I'm finding issues like API servers hanging/crashing due to overly long or
malformed headers all the time when I work on front-end projects.

Programming in a language with automatic range and type checks does not mean
that you can forego vigilance even with the most mundane overflow scenarios:
lots of stuff is being handled outside of the "safe" realm or by outside
libraries.

------
ViktorasM
Not a security topic, but POST is not necessarily "create" and PUT is not
necessarily "update".

~~~
Mandatum
And API's aren't necessarily REST. But this "checklist" is very clearly geared
towards a "standard" set of REST APIs. So what's your point, that there are
edge-cases in RESTful design?

------
kpcyrd
I've filed a pull request to include a CSP technique I've started adding on
some of my apis:

[https://github.com/shieldfy/API-Security-
Checklist/pull/5](https://github.com/shieldfy/API-Security-Checklist/pull/5)

