The security consultancy behind several PHP cryptography projects writes on password storage, encryption, authentication tokens, and secure PHP development.
Commenters see it as a go-to source for PHP security work, including libsodium. One calls its anti-JWT post bizarre, since it rests on library bugs.
> Context matters: That's a CLI script.
Ahh, my bad, it's still an odd way of doing this. And it's vulnerable to injection via the prompt parameter (not that it matters, but...). That pattern is repeated in a couple of places like the updater.
> Because when Airship was started, everyone insisted on backwards compatibility for PHP 5 and I wanted to make use of strict typing. The master branch includes a static analyzer as part of continuous integration.
Strict typing is great, but you don't have to write your own framework to benefit from it. Is PHP 5 not compatible with modern frameworks?
> Have you seen what I've done to PHP frameworks over the years?
> https://scott.arciszewski.me/open-source/
> https://paragonie.com/security/advisories
> I wasn't in a hurry to pick up other peoples' technical debt.
Indeed there are some vulnerabilities found in PHP libraries in those pages, but hardly enough to warrant your position.
You aren't in a hurry to pick up others technical debt, but you rush ahead and create your own?
All I'm saying is you put out a post saying you designed this from the ground up to be secure, but did you really? Is rolling your own ORM and homegrown framework secure? Says who?
Yeah, you use modernish stuff like csp etc, but the code is still a typical PHP spaghetti of mixed concerns and hard-to-audit flows. It's not really a CMS, it's a NIH syndromed framework with a CMS on top of that. That's a typical source of bugs.
> That's simply a…
I'm a developer, not a cryptographer, and like most crypto articles, most of this post is gibberish to me. I really tried to follow it in the beginning, but then I gave up, scrolled to the "what should you use instead", and then realized I didn't understand that either.
If this is article is "easy" crypto, and I shouldn't roll my own crypto, then what should I do? "Just use elliptic curve crypto but make sure you choose the right curve! Here's an abbreviation for you, libsodium has it so you're all set" doesn't comfort me much. I don't have a good intuition of what a curve even is and why my sensitive data can't just go straight ahead like all the other data. I mean, when I call into libsodium with parameters I do not understand, then aren't I, for all intents and purposes, rolling my own crypto anyway? How is any of this of help?
If I want to allow my customers to send me encrypted data via an untrusted channel, then what do I do? I need public key crypto for that, right? Basically, I want the public key cryptography version of Coda Hale's classic blog post about password hashing [0], does that exist?
EDIT: thanks for all the comments folks, great insights! I particularly found [1] by CiPHPerCoder to be a great starting point (akin to Coda's password article) for all kinds of scenarios. I feel much more confident about this stuff now than I did 2 hours ago.
[0] https://codahale.com/how-to-safely-store-a-password/
[1]…
> OAuth uses access tokens, which are typically, but not limited to, JSON Web Tokens
This claim is misguided, but I hear it quite often. JWT is a very popular (and downright terrible[1]) format, but I there is no evidence that most of the tokens use JWT. It could be worse - I've heard some people claiming with confidence that OAuth mandates JWT.
The reality is that OAuth 2.0 predates JWT, and the implicit assumption was that all tokens are stateful. The access tokens in the examples are all short, and the spec strongly recommends revoking access tokens in case of access code reuse.
This makes JWT access tokens a non-canonical implementation of OAuth 2.0. You could add a "jti" claim (or "uti" claim in case of Microsoft) and then check for revocations in Redis, but then your only achievement was bloating up your access tokens by a factor of 20. Congratulations!
That's the reason why the other Big Tech companies are not using JWT for Access Tokens. It just doesn't make sense when you are at the scale where you need access tokens to be small and moderately long-lived. Users of JWT are more heavily concentrated on the smaller scale: more recent startups and enterprise customers.
---
[1] https://paragonie.com/blog/2017/03/jwt-json-web-tokens-is-bad-standard-that-everyone-should-avoid
Authentication in this context means baking in a way to verify that what you receive is something you encypted and has not been altered. Or, in other words, it lets you know that the data hasn't been tampered with.
As a practical example, imagine using encrypted cookies for a session store (like Rails can do), but imagine that they're not authenticated. It's possible that with clever manipulation of the encrypted cookie, I can alter the cookie such that it still decrypts into the structure ecorcyed, but with different data. For example, maybe I change the initialization vector a bit in a clever way and that makes the userId stored in the cookie change.
For a more detailed explanation and hypotherical, I thought [1] was a great article. It uses PHP for the examples, but it's mostly the theory that's of interest.
Of note, things are actually worse in Magento's case than this hypotherical since you can, as an attacker, get Magneto to use some pretty bad crypto when decrypting your message even if they used something decent when encrypting their payload (remember: since it's unauthenticated, what they give you and what you give back are not necessarily the same).
[1] https://paragonie.com/blog/2015/05/using-encryption-and-authentication-correctly
Most of the "discussion" on this topic spins out of this blog post: https://paragonie.com/blog/2017/03/jwt-json-web-tokens-is-bad-standard-that-everyone-should-avoid. Which unfortunately is:
1. A bit unnecessarily abrasive and hysterical in its style, and
2. Comes from a PHP consulting firm, promoting their own alternative proposal (which hardly anyone else seems to discuss or use). So I think #1 above is really about drawing eyeballs and selling services, more so than providing clear information for a newcomer to follow.
JWT does have its issues, though. They basically break down into two points:
1. Because of its distributed nature, there's no built-in way to invalidate a JWT prior to its natural expiration. You have to roll your own approach for this, typically some sort of whitelist or blacklist mechanism (which defeats some of JWT's advantages).
2. By default, the spec and its major library implementations allow JWT's to specify a number of different signing algorithms (including "None"!). This is dangerously nonobvious for newbies.
Best practice is to configure your code to only allow a limited number of algorithms (i.e. one).
Unlike others, I think terrible crypto is often better than plaintext.
But they would have gotten an actually secure system implemented more cheaply with less code by just copying some example code from libsodium[1]. The author(s) went to a whole lot of unnecessary effort and the result is an insecure, embarrassing mess.
I would respect the argument of "oh, they're just picking a different point along the Pareto frontier between secure / high effort and insecure / low effort". But this is both insecure and high effort. People are piling on because it has the trademark smell of bad judgement.
Its also a great learning opportunity. Its interesting hearing about all the security problems people who are knowledgeable in the field can spot! I noticed barely any of these problems!
[1] Quick Reference, from the bottom of the article: https://paragonie.com/blog/2017/06/libsodium-quick-reference-quick-comparison-similar-functions-and-which-one-use