Rambling pontification on why capabilities are effective.

14 views
Skip to first unread message

Ian Denhardt

unread,
Mar 15, 2021, 10:34:27 AM3/15/21
to cap-...@googlegroups.com
Today I saw this post: <https://rachelbythebay.com/w/2018/04/27/uid/>,
and it got me thinking again about a particular way of framing the
effectiveness of capabilities that's been floating around in my head,
but that I haven't seen expressed anywhere. I'm curious as to other's
thoughts on the below, as well as pointers to prior art on the
particular framing.

It seems like capabilities really do two conceptually separate things
for you:

1. Eliminate confused deputy vulnerabilities, by following the central
dogma "Don't separate designation from authority"
2. Drastically reduce then tension between security and usability

(2) is done by *aligning* the mechanisms of composability with the
mechanisms of security, so that fine grained security naturally falls
out of the way we already organize and reason about code to keep it
maintainable, even outside of a security setting. This way, security
and functionality are not fighting each other.

But (2) doesn't necessarily imply the central dogma; people do sometimes
use separate designators in normal code, e.g. array indexes. This is
where the post comes in. The post posits some code that iterates over
user ids in an database where ids are allocated sequentially:

ban_senders_of_messages(messages) {
for (i = 0; i < messages.size(); ++i) {
ban_account(i);
}
}

This code has a *serious* bug; the author offers the corrected version:

ban_senders_of_messages(messages) {
for (i = 0; i < messages.size(); ++i) {
ban_account(message[i].sender);
}
}

The bug is that the first version passes the *loop index* to
ban_account() as opposed to using it to fetch the account id that is
supposed to be banned. (As an aside, the new code has a bug too, but a
much less serious one and orthogonal to both the author's point and
mine. Do you see it?)

The post goes on to make a point about the ills of numeric IDs, but the
point I'd like to make is: this is not a security bug, but the central
dogma still fixes it. Here's a (correct) version in Python:

def ban_senders_of_messages(messages):
for message in messages:
ban_account(message.sender)

Note that there is no loop index, since Python's for loop is really a
for-each loop.

I would argue that this bug is due to the violation of a non-security
analog of the central dogma: `i` is an out-of-band designator, and we
could imagine in a capability context, `message.sender` is the
"capability." So the bug has arisen by separating designation (`i`) from
"authority" (`message.sender`). Authority is the wrong word in this
case, since access control isn't the issue, but it's the same footgun.

Often when issues around sequential user ids come up, many people
suggest an alternate fix: use uuids, or something else that has a large
keyspace, so if you have a bug it's unlikely to result in accessing the
wrong object. I would argue that this is the non-security analogue of
using cryptographic secrets -- the designator is still separate from
the "authority" in some sense (see also all the discussion about why
cryptographic caps are less powerful than true ocaps), but it solves the
issue by making it hard to come up with the designator if you're not
supposed to be accessing that object.

So I think the core of capability security is really *two* insights,
which are conceptually separate things:

1. A general guideline for avoiding a certain class of bugs, independent
of whether those bugs are security related or not. This is the
central dogma.
2. An approach to making security play nice with other software
engineering concerns, but leveraging the using techniques of software
development in a security context.

Thoughts?

-Ian

Christopher Lemmer Webber

unread,
Mar 15, 2021, 12:18:20 PM3/15/21
to cap-...@googlegroups.com, Ian Denhardt
Ian Denhardt writes:

> Today I saw this post: <https://rachelbythebay.com/w/2018/04/27/uid/>,
> and it got me thinking again about a particular way of framing the
> effectiveness of capabilities that's been floating around in my head,
> but that I haven't seen expressed anywhere. I'm curious as to other's
> thoughts on the below, as well as pointers to prior art on the
> particular framing.
>
> It seems like capabilities really do two conceptually separate things
> for you:
>
> 1. Eliminate confused deputy vulnerabilities, by following the central
> dogma "Don't separate designation from authority"
> 2. Drastically reduce then tension between security and usability
>
> (2) is done by *aligning* the mechanisms of composability with the
> mechanisms of security, so that fine grained security naturally falls
> out of the way we already organize and reason about code to keep it
> maintainable, even outside of a security setting. This way, security
> and functionality are not fighting each other.

(2) is extremely important and under-discussed. I realized just how
critical it was after I managed to convince a number of people to pick
up zcap-ld but did not convince them yet of language-oriented ocaps,
which I ultimately believe are more important. I've begun increasingly
talking about "strong security with good developer ergonomics".

> But (2) doesn't necessarily imply the central dogma; people do sometimes
> use separate designators in normal code, e.g. array indexes. This is
> where the post comes in. The post posits some code that iterates over
> user ids in an database where ids are allocated sequentially:
>
> ban_senders_of_messages(messages) {
> for (i = 0; i < messages.size(); ++i) {
> ban_account(i);
> }
> }
>
> This code has a *serious* bug; the author offers the corrected version:
>
> ban_senders_of_messages(messages) {
> for (i = 0; i < messages.size(); ++i) {
> ban_account(message[i].sender);
> }
> }
>
> The bug is that the first version passes the *loop index* to
> ban_account() as opposed to using it to fetch the account id that is
> supposed to be banned. (As an aside, the new code has a bug too, but a
> much less serious one and orthogonal to both the author's point and
> mine. Do you see it?)

I don't aside from the usual risks of this ambient approach I guess?

I bet I'll hit myself when you point it out.

> The post goes on to make a point about the ills of numeric IDs, but the
> point I'd like to make is: this is not a security bug, but the central
> dogma still fixes it. Here's a (correct) version in Python:
>
> def ban_senders_of_messages(messages):
> for message in messages:
> ban_account(message.sender)
>
> Note that there is no loop index, since Python's for loop is really a
> for-each loop.
>
> I would argue that this bug is due to the violation of a non-security
> analog of the central dogma: `i` is an out-of-band designator, and we
> could imagine in a capability context, `message.sender` is the
> "capability." So the bug has arisen by separating designation (`i`) from
> "authority" (`message.sender`). Authority is the wrong word in this
> case, since access control isn't the issue, but it's the same footgun.

Yes!

> Often when issues around sequential user ids come up, many people
> suggest an alternate fix: use uuids, or something else that has a large
> keyspace, so if you have a bug it's unlikely to result in accessing the
> wrong object. I would argue that this is the non-security analogue of
> using cryptographic secrets -- the designator is still separate from
> the "authority" in some sense (see also all the discussion about why
> cryptographic caps are less powerful than true ocaps), but it solves the
> issue by making it hard to come up with the designator if you're not
> supposed to be accessing that object.
>
> So I think the core of capability security is really *two* insights,
> which are conceptually separate things:
>
> 1. A general guideline for avoiding a certain class of bugs, independent
> of whether those bugs are security related or not. This is the
> central dogma.
> 2. An approach to making security play nice with other software
> engineering concerns, but leveraging the using techniques of software
> development in a security context.

Yes, and (2) is more important than people realize because writing
software is hard, reasoning about security is hard, and composition is
always necessary and always happens. Thus we should have composition
layers where doing the right thing more often is important.

Side note, I think this highlights one of the reasons I feel so
uncomfortable with many of the groups of people who self-advertise as
"security experts"... a lot of security practices seem to involve
embracing the world as broken as it is and an egotistical approach to
being "better than everyone in being able to navigate it"... which feels
like a very ego-stroking approach. And of course message boards filled
with people pointing and wagging their fingers and laughing after the
fact about security vulnerabilities after they are pointed out *in
retrospect*. What fools! Well except we're all set up to be fools by
current architecture...

So these days I don't even find penetration testing of traditional
software very interesting. We know everything is so broken it's just
too easy. That isn't to say it isn't important, it just doesn't impress
me, and I hate the machismo culture which seems to have permeated it. A
much more important and useful job to me is figuring out how to build
things where people are more secure by default. This is why ocap
security approaches give me hope.

Of course, finding out about the solutions can also be maddening:

https://octodon.social/@cwebber/105889364886089079 /
https://twitter.com/dustyweb/status/1371153265161822212

> Thoughts?
>
> -Ian

Great writeup, thanks for putting it together!

- Chris

Matt Rice

unread,
Mar 15, 2021, 4:51:11 PM3/15/21
to cap-talk
On Mon, Mar 15, 2021 at 4:18 PM Christopher Lemmer Webber <cwe...@dustycloud.org> wrote:
Ian Denhardt writes:

> Today I saw this post: <https://rachelbythebay.com/w/2018/04/27/uid/>,
> and it got me thinking again about a particular way of framing the
> effectiveness of capabilities that's been floating around in my head,
> but that I haven't seen expressed anywhere. I'm curious as to other's
> thoughts on the below, as well as pointers to prior art on the
> particular framing.
>
> It seems like capabilities really do two conceptually separate things
> for you:
>
> 1. Eliminate confused deputy vulnerabilities, by following the central
>    dogma "Don't separate designation from authority"
> 2. Drastically reduce then tension between security and usability
>
> (2) is done by *aligning* the mechanisms of composability with the
> mechanisms of security, so that fine grained security naturally falls
> out of the way we already organize and reason about code to keep it
> maintainable, even outside of a security setting. This way, security
> and functionality are not fighting each other.

(2) is extremely important and under-discussed.  I realized just how
critical it was after I managed to convince a number of people to pick
up zcap-ld but did not convince them yet of language-oriented ocaps,
which I ultimately believe are more important.  I've begun increasingly
talking about "strong security with good developer ergonomics".

I suppose I cannot resist rambling pontification (Although this seems to be coming out as the converse ineffectiveness of ACLs),
the way I see it is, ACL's in particular cast
things as a decision procedure at time of use, that is for all access control decisions there exists and algorithm
which can respond yes or no at time of attempted use. Forcing that discounts the input which populates the access control matrix.
capabilities on the other hand do not force a decision procedure, they allow the user to make decisions...

on the receiver side: should I invoke this capability, or should I not invoke it?
and on the sender side: should I give this capability or not?
not really a decision procedure since there might not be an answer.

This is not to say that you can no longer write algorithms which make decisions in capability systems, just that the other way forces you to frame it as a decision procedure.
I.e. the null cap being some form of a decision procedure for the empty ACL.
I would guess the property (nobody, few?) cares about which drove everyone to ACL's is likely enumerability, as it is harder to imagine enumeration without prescribing decidability.
However you can have closed domains, and horton like enumeration of past decisions (I think I should stop here).

Anyhow to summarize I think ACLs through casting access control decisions artificially as a decision procedure divorces choice from the context in which that choice is made,
role based mechanisms try to add this context back in through the use of a role in a specific context. Where in capability systems choice is left entirely up to the user in the context in which they are already aware.
Since nobody *actually* enumerates in practice, we are left with the user navigating a holmesian mind palace in all cases, the one shortest distance between context and actual decision making process by the user is probably better, because in reality we can only computationally enumerate the actual decisions rather than intent, context, etc.

anyhow

--
You received this message because you are subscribed to the Google Groups "cap-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cap-talk+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/cap-talk/87y2eocrw5.fsf%40dustycloud.org.

Alan Karp

unread,
Mar 17, 2021, 11:23:50 AM3/17/21
to cap-...@googlegroups.com
A really nice post that should be more widely distributed, but I must be missing something.  Your second example is not using "i" to designate the sender; it is using "i" to designate the problematic message.  Even your first example doesn't show how "i" is used, so it might also be used to select the message.  Your third example is using an iterator, which necessarily has an internal "i" so it knows what message next() should return.  An example that makes your point would be one where message.sender returns an index into an array of senders.  In that case, you've got a lot more chances to go wrong, which is the point I believe you are making.

I heartily agree with (2).  In fact, Stiegler and I wrote papers making this point.  We just didn't articulate it as clearly as you did.  I would go one step further than you, though.  You talk about the impact on software development, but I think it also has a big impact on usability.  The capability model maps naturally to users selecting items in a GUI.  It's not quite as good at expressing attenuation.  Stiegler proposed WYSIWYSh (What You See Is What You Share) to solve this problem.  I used his approach, and I think we need something like 3-click sharing.

--------------
Alan Karp


--
You received this message because you are subscribed to the Google Groups "cap-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cap-talk+u...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages