使用自动化推理和差分测试构建Cedar语言
Cedar是一种新的授权策略语言,被某中心的验证权限服务和某机构云服务使用,最近已公开发布。使用Cedar,开发人员可以编写策略,为其应用程序指定细粒度权限。应用程序随后通过调用Cedar的授权引擎来授权访问请求。由于Cedar策略与应用程序代码分离,它们可以独立编写、更新、分析和审计。
希望确保开发人员能够信任Cedar的授权决策是正确的。为了提供这种保证,在开发Cedar时遵循一个称为验证引导开发的两部分过程。首先,使用自动化推理来证明Cedar组件形式化模型的重要正确性属性。其次,使用差分随机测试来展示模型与生产代码匹配。
Cedar入门
Cedar是一种用于编写和执行自定义应用程序授权策略的语言。Cedar策略采用类似自然语言的语法表达。它们定义了谁(主体)可以在什么条件下(何时)对什么目标(资源)执行什么操作(动作)?
考虑一个简单的应用程序TinyTodo,设计用于管理任务列表。TinyTodo使用Cedar来控制谁可以执行什么操作。以下是TinyTodo的一个策略:
// 策略1
permit(principal, action, resource)
when {
resource has owner && resource.owner == principal
};
该策略规定,任何主体(TinyTodo用户)可以对任何资源(TinyTodo列表)执行任何操作,只要资源的创建者(由其所有者属性定义)与请求主体匹配。这是另一个TinyTodo Cedar策略:
// 策略2
permit (
principal,
action == Action::"GetList",
resource
)
when {
principal in resource.editors || principal in resource.readers
};
该策略规定,如果主体在资源的读者组或编辑组中,任何主体都可以读取任务列表的内容(Action::“GetList”)。这是第三个策略:
// 策略3
forbid (
principal in Team::"interns",
action == Action::"CreateList",
resource == Application::"TinyTodo"
);
该策略规定,任何实习生(在Team::"interns"中)被禁止使用TinyTodo(Application::“TinyTodo”)创建新任务列表(Action::“CreateList”)。
当应用程序需要强制执行访问控制时,如TinyTodo用户发出命令时,只需要向Cedar授权引擎发出相应请求。授权引擎根据Cedar策略和相关应用程序数据评估请求。如果返回Allow决定,TinyTodo可以继续执行命令。如果返回Deny决定,TinyTodo可以报告不允许该命令。
如何构建可信的Cedar?
在Cedar上的工作使用称为验证引导开发的过程,以确保Cedar的授权引擎做出正确的决策。该过程有两个部分。首先,在Dafny验证感知编程语言中对Cedar的授权引擎和验证器进行建模。使用Dafny,可以编写代码,并可以指定代码在所有情况下应该做什么的属性。使用Dafny内置的自动化推理能力,已经证明了代码满足各种安全和安全属性。
其次,使用差分随机测试(DRT)来确认Cedar的生产实现(用Rust编写)与Dafny模型的行为匹配。生成数百万个不同的输入,并将它们馈送到Dafny模型和生产代码中。如果两个版本总是产生相同的输出,就对实现与模型匹配有高度的信心。
证明Cedar授权属性
Cedar的授权算法被设计为默认安全,以下两个属性为例:
- 显式许可——权限仅由单独的许可策略授予,不会因错误或默认获得;
- 禁止覆盖许可——任何适用的禁止策略总是拒绝访问,即使有允许它的许可策略。
有了这些属性,策略集更容易理解。策略作者知道许可策略是授予访问权限的唯一方式,而禁止策略无论是否明确允许都会拒绝访问。
给定授权请求,Cedar授权引擎获取每个Cedar策略,并在将应用程序请求参数替换为主体、动作和资源变量后对其进行评估。例如,对于请求principal=User::“Alice”、action=Action::"GetList"和resource=List::“AliceList”,在策略1中替换变量将产生表达式List::“AliceList” has owner && List::“AliceList”.owner == User::“Alice”。如果此表达式评估为true,称请求满足策略。授权引擎将满足的禁止和许可策略收集到不同的集合中,然后做出决定。
将授权引擎建模为Dafny函数,并使用Dafny的自动化推理能力来陈述和证明显式许可和禁止覆盖许可属性。为了了解这如何帮助发现错误,考虑授权引擎的一个有错误版本:
function method isAuthorized(): Response { // 错误版本
var f := forbids();
var p := permits();
if f != {} then
Response(Deny, f)
else
Response(Allow, p)
}
该逻辑规定,如果任何禁止策略适用(集合f不是空集{}),结果应为Deny,从而覆盖任何适用的许可策略(在集合p中)。否则,结果为Allow。虽然此逻辑正确反映了所需的禁止覆盖许可属性,但未正确捕获显式许可。仅仅因为没有适用的禁止策略并不意味着有适用的许可策略。可以通过在Dafny中指定并尝试证明显式许可来看到这一点:
// 当许可策略满足时,请求被显式许可
predicate IsExplicitlyPermitted(request: Request, store: Store) {
exists p ::
p in store.policies.policies.Keys &&
store.policies.policies[p].effect == Permit &&
Authorizer(request, store).satisfied(p)
}
lemma AllowedIfExplicitlyPermitted(request: Request, store: Store)
ensures // 如果请求被显式许可,则允许
(Authorizer(request, store).isAuthorized().decision == Allow) ==>
IsExplicitlyPermitted(request, store)
{ ... }
Dafny谓词是接受参数并返回逻辑条件的函数,而Dafny引理是要证明的属性。IsExplicitlyPermitted谓词定义了给定请求存在适用许可策略的条件。AllowedIfExplicitlyPermitted引理陈述Allow决定必然意味着请求被显式许可。此引理不适用于上面的isAuthorized定义;Dafny抱怨后条件可能不在此返回路径上保持,并指向ensures子句。
以下是更正后的代码:
function method isAuthorized(): Response {
var f := forbids();
var p := permits();
if f == {} && p != {} then
Response(Allow, p)
else
Response(Deny, f)
}
现在,仅当没有适用的禁止策略且至少有一个适用的许可策略时,响应才为Allow。通过此更改,Dafny自动证明AllowedIfExplicitlyPermitted。它还证明了禁止覆盖许可(未显示)。
已经使用Cedar Dafny模型证明了各种属性。最重要的证明是Cedar验证器(确认Cedar策略与应用程序数据模型一致)是健全的:如果验证器接受策略,评估策略应永远不会导致某些类别的错误。在Dafny中执行此证明时,发现了验证器设计中的一些微妙错误,并能够纠正。
注意到Dafny模型不仅对自动化推理有用,对手动推理也有用。Dafny代码比Rust实现更容易阅读。作为衡量标准,在撰写本文时,授权器的Dafny模型代码行数约为生产代码的六分之一。Cedar用户和工具实现者都可以参考Dafny模型来快速了解Cedar工作原理的精确细节。
差分随机测试
一旦证明了Cedar Dafny模型的属性,希望提供证据表明这些属性也适用于生产代码,这可以通过使用DRT展示模型和生产代码行为相同来实现。使用cargo fuzz随机测试框架,生成数百万个输入(访问请求、伴随数据和策略),并将它们发送到Dafny模型引擎和Rust生产引擎。如果两个版本在决策上一致,则一切正常。如果它们不一致,则发现了错误。
有效使用DRT的主要挑战是通过生成有用且多样化的输入来确保必要的代码覆盖率。随机生成的策略不太可能提及随机生成的请求和数据中选择的相同组和属性。因此,纯随机生成将错过大量核心评估逻辑,并过度索引错误处理代码。为了解决这个问题,编写了几个输入生成器,包括注意生成彼此一致的策略、数据和请求的生成器,同时生成使用Cedar关键语言结构的策略。在撰写本文时,每晚运行DRT六小时,并执行大约1亿次总测试。
在Cedar开发期间使用DRT发现了模型与生产代码之间存在差异的角落情况,使其成为工具包中的重要工具。例如,在使用的Rust包中存在一个错误,用于IP地址操作;Dafny模型暴露了包在解析IP地址时的问题。由于错误在外部包中,在代码中修复了问题,同时等待上游修复。还发现了Cedar策略解析器中的微妙错误,授权器处理缺失应用程序数据的方式,以及应用程序数据上的命名空间前缀(例如TinyTodo::List::“AliceList”)的解释方式。
了解更多
在本文中讨论了为Cedar授权策略语言遵循的验证引导开发过程。在此过程中,在Dafny编程语言中对Cedar语言组件进行建模,并使用Dafny的自动化推理能力来证明它们的属性。通过差分随机测试检查Cedar生产代码是否与Dafny模型匹配。此过程在开发过程中揭示了几个有趣的错误,并让对Cedar授权引擎做出正确决策有了更大的信心。
要了解更多,可以在GitHub上查看Cedar Dafny模型和差分测试代码。还可以在Dafny网站和Cedar网站上了解有关Dafny和Cedar服务的更多信息。
更多精彩内容 请关注我的个人公众号 公众号(办公AI智能小助手)或者 我的个人博客 https://blog.qife122.com/
对网络安全、黑客技术感兴趣的朋友可以关注我的安全公众号(网络安全技术点滴分享)
400

被折叠的 条评论
为什么被折叠?



