ILP-over-HTTP Authentication

I have submitted a PR to the RFCs repo that updates and clarifies the Authentication section of the RFC to more clearly define what authentication mechanisms ILP Nodes should support in order to be IL-RFC-35 compliant.

The intention is to improve the overall security of the protocol, ensure that the various Connector implementations are interoperable, and provide some security-related best-practices for Connector operators when deploying ILP-over-HTTP.

Feedback welcome, either here or in the PR: https://github.com/interledger/rfcs/pull/531

I don’t have a particularly strong opinion on this, but it is worth noting there are concerns about the security of JWTs; namely, the complexity of the protocol, and a lack of defaults that make them harder to use securely.

I highly recommend reading this comment, which provides some indicts of JWTs from a crypto perspective.

(Additionally, No Way, JOSE! Javascript Object Signing and Encryption is a Bad Standard That Everyone Should Avoid).

While this has since been patched, a few years ago, the complexity exposed critical bugs in a number of the JWT implementations.

Alternatively, something like Branca is simple, offers reasonable crypto defaults, and I believe can be used in much the same way. (There are implementations for JS and Rust, but not a Java one. That said, the spec is really straightforward).

Ultimately, we may value the library support and other advantages over that (which I think is perfectly reasonable), but it’s still worth discussing the potential tradeoffs.

Thanks for your post, @kincaid! Those are good links, and worth reading (especially the developer counter-perspectives in the YC link).

Before making any particular comments, I think it’s helpful to clarify the goals (as I see it) of the PR I submitted that suggests using JWT for authentication tokens.

Fundamentally, we need at least one Authentication scheme that all Connectors running ILP-over-HTTP implement, and that scheme should attempt to satisfy the following:

  1. The scheme should be as simple as possible (emphasis: “as possible”. This doesn’t mean “simplicity over security”. Instead, it means there’s a tradeoff, and we want to find the right balance).
  2. The scheme should be required for all Connectors to implement in order to encourage broad deployment.
  3. The scheme should consider high-performance (to support high packet throughput).
  4. The scheme should resist replays (emphasis: resist, not necessarily be replay-proof, in order to aid in high-performance if required).
  5. The scheme should not negate or prevent the ability of operators to layer-on more security on top of it, depending on the requirements and characteristics of any given deployment.

That last point has been something I’ve been thinking a lot about lately. One anecdote I’ve been thinking about is that the manner in which we would secure an ATM (for cash) is not the same manner that we would secure Fort Knox (otherwise we’d have tanks in front of the local grocery store). As part of this exercise, it’s important to keep that in mind – every deployment of ILP is likely going to be unique.

OK, with all of that out of the way, the YC article brings up some interesting points, though I find them to be somewhat orthogonal to the RFC PR. For clarity, I’ve replicated some of the criticisms, and placed some of my thoughts next to each one.

  1. “JWT is complicated”. True, it can be – but we’re spec’ing a very narrow and simple JWT profile with known qualities.
  2. “The JWT spec was designed by committee”. Probably true, but that doesn’t have any bearing on our use-case (IMHO).
  3. “JWT’s defaults are incoherent”. I actually don’t follow this argument. It hinges around replayability, but not every use-case demands replay resistance (though I could be convinced otherwise).
  4. (Me summarizing the author): “The standard has things I don’t like.” I agree. But does this apply to HMAC-SHA-256 and a JWT used only for Authentication?
  5. “JWT is 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”.
    1. These aren’t invalid points. It’s just that the comment reduces an argument to a simple solution that is insufficient for our engineering problem.
    2. Advocating for a 20-bytes bearer token is somewhat similar to the SIMPLE Authentication Profile in my PR, but it has drawbacks (see PR for some of them).
    3. Do we generate a new token on every request? If so, what algorithm(s) do we use? What does the “on the wire” encoding look like? You’ll notice that even PRASETO has an encoding!
    4. Alternatively, do we re-use the bearer token across multiple requests? If so, we definitely want to narrow the token-validity window, but how? We’re back to creating our own on-the-wire encoding.

As for Braca, it’s the first I’ve heard of it, but I really like the idea of it. In practice though, we should consider various things (as you said, @kincaid):

  1. I don’t see a Java or C++ or Swift implementations. Java and Swift will be key libraries, and we’ve already seen from the OER-encoding choice that this has caused drag on developer adoption of ILP due to having to implement an OER parser where none exists (even if it’s easy). Note to the community – I’ve come to really like the OER-encoding choice, but we shouldn’t ignore that it has impeded adoption. We should consider that lesson here.

  2. Library implementation lifetime is a risk, as we’ve seen with the JWT implementations – it took a few years for those libraries to mature and figure out the footguns. Even though Braca “makes it hard to shoot yourself in the foot”, developers can do silly things sometimes, so how stable are the implementations? Say what you will about JWT, but the libraries have been around for awhile.

  3. @tarcieri I’d be curious to hear what you thinks about Braca…?

3 Likes