策略语言与语法:从XACML到JSON,再到组合算法
策略语言,说白了就是ABAC系统的“法律条文”。你定义了属性,设计了模型,最后总得有个东西把这些规则写下来吧?这就是策略语言干的事。
这一章我们聊三个主流表达方式:XACML标准、ALFA语言、JSON策略表示法。最后再讲讲策略组合算法——当多条规则冲突时,到底听谁的。
XACML标准:老祖宗级别的规范
XACML(eXtensible Access Control Markup Language)是OASIS制定的标准。我最早接触ABAC时,啃的就是XACML 3.0的规范文档。说实话,那文档写得真叫一个“全面”,但也真叫一个“啰嗦”。
XACML的核心结构,我习惯用三个要素来记:
- PolicySet:策略集,可以嵌套其他PolicySet或Policy
- Policy:策略,包含一条或多条Rule
- Rule:规则,最细粒度的授权单元
每个Rule都有三个关键部分:
- Target:这条规则适用于谁、什么资源、什么动作
- Condition:更复杂的条件判断(比如“金额大于10000”)
- Effect:Permit或Deny
来看一个XACML的简化例子:
<Policy PolicyId="view-doc-policy" RuleCombiningAlg="deny-overrides">
<Target>
<AnyOf>
<AllOf>
<Match MatchId="string-equal">
<AttributeValue DataType="string">view</AttributeValue>
<AttributeDesignator Category="action:action-id"/>
</Match>
</AllOf>
</AnyOf>
</Target>
<Rule RuleId="deny-confidential" Effect="Deny">
<Target>
<AnyOf>
<AllOf>
<Match MatchId="string-equal">
<AttributeValue DataType="string">confidential</AttributeValue>
<AttributeDesignator Category="resource:classification"/>
</Match>
</AllOf>
</AnyOf>
</Target>
</Rule>
<Rule RuleId="permit-others" Effect="Permit"/>
</Policy>
我曾经踩过的坑:XACML的XML命名空间和AttributeDesignator的Category写错,导致策略永远匹配不上。调试了整整两天才发现是resource-id的大小写问题。嗯,XML的严格性有时候真是双刃剑。
ALFA语言:写给人类读的策略语言
XACML的XML太啰嗦了,对吧?Axiomatics公司搞了个ALFA(Axiomatics Language for Authorization),说白了就是XACML的“语法糖”。
我个人习惯用ALFA来写原型,因为它更像自然语言:
namespace com.example.document {
policy viewDocument {
target clause action.actionId == "view"
apply denyOverrides
rule denyConfidential {
target clause resource.classification == "confidential"
deny
}
rule permitOthers {
permit
}
}
}
你看,同样的逻辑,ALFA比XACML简洁了不止一个量级。而且它可以直接编译成XACML,兼容性没问题。
我的建议:如果你团队里有人不熟悉XML,先用ALFA写策略原型,再转成XACML部署。我在两个项目里都这么干,效率提升很明显。
JSON策略表示法:云原生的选择
现在很多云原生ABAC系统(比如AWS IAM、Google Cloud IAM)都用JSON来表示策略。JSON的好处是轻量、易解析、前端友好。
一个典型的JSON策略长这样:
{
"policyId": "view-doc-policy",
"ruleCombining": "deny-overrides",
"rules": [
{
"ruleId": "deny-confidential",
"effect": "Deny",
"condition": {
"resource.classification": "confidential"
}
},
{
"ruleId": "permit-others",
"effect": "Permit"
}
]
}
JSON表示法没有XACML那么严格的标准,但胜在灵活。我在做微服务网关的ABAC时,就用的JSON策略,因为可以直接存在Redis里,解析速度也快。
| 特性 | XACML | ALFA | JSON |
|---|---|---|---|
| 标准化程度 | OASIS标准 | 厂商扩展 | 无统一标准 |
| 可读性 | 差(XML冗长) | 好(类自然语言) | 中等 |
| 解析性能 | 慢 | 需编译 | 快 |
| 适用场景 | 企业级、跨系统 | 策略设计阶段 | 云原生、微服务 |
策略组合算法:当规则打架时
你想想看,一个请求可能匹配多条规则。一条说Permit,另一条说Deny,到底听谁的?这就是策略组合算法要解决的问题。
XACML定义了四种标准算法:
- Deny-overrides:只要有一条规则是Deny,结果就是Deny。安全优先。
- Permit-overrides:只要有一条规则是Permit,结果就是Permit。开放优先。
- First-applicable:按顺序匹配,第一条生效。性能最好。
- Only-one-applicable:只能有一条规则匹配,否则报错。最严格。
核心原则:Deny-overrides是最常用的安全策略。我在金融项目里一律用Deny-overrides,宁可误杀,不可放过。Permit-overrides适合内部协作系统,比如知识库。
来看一个Deny-overrides的决策流程:
请求: 用户A 试图 view 文档D (classification=confidential)
规则1: denyConfidential → 匹配 → Deny
规则2: permitOthers → 匹配 → Permit
组合算法: Deny-overrides
结果: Deny (因为Deny优先)
为什么会这样?因为Deny-overrides的逻辑是“只要有任何一条规则说Deny,整个结果就是Deny”。哪怕后面有100条Permit规则,也改变不了。
我曾经犯过的错:在Permit-overrides策略里,不小心加了一条过于宽泛的Permit规则,结果把机密文档都开放了。后来我养成了习惯:写策略时先画决策树,再编码。
策略组合算法的选择指南
我根据项目经验,整理了一个简单的选择表:
| 场景 | 推荐算法 | 原因 |
|---|---|---|
| 金融交易、医疗数据 | Deny-overrides | 安全第一,宁可拒绝 |
| 内部知识库、协作平台 | Permit-overrides | 开放协作,减少阻碍 |
| 高性能网关、CDN | First-applicable | 性能优先,减少计算 |
| 合规审计、严格管控 | Only-one-applicable | 避免规则冲突 |
本章知识体系
下面这张图,是我梳理的本章核心脉络:
嗯,这一章的内容就到这里。策略语言是ABAC的“血肉”,没有它,再好的模型也只是空架子。你写策略时,多想想“如果规则冲突了怎么办”,这比纠结语法细节更重要。