HNHacker News
TopNewBestAskShowJobs

CiPHPerCoder

6,663 karma · joined February 25, 2016

My name is Scott. I do a lot of open source security research, and cryptography.

Previously AWS Cryptography (2019 - 2023).

Unless otherwise stated, my opinions are my own and do not reflect my employer.

https://scottarc.blog/about/

submissionscomments
CiPHPerCoder··on Show HN: I made a meme creator that makes around $4k a month
How do we pay for this?
CiPHPerCoder··on API Tokens: A Tedious Survey
If I give you a map of kid -> key material that looks like this:

  {
      "my-super-cool-key-id": "some hs256 secret key string goes here",
      "another-key-id": "-----BEGIN RSA PUBLIC KEY-----\n ... snip ...",
      "yet-another-key-id": "----BEGIN EC PUBLIC KEY-----\n... snip ..."
  }
And let's say you've got three different API endpoints, which each hard-code a specific algorithm (one HS256, one PS256, one ES256). But, because of the framework you're developing in, you're expected to provide a single configuration object containing a map of key IDs used by the entire application. (This is a common framework quirk.)

What stops you from swapping out the kid in a JWT's header and getting the underlying library to use the wrong key type for the endpoint that accepts HS256?

    {
      "alg": "HS256",
  -   "kid": "my-super-cool-key-id",
  +   "kid": "yet-another-key-id",
      "typ": "JWT"
    }
The answer varies per implementation. The JWT standards do not call this misuse potential out at all.

Strictly listing the keys does not, at all, hard-code the algorithm those keys are used with in every possible programming language and runtime.

Some languages (Java) accidentally prevent this through type safety in the low-level crypto APIs. Others accidentally prevent this by not supporting the kid header.

I have yet to see a JWT library that deliberately prevents this misuse potential. Is that the library's fault? Or their defaults' fault?

EDIT:

The fix, by the way, requires doing this:

  {
      "my-super-cool-key-id": {
          "alg": "HS256",
          "key": "some hs256 secret key string goes here"
      },
      "another-key-id": {
          "alg": "PS256",
          "key": "-----BEGIN RSA PUBLIC KEY-----\n ... snip ..."
      },
      "yet-another-key-id": {
          "alg": "ES256",
          "key": "----BEGIN EC PUBLIC KEY-----\n... snip ..."
      }
  }
And then verifying that the alg for the key matches the alg for the token before attempting to verify the signature/MAC.
CiPHPerCoder··on API Tokens: A Tedious Survey
> Blame the library, or its defaults.

Every JWT proponent says that, but it's a misuse that shows up in multiple libraries, in multiple languages, and isn't explicitly called out in the JWT Best Practices RFC at all.

I'm going to blame the standard for being error-prone.

There's nothing in any JWT RFC, to date, that calls out the need for cryptographic keys to be the raw key material in addition to its parameter choices, rather than just the raw key material. That's a fault of the standard.

That's not a single library's fault. That's the standard's fault.

PASETO has this to say: https://github.com/paseto-standard/paseto-spec/blob/master/d...

> As for the key ID attack, this sounds like it's just a trick to know where the private key is located? It shouldn't be publicly accessible.

This doesn't involve private keys at all. Look at the proof of concept code. https://github.com/firebase/php-jwt/files/6966712/php-jwt-po...

CiPHPerCoder··on API Tokens: A Tedious Survey
> Why all the hate for JWTs?

> Just pick a crypto scheme and the JWT is just an encoding that makes it easier to use.

That's not what JWT is, but I can understand why someone would be misled into believing that.

JWT isn't just an encoding format, it also includes a crypto algorithm negotiation protocol that lets the attacker choose the algorithm. Even if you strictly allow-list which algorithm you want to support, you can accidentally bypass this control in many libraries if you support the `kid` (key ID) header. [1]

It also allows attackers to completely strip the security. [2] [3]

Put shortly, JWT is a gun aimed directly at your foot. That's why there's so much hate for JWTs.

[1] https://github.com/firebase/php-jwt/issues/351

[2] https://paragonie.com/blog/2017/03/jwt-json-web-tokens-is-ba...

[3] https://www.howmanydayssinceajwtalgnonevuln.com/

CiPHPerCoder··on API Tokens: A Tedious Survey
For PASETO, the quick guide to library support is https://paseto.io
CiPHPerCoder··on A riddle wrapped in a curve (2015)
> However, it also recommends RSA & classic Diffie-Hellman over multiplicative groups of integers, while Suite B exclusively recommended elliptic curve-based public-key crypto.

I think their reasoning is probably along the lines of "large RSA keys will buy you a little bit more time to migrate than small ECC keys if a quantum computer emerged today, due to memory constraints with what we think quantum computer will look like".

CiPHPerCoder··on Paserk: Platform Agnostic SERialized Keys
> * JWT can be secure if you are careful

https://www.howmanydayssinceajwtalgnonevuln.com/

https://www.zofrex.com/blog/2020/10/20/alg-none-jwt-nhs-cont...

https://twitter.com/SchmiegSophie/status/1413248896227155968

https://twitter.com/tqbf/status/1414087907938377735

etc.

> * there is wide support for JWT. (See for example this IETF draft https://datatracker.ietf.org/doc/html/draft-ietf-oauth-acces... as well as the numerous libraries)

Yes, and my intention is to make sure there is wide support for PASETO in the near future too.

> Maybe paseto can eventually displace JWT, but I have a hard time seeing how that happens.

It won't ever 100% displace JWT in the same way that we won't ever 100% displace PHP 4 from the Internet, or the legions of badly written tutorials full of SQL Injection vulnerabilities that new programmers learn from.

The goal isn't to displace JWT, though. The goal is to provide a secure-by-default, easy-to-use, hard-to-misuse alternative.

After all, just because it's possible to implement a set of building blocks "securely" doesn't mean the kit is secure. I wrote more about this here: https://paragonie.com/blog/2019/10/against-agility-in-crypto...

But even if you don't care about all of that, the upcoming PASETO versions (v3/v4) offer cryptographic properties that JWT does not, such as exclusive ownership. https://github.com/paragonie/paseto/blob/master/docs/Rationa...

------

Also, in case it wasn't obvious: PASERK is still a work-in-progress; things might change. Wait until you see a `1.0` tag before trying to implement it.

There is a reference implementation in PHP, but that's also experimental and no stable release has occurred there yet.

CiPHPerCoder··on Google results for PHP tutorials contain SQL injection vulnerabilities
> Great article. How should the community fix this problem with bad and dangerous tutorials?

By updating all of the old, insecure tutorials to redirect towards secure answers instead.

Details here: https://paragonie.com/blog/2018/01/our-ambitious-plan-make-i...

CiPHPerCoder··on Publicly Available Standards
Suggested title: Publicly Available Standards by ISO

ISO is somewhat unique in requiring you to pay money to even know what the standard says before you can ever think about being in compliance.

Most other standards organizations (i.e. NIST, IETF, W3C) do not have this weird financial burden, so merely "Publicly Available Standards" doesn't sell the significance of this.

Making their standards publicly available is a good move by ISO. I hope we see more of this.

CiPHPerCoder··on JWT Tokens are NOT safe
https://paseto.io
CiPHPerCoder··on PHP 8.0.0 beta 2
> Is there anything that PHP is developing or adopting that can not be had at other established languages?

Modern cryptography is baked in since 7.2.

https://libsodium.gitbook.io/doc/bindings_for_other_language...

Most of the people who shit on PHP have a lot of love for other languages. A survey of the cryptography features the "favored" languages offer will almost certainly fall into two camps:

1. "We wrap OpenSSL"

2. "Go compile it yourself" (i.e. there is nothing baked in)

There's a lot of badness with OpenSSL's API design, especially with asymmetric cryptography. For a fun exercise in these languages, try encrypting with RSA with OAEP padding, but without using SHA1 as your hash function.

For completeness, PHP is one of the languages that wraps OpenSSL too! But it also wraps libsodium, and the community has been moving towards libsodium (unless they need something from OpenSSL for the sake of backwards compatibility) since early in the 7.x series.

If you're going to provide cryptography features in your language, but you aren't shipping modern cryptography in your standard library, you're underperforming what PHP has offered for years at this point. The easiest way to meet the standard that PHP 7.2+ establishes is to add libsodium to your language's standard library.

(There are salient arguments for "why even provide a cryptography feature as part of the language at all?" but most of the languages that see real world deployment are already doing that.)

CiPHPerCoder··on You don’t need reproducible builds
Reproducible builds, combined with digital signatures and an append-only cryptographic ledger, solve a lot of these trust issues.

https://paragonie.com/blog/2016/10/guide-automatic-security-...

CiPHPerCoder··on ‘BlueLeaks’ Exposes Files from Hundreds of Police Departments
> Stewart Baker, an attorney at the Washington, D.C. office of Steptoe & Johnson LLP and a former assistant secretary of policy at the U.S. Department of Homeland Security, said the BlueLeaks data is unlikely to shed much light on police misconduct, but could expose sensitive law enforcement investigations and even endanger lives.

But then there was this: https://twitter.com/NatSecGeek/status/1273329710576152581

CiPHPerCoder··on Ask HN: How does your company manage its encryption keys?
Yep: https://asecure.cloud/a/scp_kms_delete_keys/
CiPHPerCoder··on Ask HN: How does your company manage its encryption keys?
If you use the AWS Encryption SDK, you can cache your data keys and reduce your calls to KMS: https://docs.aws.amazon.com/encryption-sdk/latest/developer-...
CiPHPerCoder··on Private key of DigiCert Certificate Transparency log compromised
> Not if the root of trust is secured by a proof-of-work blockchain

https://tonyarcieri.com/on-the-dangers-of-a-blockchain-monoc...

https://paragonie.com/blog/2017/07/chronicle-will-make-you-q...

> Not if zone operators upgrade to ECDSA as defined for DNSSEC in https://tools.ietf.org/html/rfc6605

First: That's a big "if". Lots of RSA legacy support.

Furthermore, ECDSA is so bad that Ed25519 and Ed448 are even coming to FIPS 186-5 later this year.

Citing ECDSA adoption in DNSSEC doesn't make as strong of a case as you might think.

CiPHPerCoder··on Lidl to Launch Rival to AWS
I don't want to sound dismissive, but I don't think their acquisition is going to be enough for them to compete with AWS.

https://www.camao.one/de-de/referenzen

Unless they have some other cards they haven't played yet, this sounds more like a headline intended for investors rather than customers.

CiPHPerCoder··on A look at modern PHP
> Even with PHP7, PHP still feels like it is playing catch up. There is nothing new or revolutionary in PHP7, just adopting features present in other major languages.

Of the first programming languages that cater to novices to some degree (which is important to project health, because excessive gatekeeping is toxic), PHP was the first to make Curve25519 and Argon2id widely available (through the sodium extension). (7.2)

Even with the "just use FFI" mindset of other languages, the experience is janky at best.

For example: Before sodium-plus [1] came along (which was something I created, so I'm removing it from the table for my criticism of the JS crypto ecosystem), JavaScript required knowing which of the following packages to install: [2] [3] [4]

There was no guidance available anywhere. Some of these APIs were suitable for browsers, others for mobile devices, and still others for server-side JavaScript. And their APIs were subtly incompatible with each other.

Java's in a similar situation [5] today.

> Java (Java Native Access): libsodium-jna

> Java (Android): Lazysodium for Android

> Java (Android): Libstodium

> Java (Android): Robosodium

> Java (Android): libsodium-JNI

> Java: Apache Tuweni (crypto module)

> Java: Lazysodium for Java

> Java: jsodium

> Java: Kalium

Yikes.

With PHP7, you just had to update to the latest version (and make sure your OS package vendor isn't huffing or eating glue, which was rare but still existent) and you had it.

There are probably still languages and runtimes today that make using modern cryptography (Ed25519, X25519, etc.) a miserable experience.

Miserable experiences moving to modern cryptography keep peoples' projects trapped in an early 2000's RSA-PKCS#1v1.5 + AES-CBC hellscape reminiscent of SSLv3 but somehow worse.

Thus, I would argue that what PHP did with libsodium counts as revolutionary.

Your move, $languagesThatHackerNewsFindSexierThanPHP

[1]: https://github.com/paragonie/sodium-plus

[2]: https://www.npmjs.com/package/libsodium-wrappers

[3]: https://github.com/sodium-friends/sodium-native

[4]: https://www.npmjs.com/package/sodium

[5]: https://libsodium.gitbook.io/doc/bindings_for_other_language...

CiPHPerCoder··on Auth0 JWT Auth Bypass: Case-Sensitive Blacklisting Is Harmful
> I really hope you're planning some agility in PASETO otherwise it's de-facto s* protocol that will have to be thrown away within a few years upon the first cryptographic weakness, breaking all applications that dared to adopt it.

Instead of cipher agility, PASETO uses versioned protocols.

My DEFCON Crypto & Privacy Village talk (slides and YouTube video at https://paseto.io for the curious) covered this distinction in detail.

CiPHPerCoder··on Auth0 JWT Auth Bypass: Case-Sensitive Blacklisting Is Harmful
I'll be sending an email to CFRG, probably next week, with any spec changes.

But before I resuscitate PASETO, XChaCha20 needs an RFC. It's pending IRTF kick-off.

https://tools.ietf.org/html/draft-irtf-cfrg-xchacha-03

CiPHPerCoder··on Auth0 JWT Auth Bypass: Case-Sensitive Blacklisting Is Harmful
The default is to not enforce any rules beyond the cryptographic signatures.

If you need any other validations, it's entirely up to you to specify what those are.

You might care about checking `exp`, but I might instead care about `iat` with a hard-coded token lifetime.

PASETO supports whatever zany business logic developers need, but doesn't enforce anything by default.

But once you add a rule to your parser, it will fail-closed on those rules.

> A token without timestamp will never be valid if a rule for checking timestamp is added in the parser?

Correct.

If your parser is set to check timestamps and one is invalid or omitted, it throws an exception.

CiPHPerCoder··on Auth0 JWT Auth Bypass: Case-Sensitive Blacklisting Is Harmful
PASETO has the same "claims" as JWT, except they're ISO 8601 timestamps rather than integers (UNIX timestamps).

They're not required (as they weren't in JWT). If you want to use them, use them. The parser will validate them if you want it to.

https://github.com/paragonie/paseto/blob/master/src/Rules/No...

https://github.com/paragonie/paseto/tree/master/docs/02-PHP-...

CiPHPerCoder··on Auth0 JWT Auth Bypass: Case-Sensitive Blacklisting Is Harmful
Yep, that's a fair assessment.

If you want ultra-simplicity and don't need clearsigned tokens (i.e. signed by a third party), you can get away with just using Branca. PASETO covers both use cases.

CiPHPerCoder··on Auth0 JWT Auth Bypass: Case-Sensitive Blacklisting Is Harmful
Simple answer: Because secure cryptography is backwards-incompatible with insecure cryptography, and the JOSE standards have a lot of legacy cruft that will be hard to jettison.

If you're going to put in the work (which I am), you might as well start with a clean slate rather than trying to piecemeal security improvements into their design-by-committee spec.

CiPHPerCoder··on Auth0 JWT Auth Bypass: Case-Sensitive Blacklisting Is Harmful
Nothing from 2020 yet. XChaCha has to be prioritized first.
CiPHPerCoder··on Auth0 JWT Auth Bypass: Case-Sensitive Blacklisting Is Harmful
Yes, Tink is acceptable too. :)
CiPHPerCoder··on Auth0 JWT Auth Bypass: Case-Sensitive Blacklisting Is Harmful
PGP isn't great either: https://latacora.micro.blog/2019/07/16/the-pgp-problem.html

Better options for PGP use cases:

- AWS Encryption SDK: https://docs.aws.amazon.com/encryption-sdk/latest/developer-...

- age https://age-encryption.org

- Magic Wormhole https://github.com/warner/magic-wormhole

- NaCl/libsodium (and/or usability wrappers) https://libsodium.gitbook.io/doc/

Better options for JWE use cases:

- PASETO: https://paseto.io

- Branca: https://branca.io

CiPHPerCoder··on Auth0 JWT Auth Bypass: Case-Sensitive Blacklisting Is Harmful
CFRG
CiPHPerCoder··on Auth0 JWT Auth Bypass: Case-Sensitive Blacklisting Is Harmful
> > Even giving the user a choice of ciphers to use is a recipe for disaster.

> How so? I'm still learning this stuff, so I'm genuinely curious.

https://paragonie.com/blog/2019/10/against-agility-in-crypto... :)

CiPHPerCoder··on Auth0 JWT Auth Bypass: Case-Sensitive Blacklisting Is Harmful
https://github.com/auth0/node-jsonwebtoken/blob/5f10bf9957a2...

The end result depends entirely on the behavior of JavaScript's Array.indexOf() implementation.

← PreviousPage 5 of 34Next →