Non-bearer macaroons

108 views
Skip to first unread message

Neil Madden

unread,
Oct 3, 2018, 4:10:30 AM10/3/18
to maca...@googlegroups.com
It struck me recently that while Macaroons are usually bearer tokens, the caveat mechanism allows them to also function as proof-of-possession/holder-of-key/bound tokens. This would provide some additional protection against token theft in cases where the token might be exposed (e.g., passed in a URL query that might be logged, or in a MitM/phishing scenario). For instance we could build a facility like OAuth 1.0/AWS HMAC request “signatures”.

The basic idea is that we can append a special “terminal” caveat that includes a hash of the request (normalised/encoded in some way) and a timestamp/nonce to prevent replay (or else a server-supplied challenge). The normal Macaroon MAC chain will prevent tampering with the token and the request (via the hash). This would effectively prevent the token being reused if it is intercepted as the caveat ties it to this one request and the replay protection prevents that kind of attack.

It seems to me that this provides a nice middle ground between pure bearer tokens and pure bound tokens in that the original Macaroon is a bearer token but the holder can selectively choose to use it in a proof-of-possession way.

This may seem obvious, but for someone who spends his day job poring through the never ending stream of OAuth and OpenID specifications, it’s very satisfying that this fits into the Macaroon framework as just another type of caveat rather than needing half a dozen additional specs! Is this something other people have done? Is there a wiki somewhere with Macaroon usage patterns and/or common caveats?

Cheers,

Neil

Tony Arcieri

unread,
Oct 3, 2018, 4:21:51 AM10/3/18
to maca...@googlegroups.com
On Wed, Oct 3, 2018 at 1:10 AM Neil Madden <neil.e...@gmail.com> wrote:
This may seem obvious, but for someone who spends his day job poring through the never ending stream of OAuth and OpenID specifications, it’s very satisfying that this fits into the Macaroon framework as just another type of caveat rather than needing half a dozen additional specs! Is this something other people have done?

It sounds like you're describing "Contextual Caveats", which is a titular feature of the Macaroons paper:


--
Tony Arcieri

Neil Madden

unread,
Oct 3, 2018, 5:37:07 AM10/3/18
to maca...@googlegroups.com
Can you clarify? I’ve read that paper many times but I’ve never seen anything quite like what I described. Holder of key proofs are only discussed in terms of third party caveats (using public key crypto), and the authorizing Macaroon is repeatedly described as a bearer token in that paper, so I don’t think it’s the same thing.

To clarify my suggestion. If I have a Macaroon issued from https://apples.example that lets me buy apples (perhaps just at certain times of day), and I want to send a request that orders 10 apples, I could just do a POST to https://apples.example/buy with the Macaroon in the Authorization header (for sake of example). That authorizing Macaroon is a bearer token, so if it gets intercepted for any reason (malicious or accidental) then it can be reused by anyone, so long as they satisfy the caveats. In OAuth and other protocols this can be “solved” by permanently binding the token to a public key and requiring that every usage of the token proves possession of the corresponding private key (typically by signing the request or using it to authenticate the TLS channel).

My observation is that this can be done with Macaroons by just appending a unique per-request caveat, and no additional key is required. To work the example:

Original macaroon = M0, with HMAC tag T0
Request payload = {"prod":"apples”,”quant":10}

Form an unambiguous encoding of the request URI, payload and selected headers - e.g., as per https://tools.ietf.org/html/rfc5849#section-3.4.1.1
request-hash = SHA-256(encoding)

Then form per-request macaroon M1 by appending a new caveat to M0 creating new HMAC tag T1 using T0 as the key, including request-hash and a timestamp/nonce or other anti-replay feature. You then send M1 in the Authorization header rather than M0:

POST /buy HTTP/1.1
Host: apples.example
Authorization: Macaroon M1
Content-Type: application/json

{"prod":"apples”,”quant":10}

An attacker that intercepts the request then only learns M1, which is cryptographically tied to that specific request and resists replay - so is useless to them. The original authorised party still has macaroon M0 and so can still generate new requests. They can also give M0 to other people and pass it around as a normal bearer token (appending other caveats on usage in the normal way). Tag T0 is effectively the key in a holder-of-key proof.

Maybe I’m missing this in the original paper, or this is an obvious consequence of the examples in that paper, but I like to have things spelled out explicitly. I suppose all I am really saying is that a contextual caveat can confine the context to one specific request and that in this limit a macaroon becomes a holder-of-key token.

— Neil

Tony Arcieri

unread,
Oct 3, 2018, 10:29:55 AM10/3/18
to maca...@googlegroups.com
On Wed, Oct 3, 2018 at 2:37 AM Neil Madden <neil.e...@gmail.com> wrote:
Can you clarify? I’ve read that paper many times but I’ve never seen anything quite like what I described. Holder of key proofs are only discussed in terms of third party caveats (using public key crypto), and the authorizing Macaroon is repeatedly described as a bearer token in that paper, so I don’t think it’s the same thing.

To clarify my suggestion. If I have a Macaroon issued from https://apples.example that lets me buy apples (perhaps just at certain times of day), and I want to send a request that orders 10 apples, I could just do a POST to https://apples.example/buy with the Macaroon in the Authorization header (for sake of example). That authorizing Macaroon is a bearer token, so if it gets intercepted for any reason (malicious or accidental) then it can be reused by anyone, so long as they satisfy the caveats. In OAuth and other protocols this can be “solved” by permanently binding the token to a public key and requiring that every usage of the token proves possession of the corresponding private key (typically by signing the request or using it to authenticate the TLS channel).

My observation is that this can be done with Macaroons by just appending a unique per-request caveat, and no additional key is required.

Aah, okay, seems you weren't describing contextual caveats. My apologies. 

This just sounds like offline attenuation to me. I'd say this is one of the things that makes Macaroons interesting, but what you're describing actually sounds quite similar to a system like S3. Except, as you've noted, how you use the token to craft the attenuated credential, whereas e.g. S3 has you do it with an HMAC key.

That said, though this idea is only mentioned a few times in passing in the paper (e.g. "C. Cookies as Macaroons") in the talks I've seen Ulfar Erlingsson give, this idea comes up quite a bit: clients should attenuate their Macaroons before presenting them, ensuring they always expire after a few seconds.

--
Tony Arcieri

Mark Lentczner

unread,
Oct 3, 2018, 10:43:09 AM10/3/18
to maca...@googlegroups.com
In the paper, these kinds of restrictions are discussed in abstract:
  • section II, paragraph 7 (on page 2, 2nd column) and figure 2 (top of page 3)
And then the specific uses you cite in:
  • section II A, paragraphs 3 & 4. (on page 3, 2nd column)

The HMAC construction of Macaroons allows for more flexibility with less server interaction: A client can restrict a macaroon before passing it or using such that if stolen, it is less useful that the more general macaroon the client possesses. Indeed, this is the very use case that led us to start developing Macaroons in the first place.

We spent less time in the paper on these kind of caveats, even though they are used commonly, because there are other similar mechanisms (cited in paper), whereas the 3rd party construction is quite novel.

- Mark

Steven Roose

unread,
Oct 3, 2018, 10:54:49 AM10/3/18
to maca...@googlegroups.com
To clarify my suggestion. If I have a Macaroon issued from https://apples.example that lets me buy apples (perhaps just at certain times of day), and I want to send a request that orders 10 apples, I could just do a POST to https://apples.example/buy with the Macaroon in the Authorization header (for sake of example). That authorizing Macaroon is a bearer token, so if it gets intercepted for any reason (malicious or accidental) then it can be reused by anyone, so long as they satisfy the caveats. In OAuth and other protocols this can be “solved” by permanently binding the token to a public key and requiring that every usage of the token proves possession of the corresponding private key (typically by signing the request or using it to authenticate the TLS channel).

Just to quickly react to this: the fact that clients, not only servers, can add additional caveats solves this problem kinda. The active use case of Macaroons that I have seen adds two per-request caveats before adding the bearer token. One being restricting the access to its own IP address and the other adding an additional expiration of 5 seconds in the future. That way it's really hard for a MITM to use the bearer token in a meaningful way. 

It seems like what you're describing is equivalent to not only adding "IP" and "expiration in 5 seconds" per request, but also "payload hash" caveat. That makes total sense. The same request could still be replayed by the interceptor until te 5 second deadline is expired though..



--
You received this message because you are subscribed to the Google Groups "Macaroons" group.
To unsubscribe from this group and stop receiving emails from it, send an email to macaroons+...@googlegroups.com.
To post to this group, send email to maca...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/macaroons/3F8953B3-0BF3-4BB1-98B4-BC5D6787A32A%40gmail.com.
For more options, visit https://groups.google.com/d/optout.

Neil Madden

unread,
Oct 3, 2018, 4:07:10 PM10/3/18
to maca...@googlegroups.com

> On 3 Oct 2018, at 15:55, Steven Roose <steve...@gmail.com> wrote:
>
> To clarify my suggestion. If I have a Macaroon issued from https://apples.example that lets me buy apples (perhaps just at certain times of day), and I want to send a request that orders 10 apples, I could just do a POST to https://apples.example/buy with the Macaroon in the Authorization header (for sake of example). That authorizing Macaroon is a bearer token, so if it gets intercepted for any reason (malicious or accidental) then it can be reused by anyone, so long as they satisfy the caveats. In OAuth and other protocols this can be “solved” by permanently binding the token to a public key and requiring that every usage of the token proves possession of the corresponding private key (typically by signing the request or using it to authenticate the TLS channel).
>
> Just to quickly react to this: the fact that clients, not only servers, can add additional caveats solves this problem kinda. The active use case of Macaroons that I have seen adds two per-request caveats before adding the bearer token. One being restricting the access to its own IP address and the other adding an additional expiration of 5 seconds in the future. That way it's really hard for a MITM to use the bearer token in a meaningful way.
>
> It seems like what you're describing is equivalent to not only adding "IP" and "expiration in 5 seconds" per request, but also "payload hash" caveat. That makes total sense. The same request could still be replayed by the interceptor until te 5 second deadline is expired though..
>

Right. There are a bunch of ways you could tighten that up even more. If you don’t mind the overhead you can do challenge response - the client makes the request without the macaroon initially (e.g. an OPTIONS request), the server responds with a WWW-Authenticate header containing a random challenge, the client includes that random challenge in the caveat. (The server must remember the challenge, of course). Or the caveat could contain a high resolution timestamp and the server enforces strict monotonicity for each client. Both require some state to be maintained (and synchronised) on the server.

An alternative that I have used before for operations that alter a resource on the server (i.e., PUT, POST, DELETE) is to maintain an ETag for each resource as a monotonic counter of some kind - every update bumps the counter. Requests then include an If-Match: <etag> header to enforce that the operation is only applied if the current ETag matches that in the header. This naturally prevents replay (if the If-Match header is included in the request hash) as once the operation has been performed once then the etag has changed.

— Neil

Neil Madden

unread,
Oct 3, 2018, 4:16:40 PM10/3/18
to maca...@googlegroups.com
Thanks for the pointer, I will see if any of his talks are online. That sounds like a good best practice in all cases.

When I find time to get back to it, I am currently writing a book on (REST) API security for a well-known publisher. The book will cover many of the usual suspects (OAuth etc), but I plan to feature macaroons prominently. So I am interested in collecting best practices and patterns that demonstrate the power of the approach. (This is also why I am interested in combining Macaroons with other technologies, as it will make the presentation easier).

— Neil

Neil Madden

unread,
Oct 3, 2018, 4:21:58 PM10/3/18
to maca...@googlegroups.com
I understand that - 3rd party caveats are incredibly powerful - and I can see why you would want to focus on that in the paper.

— Neil

Judson Lester

unread,
Oct 3, 2018, 5:07:52 PM10/3/18
to maca...@googlegroups.com
Two extra wrinkles though

It should be possible to require that a macaroon be attenuated in a particular way. But, I don't recall any of the standardization or libraries having such a feature to the verifiers. In other words, while a security minded client might do an offline attenuation, the server can't enforce that.

The other half is that many clients here are web browsers, and last I checked it wasn't feasible to do attenuation in a browser Javascript environment.

roger peppe

unread,
Oct 3, 2018, 5:39:01 PM10/3/18
to maca...@googlegroups.com
On 3 October 2018 at 22:07, Judson Lester <nya...@gmail.com> wrote:
> Two extra wrinkles though
>
> It should be possible to require that a macaroon be attenuated in a
> particular way. But, I don't recall any of the standardization or libraries
> having such a feature to the verifiers. In other words, while a security
> minded client might do an offline attenuation, the server can't enforce
> that.

I'm not sure that an attenuation requirement is *that* useful, as if a
client happens to have a macaroon without the required attenuation,
they're free to add it. That said, the verifier framework for
macaroons that we use does directly support structural caveats like
this. You can write a first party caveat checker that extracts the
macaroons being verified from its context argument using
https://godoc.org/gopkg.in/macaroon-bakery.v2/bakery/checkers#MacaroonsFromContext,
then does whatever structural checking is required.

> The other half is that many clients here are web browsers, and last I
> checked it wasn't feasible to do attenuation in a browser Javascript
> environment.

FWIW, that also is definitely possible in our macaroon JS code
(https://github.com/go-macaroon/js-macaroon; "macaroon" on npm),
although I can't speak for others.

cheers,
rog.
> https://groups.google.com/d/msgid/macaroons/CAOpbp3e_pCC1gWtYFLx6JPYUgFJEd_wRynva3zT3HUc4Y_tyeA%40mail.gmail.com.
Reply all
Reply to author
Forward
0 new messages