1. 1

    Why not establish a JOSE subset with said “secure implementation” and give a name to your subset?

    JOSE is a broad standard providing a basic framework to do many things. At times it just provides guidelines (just look at rfc 7800). It’s not designed to be the end all “secure solution”. That’s simply not its stated design goals.

    JOSE assumes that specific applications will use a small subset a features for specific things. It’s assumed that the developer has some clue what they are doing. Based on the JOSE philosophy, I would assume that standard libraries for specific usages would be established which would in turn be used by end developers. The article doesn’t seem to consider this organization.

    As the larger industry moves to adopt JOSE for specific secure applications, why not build your solution on something JOSE like? https://xkcd.com/927/ The reason JOSE doesn’t use “ver” is because it’s assumed specific applications should have foreknowledge of a particular JOSE usage. The application would define “ver”. BUT there is no reason why you can’t fit your “ver” philosophy into JOSE. Moreover, JOSE is designed to accommodate this sort of extension. The article lead the read to conclude, “alg”:“none” is proof of JOSE’s fallacy. This is not the case. It is only proof of JOSE’s objectives.

    Now to change from criticism to commendation, I commend paseto’s continued use of json. https://github.com/paragonie/paseto/blob/master/docs/01-Protocol-Versions/Version2.md I’m glad to see it’s remarkable like JOSE, but that leads me to wonder could you really not figure out how to fit your philosophy in something considered by some great minds in the industry?

    1. 4

      The blog post explains why, dude. In security world, it’s bad practice to enable devs to do the wrong insecure thing.

      1. 2

        Why not establish a JOSE subset with said “secure implementation” and give a name to your subset?

        Secure cryptography is inherently incompatible with insecure cryptography, and since most of the vulnerabilities in cryptography protocols occurs at the joinery rather than the primitives, bolting a massive backward compatibility with JOSE would be self-defeating.

        The goal of Paseto is to be boring (PDF).

      1. 1

        Really well written and motivating blog post. Paseto wouldn’t be useable with OIDC tokens, right? That’s the place from which JOSE starts entering a project and expanding.

        1. 2

          Not currently, getting Paseto to be usable with OIDC is something I haven’t gotten to yet, but hope to soon.

          1. 1

            Do you mean that an existing JWT could be consumed using Paseto? Or that a translation layer would need to be created?

            I looked all over the docs for an example of the structure of a Paseto token but couldn’t find one. I was curious if it’s formatted exactly like JWT or not.

              1. 1

                Oh perfect! Sorry I didn’t check the readme - I got all my backstory from the blog post so didn’t check the readme. Yeah, looks quite different from jwt, so idk how it would work with OIDC. I’ll have to read the spec, I’ve only read the oauth 2 spec.

        1. 5

          Is this token local or public? local: shared-key authenticated encryption, public: public-key digital signatures.

          If someone doesn’t know whether to pick between encrypting or signing or tagging [1] a token, it seems that asking whether the token is local or public could only confuse them. SWEs implementing their own encryption might be foolish, but not understanding the primitive cryptographic operations you can utilize seems to err in the other end of the possible delineations between researchers and practitioners.

          1. since this one is slightly less commonly known — https://en.wikipedia.org/wiki/Message_authentication_code
          1. 1

            If it’s local, you get authenticated encryption. No other choices.

            If it’s public (i.e. the token is signed by one party and verified by another), you get digital signatures.

            That’s the only choice that needs to be made.

            1. 4

              That misses quite a few use-cases, no? Most importantly, tagging, where I don’t need asymmetric signatures and I don’t need encryption, but I want to give you a token you can read but not modify before you pass it back to me.

              Also, why does “local” mean “authenticated encryption”? And “public” mean “digital signatures”? I might be getting dense towards the end of a long week, but the linguistic intuition seems non-obvious.

              1. 3

                Most importantly, tagging, where I don’t need asymmetric signatures and I don’t need encryption, but I want to give you a token you can read but not modify before you pass it back to me.

                If you want unencrypted-but-authenticated tokens, stick the raw data in the unencrypted footer. Strictly speaking, your options are AEAD or Ed25519.

                Also, why does “local” mean “authenticated encryption”? And “public” mean “digital signatures”?

                Local means local to a system. The issuer is the verifier.

                Public means it’s not local to a system, it’s going to be transmitted over the public Internet. The issuer is a different entity than the verifier. (It doesn’t make sense to use public-key cryptography for a purely-local use case.)

                1. 2

                  If you want unencrypted-but-authenticated tokens, stick the raw data in the unencrypted footer.

                  So instead of buttons and levers, there’s more the one place I can stick my data?

                  The issuer is the verifier.

                  The word for that use case is “symmetric”.

                  Public means it’s not local to a system, it’s going to be transmitted over the public Internet.

                  And if the data is public, but the token verification is local (i.e. symmetric), then you stick it in the unencrypted footer. Got it.

                  Hope you don’t take it personally if I stick with { data, tag: SHA(secret + data) } and call it a day ;)

                  1. 7

                    { data, tag: SHA(secret + data) }

                    I hope you don’t stick with that, since I can add my own data and produce a new, but valid SHA, via a length extension attack, no?

                    1. 4

                      Just to really drive this home @anfedorov - the tldr from @apg’s link:

                      HMAC is the real solution. HMAC is designed for securely hashing data with a secret key.

          1. 3

            Nice that this is being pushed forward now. I’ve written a C implementation of (for now) v2.local with bindings to Java and C# (latter by a colleague). I’ve been wanting to publish it, but had my hands full. I hope I manage to get it out on the web in the next two weeks, hopefully including Python bindings!

            1. 2

              That sounds amazing :O

              Can you please link them here when they’re released? https://github.com/paragonie/paseto/issues/45

              1. 1

                I’m not sure what the relevance is?

              1. 3

                It sounds to me like “the desired out come [sic] of a very short URL” needs to be examined: What is so wrong about a long URL? Google use them, and Apple use them. As a content-identifier, a URL should (conceptually) be a hash of its content and accessor, and so very compressed hashes for mostly public information (like on Twtitter) are absolutely acceptable. URLs can get quite large these days, and long URLs may scare people giving them pause before sending them to others. For all these reasons and more, I’d really like to see this point justified further.

                However even given that, there’s other strange advice in here as well, like “Do not use obfuscated URLs as a backdoor.” which is silly. A long, hard-to-guess URL is absolutely more secure than a short, easy-to-remember (and frequently-typed) password.

                And the proposed protection against timing attacks is troubling in the face of a much simpler solution: Find the max lookup time, and sleep up to it. Add some random fuzz to protect against jitter.

                1. 2

                  A long, hard-to-guess URL is absolutely more secure than a short, easy-to-remember (and frequently-typed) password.

                  This is false. The problem is that you’re only considering the raw entropy, but not all of the other technical implications - because a URL is not considered sensitive information, it may be retained by proxies, in access logs, browser history, desktop session data, and so on.

                  It may be sent over a message bus like DBus, or through custom IPC protocols to other applications on the system. Browser extensions may even send this URL elsewhere for purposes like malware scans, because they don’t expect the URL to essentially contain a password. And so on - the possibilities are endless.

                  This would be a good moment to invoke this article. Deviating from the assumptions under which something is designed, is generally a bad idea because of pitfalls like this.

                  1. 1

                    a URL is not considered sensitive information,

                    And you a password is? That’s so cute.

                    Should I address you? Or the person working the sock puppet?

                    It may be sent over a message bus like DBus, or through custom IPC protocols to other applications on the system.

                    That’s no different than any keychain or password manager.

                    Browser extensions may even send this URL elsewhere for purposes like malware scans

                    No, they don’t. But it’s not like they’re smart about security, it’s that they’re smart about the privacy backlash. Software that works that way is illegal in Germany and Switzerland, and about to be made illegal (GDPR) in the rest of Europe.

                    If you know of a browser extension that does this, you should have it reported.

                    And so on - the possibilities are endless.

                    No. They’re really not.

                    Meanwhile, the very real risk of someone having to remember “yet another password” writes it down with all their other passwords – know an attacker knows by searching for that password which file contains all of the other goodies. Yum.

                    Or someone decides to change the password. Or reuse it. Or copy/paste it and accidentally paste it into the wrong place.

                    We have too many passwords and I get it: we think we want to “make things secure” instead of authenticating and confirming authorisation to resources. But that’s just caused by too many cargo-cult programmers who find one blog post they agree with and forget how to think for themselves.

                  2. 0

                    It sounds to me like “the desired out come [sic] of a very short URL” needs to be examined: What is so wrong about a long URL?

                    SMS. You only get 160 characters, and you want as short of a URL as possible. This is the sort of constraint I’ve had to work around for clients in the past.

                    However even given that, there’s other strange advice in here as well, like “Do not use obfuscated URLs as a backdoor.” which is silly. A long, hard-to-guess URL is absolutely more secure than a short, easy-to-remember (and frequently-typed) password.

                    That depends on whether or not you allow weak passwords.

                    And the proposed protection against timing attacks is troubling in the face of a much simpler solution: Find the max lookup time, and sleep up to it. Add some random fuzz to protect against jitter.

                    Do not use sleep to mitigate timing attacks. It might seem tempting, but it doesn’t work. You either use too short of a delay (and your random fuzz becomes useless with enough samples) or too long of a delay (and expose your server to easier DoS attacks). A Goldilocks strategy won’t work either: the goalposts will move over time, and you’ll need to figure out where/how to calibrate the values for the delays. You’re better off solving the real problem.

                    1. 1

                      SMS. You only get 160 characters, and you want as short of a URL as possible. This is the sort of constraint I’ve had to work around for clients in the past.

                      160 characters is plenty for authenticated secret-key encryption.

                      Do not use sleep to mitigate timing attacks.

                      Yes, do. And in fact read the article you just linked to where it suggests exactly my mitigation suggestion: “Make the operation take a minimum time (clamping)”. It suggests a weaknesses to local users and some handwaving about security by obscurity, but no real actual problems with it.

                      [too long of a delay] and expose your server to easier DoS attacks

                      Saying “easier” is intellectually dishonest. If someone can DoS your cpu idle, then they can certainly DoS you when your cpu is warm. Process and network utilisation remains almost exactly the same, and in all practical ways of measuring it, you’re introducing no new attacks.

                      That depends on whether or not you allow weak passwords.

                      The weak password is the one that someone has to write down in an accessible place, but by all means: put your money where your mouth is and find my secret url.

                      Just stop using passwords.

                      1. 1

                        160 characters is plenty for authenticated secret-key encryption.

                        Yes, but not “a custom message + the URL”, which is what my past clients wanted.

                        Saying “easier” is intellectually dishonest. If someone can DoS your cpu idle, then they can certainly DoS you when your cpu is warm. Process and network utilisation remains almost exactly the same, and in all practical ways of measuring it, you’re introducing no new attacks.

                        The DoS comes in when you have idle connections being used (and using memory) for needlessly long periods of time, which allows an attacker to send more requests than the server can fulfill which blocks legitimate traffic.

                        Having a long sleep on the server side makes that easier.

                        I wouldn’t be so quick to call something intellectually dishonest, because all that does is hamper understanding and make future interactions needlessly adversarial.

                        1. 1

                          Yes, but not “a custom message + the URL”, which is what my past clients wanted.

                          Two messages are cheap.

                          Anyway, I try to avoid making things harder for myself since I’m trying to save my customers their money.

                          for needlessly long periods of time, … I wouldn’t be so quick to call something intellectually dishonest, because all that does is hamper understanding and make future interactions needlessly adversarial.

                          You keep saying “long”. Be specific. Give timings: This is usec and nsec territory. An attacker that can overload you taking T+100 usec but not T usec doesn’t exist.

                  1. 3

                    If you generate 9 raw bytes from a cryptographically secure pseudorandom number generator, then base64 the result, you will end up with a 12 character identifier (72 bits of possible values).

                    If you generate 9 raw bytes and base64 the result, the number of possible values is not increased by running base64 (although the prose could be read to implies it would).

                    Furthermore, this record is completely randomly generated and has nothing to do with the rest of the data stored in your database. There is no pattern to be found. (The closest relevant buzz-word here is a “zero knowledge”.)

                    The closest relevant buzz-word should be “Message Authorization Code”, because that’s how you would do this securely. It would also make the timing attack a non-issue.

                    Zero knowledge encryption has nothing to do with this (and I’ll resist the urge to make the oh-so-tempting pun about the author because it’s entirely unfair).

                    1. 1

                      If you generate 9 raw bytes and base64 the result, the number of possible values is not increased by running base64 (although the prose could be read to implies it would).

                      The 9 bytes offer 2^72 possibilities. The base64 transformation is just for safe storage.

                      The closest relevant buzz-word should be “Message Authorization Code”, because that’s how you would do this securely. It would also make the timing attack a non-issue.

                      Did you mean “Message Authentication Code”? Or am I missing one of the linguistic atrocities from bizdev?

                      Zero knowledge encryption has nothing to do with this (and I’ll resist the urge to make the oh-so-tempting pun about the author because it’s entirely unfair).

                      Zero knowledge isn’t encryption, it’s authentication. :)

                      1. 1

                        The 9 bytes offer 2^72 possibilities. The base64 transformation is just for safe storage.

                        I assume you mean “so it’s valid in a URL param” (which IMO is worth mentioning given the intended audience)

                        Did you mean “Message Authentication Code”? Or am I missing one of the linguistic atrocities from bizdev?

                        I did mean “Message Authentication Code”, yes. There’s no reason to allow clients to tamper with these.

                    1. 3

                      Prepared statements resist SQL injection, but are not immune to injection, and I always break out in hives when people describe their complete SQL injection security strategy as “we use prepared statements”.

                      1. 7

                        There are roughly two kinds of SQL injection that are possible when prepared statements are used in a PHP application.

                        1. Higher-order SQL injection (i.e. stored procedures).
                        2. Weird bypasses if you’re using emulated prepared statements rather than actual prepared statements.

                        Neither are relevant to our codebase.

                        If there’s a third that I’m not aware of, I promise you most PHP developers aren’t either, and should be made aware.

                        1. 3

                          This depends on your database, doesn’t it? There are versions of MySQL where you can’t even parameterize a LIMIT. There are databases that can’t parameterize column names for search queries with selectable columns. It can be hard to build IN queries. There are lots of little exceptions.

                          It’s the confidence that “parameterized queries means no SQL injection” that scares me. We still find SQLI in applications despite the fact that most teams now pretty reliably parameterize queries.

                          1. 4

                            Allowing end users to supply column names implicitly invites injection, and a strict whitelist is the sane solution here. The linked post in that section explains the caveats in detail.

                            It sounds to me like “we aren’t actually using prepared statements for this query” is the culprit, however.

                        2. [Comment removed by author]

                          1. 4

                            In PHP’s PDO case, there’s only a corner case with emulated prepared statements that I’m aware of.

                        1. 7

                          This is a fine post, but I’m surprised how much more attention it got than the totally ignored post about the invalid curve attack (which I would guess inspired this post). “We want in depth technical articles. No, no, not that technical. Too deep, too deep, pull up.”

                          1. 4

                            You mean this one? If so, I bet the word “adobe” made a lot of people not click it.

                            1. 4

                              yeah, which is a shame.

                            2. 1

                              Yeah, not only was that that was far more innovative research than anything I’ve blogged about to date, it was one of the inspirations for this post.

                              As an attempt to mitigate this, I’m going to update my post to emphasize that attack and get more eyes on theirs. It’s good work.

                            1. 39

                              Reprising and reformatting something I wrote on that other site about this:

                              The problem with JWT/JOSE is that it’s too complicated for what it does. It’s a meta-standard capturing basically all of cryptography which wasn’t written by or with cryptographers. Crypto vulnerabilities usually occur in the joinery of a protocol. JWT was written to maximize the amount of joinery.

                              Negotiation: Good modern crypto constructions don’t do complicated negotiation or algorithm selection. Look at Trevor Perrin’s Noise protocol, which is the transport for Signal. Noise is instantiated statically with specific algorithms. If you’re talking to a Chapoly Noise implementation, you cannot with a header convince it to switch to AES-GCM, let alone “alg:none”. The ability to negotiate different ciphers dynamically is an own-goal. The ability to negotiate to no crypto, or (almost worse) to inferior crypto, is disqualifying.

                              Defaults: A good security protocol has good defaults. But JWT doesn’t even get non-replayability right; it’s implicit, and there’s more than one way to do it.

                              Inband Signaling: Application data is mixed with metadata (any attribute not in the JOSE header is in the same namespace as the application’s data). Anything that can possibly go wrong, JWT wants to make sure will go wrong.

                              Complexity: It’s 2017 and they still managed to drag all of X.509 into the thing, and they indirect through URLs. Some day some serverside library will implement JWK URL indirection, and we’ll have managed to reconstitute an old inexplicably bad XML attack.

                              Needless Public Key: For that matter, something crypto people understand that I don’t think the JWT people do: public key crypto isn’t better than symmetric key crypto. It’s certainly not a good default: if you don’t absolutely need public key constructions, you shouldn’t use them. They’re multiplicatively more complex and dangerous than symmetric key constructions. But just in this thread someone pointed out a library — auth0’s — that apparently defaults to public key JWT. That’s because JWT practically begs you to find an excuse to use public key crypto.

                              These words occur in a JWT tutorial (I think, but am not sure, it’s auth0’s):

                              “For this reason encrypted JWTs are sometimes nested: an encrypted JWT serves as the container for a signed JWT. This way you get the benefits of both.”

                              There are implementations that default to compressing plaintext before encrypting.

                              There’s a reason crypto people table flip instead of writing detailed critiques of this protocol. It’s a bad protocol. You look at this and think, for what? To avoid the effort of encrypting a JSON blob with libsodium and base64ing the output? Burn it with fire.

                              1. 3

                                I have a related but somewhat OT question. In one of the articles linked to by the article [1], they say this:

                                32 bytes of entropy from /dev/urandom hashed with sha256 is sufficient for generating session identifiers.

                                What purpose does the hash serve here besides transforming the original random number into a different random number? Surely the only reason to use hashing in session ID generation is if there’s no good RNG available in which case one might do something like hash(IP, username, user_agent, server_secret) to generate a unique token? (And in the presence of server-side session storage there’d be no point to including the secret in the hash because its presence in the session table would prove its validity.)

                                [1] https://paragonie.com/blog/2015/04/fast-track-safe-and-secure-php-sessions

                                1. 2

                                  Yeah, if urandom is actually good, then hashing it serves no real purpose. (In fact if you want to get mathematical, it can only decrease the randomness, but luckily by an absolutely negligible amount). Certain kinds of less-than-great randomness can be improved by hashing (as a form of whitening), but no good urandom deserves to be treated that way.

                                  1. 2

                                    The reason for that is PHP is weird. PHP hashes session entropy with MD5 by default. Setting it to SHA256 just minimizes the entropy reduction by this step. There is no “don’t hash, just use urandom” configuration directive possible (unless you’re rolling your own session management code, in which case, please just use random_bytes()).

                                    This is no longer the case in PHP 7.1.0, but that blog post is nearly two years old.

                                  2. 2

                                    Thanks for that very thorough dissection of JWT. Are there web app frameworks/stacks that do have helpfully secure and well-engineered defaults that you’d recommend?

                                    1. 1

                                      The post itself offers a suggestion (at the bottom): use libsodium.

                                      1. 1

                                        The author refers to Fernet as a JWT alternative. https://github.com/fernet/spec/blob/master/Spec.md

                                        However, Fernet is not nearly as comprehensive as JOSE and does not appear to be a suitable alternative.

                                        1. 2

                                          Hah, it seems the article changed a few times, and not just the title…