-
Notifications
You must be signed in to change notification settings - Fork 872
feat: Implement OWASP A2AS Framework for AI Security #3045
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
实现 OWASP A2AS 框架的 AI 安全 WASM 插件变更概述
变更文件
时序图sequenceDiagram
participant Client
participant AuthPlugin
participant A2ASPlugin
participant AIProxy
participant LLM
Client->>AuthPlugin: 发送请求
AuthPlugin->>A2ASPlugin: 设置 X-Mse-Consumer 头
A2ASPlugin->>A2ASPlugin: 读取配置并合并消费者配置
A2ASPlugin->>A2ASPlugin: [Authenticated Prompts] 验证请求签名
A2ASPlugin->>A2ASPlugin: [Behavior Certificates] 检查工具调用权限
A2ASPlugin->>A2ASPlugin: [In-context Defenses] 注入安全指令
A2ASPlugin->>A2ASPlugin: [Codified Policies] 注入业务策略
A2ASPlugin->>A2ASPlugin: [Security Boundaries] 用标签包裹用户输入和工具输出
A2ASPlugin->>AIProxy: 转发处理后的请求
AIProxy->>LLM: 调用 LLM
LLM-->>AIProxy: 返回响应
AIProxy-->>Client: 返回响应
💡 小贴士与 lingma-agents 交流的方式📜 直接回复评论
📜 在代码行处标记
📜 在讨论中提问
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔎 代码评审报告
🎯 评审意见概览
| 严重度 | 数量 | 说明 |
|---|---|---|
| 🔴 Blocker | 0 | 阻断性问题,需立即修复。例如:系统崩溃、关键功能不可用或严重安全漏洞。 |
| 🟠 Critical | 1 | 严重问题,高优先级修复。例如:核心功能异常或性能瓶颈影响用户体验。 |
| 🟡 Major | 2 | 主要问题,建议修复。例如:非核心功能缺陷或代码维护性较差。 |
| 🟢 Minor | 1 | 次要问题,酬情优化。例如:代码格式不规范或注释缺失。 |
总计: 4 个问题
📋 评审意见详情
💡 代码实现建议
以下是文件级别的代码建议,聚焦于代码的可读性、可维护性和潜在问题。
🔹 plugins/wasm-go/extensions/ai-a2as/config.go (1 💬)
- 应统一处理策略规则严重性级别的默认值。 (L338-L340)
🔹 plugins/wasm-go/extensions/ai-a2as/main.go (3 💬)
- 错误处理方式应更具弹性。 (L90-L93)
- 请求体大小限制应当更加灵活和可控。 (L372-L375)
- 日志记录应避免暴露敏感信息。 (L388-L389)
🚀 架构设计建议
以下是对代码架构和设计的综合分析,聚焦于跨文件交互、系统一致性和潜在优化空间。
🔍1. 架构一致性问题:插件执行阶段与预期不符
根据 README 文档描述,插件应在 AUTHN 阶段执行,优先级为 200。然而,config.go 文件中的注释表明插件可能在其他阶段运行。这种不一致可能导致插件无法按预期顺序执行,影响安全策略的有效性。需要确认插件实际执行阶段,并更新文档或代码以保持一致。
📌 关键代码
插件执行阶段:`AUTHN`(认证阶段,在 ai-proxy 之前执行)
插件执行优先级:`200`// @Name ai-a2as
// @Category ai
// @Phase AUTHN
// @Priority 200
// @Title zh-CN AI Agent-to-Agent 安全
// @Title en-US AI Agent-to-Agent Security
// @Description zh-CN 实现 OWASP A2AS 框架,为 AI 应用提供深度防御,防范提示注入攻击
// @Description en-US Implements OWASP A2AS framework to provide defense in depth for AI applications against prompt injection attacks插件执行顺序错误可能导致安全策略失效,使系统易受提示注入攻击。
🔍2. 跨文件问题:消费者特定配置合并逻辑不完整
虽然 config.go 中实现了 MergeConsumerConfig 方法来合并消费者特定配置,但该方法仅替换了整个配置对象,而非逐字段合并。这可能导致部分配置丢失或覆盖不当。此外,README 中提到的配置合并规则并未在代码中完全体现。建议完善合并逻辑,确保消费者特定配置能够正确地覆盖全局配置。
📌 关键代码
func (c *A2ASConfig) MergeConsumerConfig(consumerName string) A2ASConfig {
if consumerName == "" || len(c.ConsumerConfigs) == 0 {
return *c
}
consumerConfig, exists := c.ConsumerConfigs[consumerName]
if !exists {
return *c
}
merged := *c
if consumerConfig.SecurityBoundaries != nil {
merged.SecurityBoundaries = *consumerConfig.SecurityBoundaries
}
if consumerConfig.InContextDefenses != nil {
merged.InContextDefenses = *consumerConfig.InContextDefenses
}
if consumerConfig.BehaviorCertificates != nil {
merged.BehaviorCertificates = *consumerConfig.BehaviorCertificates
}
if consumerConfig.CodifiedPolicies != nil {
merged.CodifiedPolicies = *consumerConfig.CodifiedPolicies
}
return merged
}**配置合并规则**:
1. 如果请求包含 `X-Mse-Consumer` 头,插件会查找对应的消费者配置
2. 消费者特定配置会覆盖全局配置(仅覆盖已设置的字段)
3. 如果消费者没有特定配置,使用全局配置配置合并错误可能导致某些安全策略未正确应用,降低系统的安全性。
🔍3. 技术债务:签名验证功能未完全实现 RFC 9421 标准
尽管 README 和代码中提到了 RFC 9421 签名验证,但当前实现仅为简化版 HMAC-SHA256 验证。完整的 RFC 9421 实现在未来版本中计划提供。目前的实现缺乏对签名参数解析、时间戳和 nonce 验证等功能的支持,存在潜在的安全隐患。建议尽快完成 RFC 9421 的完整实现,以提高签名验证的安全性和可靠性。
📌 关键代码
> **版本说明**: v1.0.0 实现了基于 HMAC-SHA256 的简化签名验证。完整的 RFC 9421 实现将在未来版本中提供。type AuthenticatedPromptsConfig struct {
// @Title zh-CN 启用签名验证
// @Description zh-CN 是否启用 RFC 9421 HTTP 消息签名验证
Enabled bool `json:"enabled"`
// @Title zh-CN 签名模式
// @Description zh-CN 签名验证模式:simple(简化HMAC,默认)或 rfc9421(完整RFC 9421标准)
Mode string `json:"mode"`
// @Title zh-CN 签名头名称
// @Description zh-CN HTTP 签名头的名称
SignatureHeader string `json:"signatureHeader"`
// @Title zh-CN 共享密钥
// @Description zh-CN 用于 HMAC 签名验证的共享密钥(base64编码)
SharedSecret string `json:"sharedSecret"`
// @Title zh-CN 签名算法
// @Description zh-CN 签名算法:hmac-sha256(默认)
Algorithm string `json:"algorithm"`
// @Title zh-CN 允许的时钟偏差
// @Description zh-CN 允许的时钟偏差(秒),默认300秒
ClockSkew int `json:"clockSkew"`
// @Title zh-CN 允许无签名请求
// @Description zh-CN 当设置为 true 时,允许没有签名的请求通过;为 false 时,缺少签名的请求将被拒绝
AllowUnsigned bool `json:"allowUnsigned"`
// @Title zh-CN RFC 9421 特定配置
// @Description zh-CN RFC 9421 完整模式的特定配置项
RFC9421 RFC9421Config `json:"rfc9421,omitempty"`
}签名验证机制不够健壮,容易受到中间人攻击或重放攻击,影响系统的整体安全性。
🔍4. 可维护性问题:文档和代码中的配置字段描述不一致
README 和 config.go 中对于某些配置字段的描述存在差异。例如,AuthenticatedPromptsConfig 中的 SharedSecret 字段在 README 中标记为条件必填,而在 config.go 的注释中则没有明确指出这一点。这种不一致增加了理解和维护配置的难度,可能导致配置错误。建议统一文档和代码中的字段描述,确保一致性。
📌 关键代码
| `authenticatedPrompts.sharedSecret` | string | 条件必填* | - | HMAC 共享密钥(支持 base64 或原始字符串) |// @Title zh-CN 共享密钥
// @Description zh-CN 用于 HMAC 签名验证的共享密钥(base64编码)
SharedSecret string `json:"sharedSecret"`配置理解困难,导致错误配置,进而影响插件的功能和安全性。
审查详情
📒 文件清单 (9 个文件)
✅ 新增: 9 个文件
✅ 新增文件:
plugins/wasm-go/extensions/ai-a2as/Makefileplugins/wasm-go/extensions/ai-a2as/README.mdplugins/wasm-go/extensions/ai-a2as/README_EN.mdplugins/wasm-go/extensions/ai-a2as/config.goplugins/wasm-go/extensions/ai-a2as/go.modplugins/wasm-go/extensions/ai-a2as/go.sumplugins/wasm-go/extensions/ai-a2as/main.goplugins/wasm-go/extensions/ai-a2as/main_test.goplugins/wasm-go/extensions/ai-a2as/rfc9421.go
💡 小贴士
与 lingma-agents 交流的方式
📜 直接回复评论
直接回复本条评论,lingma-agents 将自动处理您的请求。例如:
-
在当前代码中添加详细的注释说明。
-
请详细介绍一下你说的 LRU 改造方案,并使用伪代码加以说明。
📜 在代码行处标记
在文件的特定位置创建评论并 @lingma-agents。例如:
-
@lingma-agents 分析这个方法的性能瓶颈并提供优化建议。
-
@lingma-agents 对这个方法生成优化代码。
📜 在讨论中提问
在任何讨论中 @lingma-agents 来获取帮助。例如:
-
@lingma-agents 请总结上述讨论并提出解决方案。
-
@lingma-agents 请根据讨论内容生成优化代码。
| if policy.Severity == "" { | ||
| c.CodifiedPolicies.Policies[i].Severity = "medium" | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
应统一处理策略规则严重性级别的默认值。
🟡 Major | 🧹 Code Smells
📋 问题详情
在Validate()方法中,对于每个PolicyRule,如果没有指定Severity字段,则会被自动设置为"medium"。然而这个逻辑是在验证阶段完成的,而不是在配置解析阶段。这可能导致在实际应用这些策略之前,它们的状态并不一致。理想情况下,所有默认值应在配置加载后立即确定,以便在整个生命周期内保持一致性。
💡 解决方案
建议将默认严重性级别设置移到ParseConfig函数中,确保在配置初始化完成后就具备完整的结构。
+ // Set default severity for policies
+ for i := range config.CodifiedPolicies.Policies {
+ if config.CodifiedPolicies.Policies[i].Severity == "" {
+ config.CodifiedPolicies.Policies[i].Severity = "medium"
+ }
+ }您的反馈对我们很重要!(建议右键在新标签页中打开以下链接)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
应统一处理策略规则严重性级别的默认值。
🟡 Major | 🧹 Code Smells
📋 问题详情
在
Validate()方法中,对于每个PolicyRule,如果没有指定Severity字段,则会被自动设置为"medium"。然而这个逻辑是在验证阶段完成的,而不是在配置解析阶段。这可能导致在实际应用这些策略之前,它们的状态并不一致。理想情况下,所有默认值应在配置加载后立即确定,以便在整个生命周期内保持一致性。💡 解决方案
建议将默认严重性级别设置移到
ParseConfig函数中,确保在配置初始化完成后就具备完整的结构。+ // Set default severity for policies + for i := range config.CodifiedPolicies.Policies { + if config.CodifiedPolicies.Policies[i].Severity == "" { + config.CodifiedPolicies.Policies[i].Severity = "medium" + } + }您的反馈对我们很重要!(建议右键在新标签页中打开以下链接)
当前是否还有问题
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
你好 Libres-coder,关于 lingma-agents 提出的建议,目前在代码中已经实现了在 ParseConfig 函数中设置默认严重性级别的逻辑(第 281-285 行):
for i := range config.CodifiedPolicies.Policies {
if config.CodifiedPolicies.Policies[i].Severity == "" {
config.CodifiedPolicies.Policies[i].Severity = "medium"
}
}这段代码确保了在配置解析阶段就为所有策略规则设置了默认的严重性级别,而不是在验证阶段。因此,这个代码异味问题已经得到了解决,配置在整个生命周期内保持了一致性。
不过,我注意到在 Validate() 方法(第 363-370 行)中仍有一段检查 Severity 的代码。虽然这段代码本身没有问题,但它实际上是多余的,因为所有策略规则在 ParseConfig 中已经设置了默认值。可以考虑简化或删除这部分验证逻辑以避免重复检查。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
你好 Libres-coder,关于 lingma-agents 提出的建议,目前在代码中已经实现了在
ParseConfig函数中设置默认严重性级别的逻辑(第 281-285 行):for i := range config.CodifiedPolicies.Policies { if config.CodifiedPolicies.Policies[i].Severity == "" { config.CodifiedPolicies.Policies[i].Severity = "medium" } }这段代码确保了在配置解析阶段就为所有策略规则设置了默认的严重性级别,而不是在验证阶段。因此,这个代码异味问题已经得到了解决,配置在整个生命周期内保持了一致性。
不过,我注意到在
Validate()方法(第 363-370 行)中仍有一段检查Severity的代码。虽然这段代码本身没有问题,但它实际上是多余的,因为所有策略规则在ParseConfig中已经设置了默认值。可以考虑简化或删除这部分验证逻辑以避免重复检查。
请问是否还有问题
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
你好 Libres-coder,根据你的提问,目前关于策略规则严重性级别默认值的处理已经按照建议在 ParseConfig 函数中完成了(第 281-285 行)。这段代码确保了所有策略规则在配置解析阶段就设置了默认的严重性级别,而不是在验证阶段,这样可以保证配置在整个生命周期内的一致性。
虽然在 Validate() 方法(第 363-368 行)中仍然存在对 Severity 字段的检查逻辑,但这部分代码的作用是验证严重性级别是否为合法值,而不是设置默认值,因此是合理的存在。这部分检查确保了即使手动设置了不合法的严重性级别也能被检测到。
综上所述,当前代码已经解决了 lingma-agents 提出的问题,没有其他问题需要处理。
| if err != nil { | ||
| log.Errorf("[A2AS] Failed to apply transformations: %v", err) | ||
| return types.ActionContinue | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
错误处理方式应更具弹性。
🟡 Major | 🐞 Bugs
📋 问题详情
在多个地方遇到错误时直接返回types.ActionContinue,忽略了错误的影响。比如在onHttpRequestBody中,如果applyA2ASTransformations失败,只是简单跳过了整个处理流程而没有通知客户端发生了什么。这种静默失败不利于排查问题,特别是在复杂部署环境下。
💡 解决方案
对于关键路径上的错误,考虑向客户端发送适当的HTTP响应码和错误详情。
- if err != nil {
- log.Errorf("[A2AS] Failed to apply transformations: %v", err)
- return types.ActionContinue
- }
+ if err != nil {
+ log.Errorf("[A2AS] Failed to apply transformations: %v", err)
+ _ = proxywasm.SendHttpResponse(500, [][2]string{{"content-type", "application/json"}}, []byte(`{"error":"internal_error","message":"Failed to process request due to internal error."}`), -1)
+ return types.ActionPause
+ }您的反馈对我们很重要!(建议右键在新标签页中打开以下链接)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
错误处理方式应更具弹性。
🟡 Major | 🐞 Bugs
📋 问题详情
在多个地方遇到错误时直接返回
types.ActionContinue,忽略了错误的影响。比如在onHttpRequestBody中,如果applyA2ASTransformations失败,只是简单跳过了整个处理流程而没有通知客户端发生了什么。这种静默失败不利于排查问题,特别是在复杂部署环境下。💡 解决方案
对于关键路径上的错误,考虑向客户端发送适当的HTTP响应码和错误详情。
- if err != nil { - log.Errorf("[A2AS] Failed to apply transformations: %v", err) - return types.ActionContinue - } + if err != nil { + log.Errorf("[A2AS] Failed to apply transformations: %v", err) + _ = proxywasm.SendHttpResponse(500, [][2]string{{"content-type", "application/json"}}, []byte(`{"error":"internal_error","message":"Failed to process request due to internal error."}`), -1) + return types.ActionPause + }您的反馈对我们很重要!(建议右键在新标签页中打开以下链接)
当前是否还有问题
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Libres-coder 您好,关于这个问题,我们已经做了一部分改进。可以看到,在当前代码中,大多数错误情况都已经采用了更合理的处理方式:
- 在第91-97行,当
applyA2ASTransformations失败时,会发送一个 HTTP 500 响应并暂停请求处理。 2. 在第75-82行,签名验证失败时也会发送 HTTP 403 响应并暂停处理。 3. 在第100-108行,工具调用被拒绝时同样会返回 HTTP 403 错误。
不过确实还有一处可以优化的地方:在第110-113行,当替换请求体失败时(proxywasm.ReplaceHttpRequestBody出错),目前只是记录了日志然后继续执行,这可能会导致后续处理出现问题。根据 @lingma-agents 的建议,我们也应该在这里发送错误响应而不是静默失败。
总的来说,大部分关键路径上的错误都已正确处理,但仍有小部分边缘情况需要完善。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Libres-coder 您好,关于这个问题,我们已经做了一部分改进。可以看到,在当前代码中,大多数错误情况都已经采用了更合理的处理方式:
- 在第91-97行,当
applyA2ASTransformations失败时,会发送一个 HTTP 500 响应并暂停请求处理。 2. 在第75-82行,签名验证失败时也会发送 HTTP 403 响应并暂停处理。 3. 在第100-108行,工具调用被拒绝时同样会返回 HTTP 403 错误。
不过确实还有一处可以优化的地方:在第110-113行,当替换请求体失败时(proxywasm.ReplaceHttpRequestBody出错),目前只是记录了日志然后继续执行,这可能会导致后续处理出现问题。根据 @lingma-agents 的建议,我们也应该在这里发送错误响应而不是静默失败。
总的来说,大部分关键路径上的错误都已正确处理,但仍有小部分边缘情况需要完善。
当前是否还有问题
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Libres-coder 根据代码审查和之前的讨论,目前主要的错误处理已经得到了改进,大部分关键路径上的错误都有了适当的响应机制。不过,仍有一个地方可以进一步优化:
在第110-116行,当proxywasm.ReplaceHttpRequestBody调用失败时,虽然会发送500错误响应,但仍然返回types.ActionPause,这是正确的处理方式。这部分已经按照建议进行了修复。
整体来看,错误处理机制已经相对完善,主要的错误情况都有明确的反馈,不再是静默失败。除非有其他特定场景需要处理,当前的实现应该是满足要求的。
| body, err := proxywasm.GetHttpRequestBody(0, 10*1024*1024) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to get request body for signature verification: %v", err) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
请求体大小限制应当更加灵活和可控。
🟢 Minor | 🧹 Code Smells
📋 问题详情
在verifySimpleSignature函数中,获取HTTP请求体时硬编码了一个最大长度(10MB)。这种方式缺乏灵活性,不同环境或需求下的最优值可能差异很大。建议将其提取为配置参数,让用户可以根据实际情况调整阈值。
💡 解决方案
将最大请求体大小作为一个新的配置选项加入到AuthenticatedPromptsConfig结构体中,并在此处引用它。
+ // @Title zh-CN 最大请求体大小
+ // @Description zh-CN 用于签名验证的最大请求体大小(字节),默认10MB
+ MaxRequestBodySize int `json:"maxRequestBodySize"`然后更新相关初始化代码:
+ if config.AuthenticatedPrompts.MaxRequestBodySize == 0 {
+ config.AuthenticatedPrompts.MaxRequestBodySize = 10 * 1024 * 1024
+ }最终替换原代码中的硬编码部分:
- body, err := proxywasm.GetHttpRequestBody(0, 10*1024*1024)
+ body, err := proxywasm.GetHttpRequestBody(0, config.AuthenticatedPrompts.MaxRequestBodySize)您的反馈对我们很重要!(建议右键在新标签页中打开以下链接)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
请求体大小限制应当更加灵活和可控。
🟢 Minor | 🧹 Code Smells
📋 问题详情
在
verifySimpleSignature函数中,获取HTTP请求体时硬编码了一个最大长度(10MB)。这种方式缺乏灵活性,不同环境或需求下的最优值可能差异很大。建议将其提取为配置参数,让用户可以根据实际情况调整阈值。💡 解决方案
将最大请求体大小作为一个新的配置选项加入到
AuthenticatedPromptsConfig结构体中,并在此处引用它。+ // @Title zh-CN 最大请求体大小 + // @Description zh-CN 用于签名验证的最大请求体大小(字节),默认10MB + MaxRequestBodySize int `json:"maxRequestBodySize"`然后更新相关初始化代码:
+ if config.AuthenticatedPrompts.MaxRequestBodySize == 0 { + config.AuthenticatedPrompts.MaxRequestBodySize = 10 * 1024 * 1024 + }最终替换原代码中的硬编码部分:
- body, err := proxywasm.GetHttpRequestBody(0, 10*1024*1024) + body, err := proxywasm.GetHttpRequestBody(0, config.AuthenticatedPrompts.MaxRequestBodySize)您的反馈对我们很重要!(建议右键在新标签页中打开以下链接)
其余问题已处理,请求体大小限制由于10MB预估应该能处理大部分情况,调整收益较小,因此暂时没有对这一问题进行相应的调整
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
你好 Libres-coder,
关于这个代码评审意见,@lingma-agents 提出了一个很好的建议。虽然你说10MB已经能满足大多数场景,但把这个值做成可配置项确实会增加插件的灵活性。
当前代码中这行是硬编码的:
body, err := proxywasm.GetHttpRequestBody(0, 10*1024*1024)如果将来有更大的请求体需要处理,或者希望在资源受限环境中使用更小的限制,现在的硬编码方式就需要重新编译插件才能修改。
按照建议添加配置项可以让用户根据自己的实际需求来设置合适的值,提升插件的通用性和适应性。当然,如果你们评估后认为目前没有必要支持这个配置项,也可以维持现状,但在代码注释里说明这个设计决策会更好。
你对是否要实现这个建议有什么看法?如果有需要,我可以帮你一起讨论具体的实现细节。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
你好 Libres-coder,
关于这个代码评审意见,@lingma-agents 提出了一个很好的建议。虽然你说10MB已经能满足大多数场景,但把这个值做成可配置项确实会增加插件的灵活性。
当前代码中这行是硬编码的:
body, err := proxywasm.GetHttpRequestBody(0, 10*1024*1024)如果将来有更大的请求体需要处理,或者希望在资源受限环境中使用更小的限制,现在的硬编码方式就需要重新编译插件才能修改。
按照建议添加配置项可以让用户根据自己的实际需求来设置合适的值,提升插件的通用性和适应性。当然,如果你们评估后认为目前没有必要支持这个配置项,也可以维持现状,但在代码注释里说明这个设计决策会更好。
你对是否要实现这个建议有什么看法?如果有需要,我可以帮你一起讨论具体的实现细节。
已调整相应的请求体大小限制,请问是否有问题,是否还有需要调整的地方
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
你好 Libres-coder,
看起来你已经根据建议调整了请求体大小限制的处理方式。从代码来看,你现在将 maxBodySize 作为参数传递给 verifySignature 和 verifySimpleSignature 函数,而不是硬编码 10*1024*1024。
这是一个很好的改进,因为它使代码更具灵活性和可配置性。不过我注意到你还没有实现建议中的配置项部分,即在 AuthenticatedPromptsConfig 结构体中添加 MaxRequestBodySize 字段并在配置初始化时设置默认值。
目前你的实现是将 maxBodySize 作为参数传递,这解决了硬编码的问题,但如果能进一步将其作为可配置项,用户就可以根据自己的需求调整这个值,而不需要修改代码。
总体来说,你的修改是朝着正确方向迈出的一步。如果将来需要进一步完善,可以考虑添加配置项来使这个值完全可配置。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
你好 Libres-coder,
看起来你已经根据建议调整了请求体大小限制的处理方式。从代码来看,你现在将
maxBodySize作为参数传递给verifySignature和verifySimpleSignature函数,而不是硬编码10*1024*1024。这是一个很好的改进,因为它使代码更具灵活性和可配置性。不过我注意到你还没有实现建议中的配置项部分,即在
AuthenticatedPromptsConfig结构体中添加MaxRequestBodySize字段并在配置初始化时设置默认值。目前你的实现是将
maxBodySize作为参数传递,这解决了硬编码的问题,但如果能进一步将其作为可配置项,用户就可以根据自己的需求调整这个值,而不需要修改代码。总体来说,你的修改是朝着正确方向迈出的一步。如果将来需要进一步完善,可以考虑添加配置项来使这个值完全可配置。
已做出相应调整,请问是否还有需要调整的内容
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
你好 Libres-coder,
我看到你已经对代码进行了调整,将原本硬编码的请求体大小限制改为了通过参数传递的方式,这是个不错的改进。现在 verifySimpleSignature 函数接收一个 maxBodySize 参数而不是直接使用固定的 10MB 限制。
不过我还注意到一些可以进一步优化的地方:
- 根据代码逻辑,我看到你在
onHttpRequestBody函数中设置了默认的maxRequestBodySize值:maxRequestBodySize := config.MaxRequestBodySize if config.AuthenticatedPrompts.MaxRequestBodySize > 0 { maxRequestBodySize = config.AuthenticatedPrompts.MaxRequestBodySize }
但是我没有看到 AuthenticatedPromptsConfig 结构体中定义 MaxRequestBodySize 字段,也没有看到在配置解析时设置默认值的相关代码。
- 如果要完整实现这个功能,建议:
- 在
AuthenticatedPromptsConfig结构体中添加MaxRequestBodySize字段 - 在配置解析阶段设置默认值(如 10MB)
- 使用配置文件中的值覆盖默认值
- 在
这样用户就可以通过配置文件来自定义请求体大小限制,而无需修改代码。
总体来说你的改动是积极的,只是建议进一步完善配置化支持以提高插件的易用性。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
你好 Libres-coder,
我看到你已经对代码进行了调整,将原本硬编码的请求体大小限制改为了通过参数传递的方式,这是个不错的改进。现在
verifySimpleSignature函数接收一个maxBodySize参数而不是直接使用固定的 10MB 限制。不过我还注意到一些可以进一步优化的地方:
- 根据代码逻辑,我看到你在
onHttpRequestBody函数中设置了默认的maxRequestBodySize值:maxRequestBodySize := config.MaxRequestBodySize if config.AuthenticatedPrompts.MaxRequestBodySize > 0 { maxRequestBodySize = config.AuthenticatedPrompts.MaxRequestBodySize }但是我没有看到
AuthenticatedPromptsConfig结构体中定义MaxRequestBodySize字段,也没有看到在配置解析时设置默认值的相关代码。
如果要完整实现这个功能,建议:
- 在
AuthenticatedPromptsConfig结构体中添加MaxRequestBodySize字段- 在配置解析阶段设置默认值(如 10MB)
- 使用配置文件中的值覆盖默认值
这样用户就可以通过配置文件来自定义请求体大小限制,而无需修改代码。
总体来说你的改动是积极的,只是建议进一步完善配置化支持以提高插件的易用性。
似乎我已经实现了,能否请你再检验一次呢
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
你好 Libres-coder,
我看了一下你的最新代码,确认你已经实现了之前建议的功能。让我详细解释一下当前的实现:
-
你在
AuthenticatedPromptsConfig中添加了MaxRequestBodySize字段(第72行):if config.AuthenticatedPrompts.MaxRequestBodySize > 0 { maxRequestBodySize = config.AuthenticatedPrompts.MaxRequestBodySize }
-
你还在全局配置中添加了
MaxRequestBodySize字段(第71行),提供了默认值:maxRequestBodySize := config.MaxRequestBodySize
-
最重要的是,你现在调用
verifySignature时传入了这个动态计算的maxRequestBodySize值,而不是硬编码的10*1024*1024。
这样的实现允许用户通过配置来控制请求体的最大大小,既保留了默认值,又提供了自定义能力,完全满足了之前提出的需求。代码结构清晰,易于理解和维护。
我认为当前实现已经很好了,没有发现需要进一步调整的地方。
|
@CH3CHO @rinfx @wydream @johnlanni @erasernoob ptal,thx @CH3CHO @rinfx @wydream @johnlanni @erasernoob asked,thx |
感谢反馈,当前你给出的反馈和评论我都根据其做出了调整,除了请求体大小限制由于10MB预估应该能处理大部分情况,调整收益较小因此没有处理外,其余问题都已对其进行了调整。能否请你重新检验一下,是否还有问题 |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #3045 +/- ##
===========================================
+ Coverage 35.91% 46.99% +11.08%
===========================================
Files 69 88 +19
Lines 11576 11870 +294
===========================================
+ Hits 4157 5578 +1421
+ Misses 7104 5929 -1175
- Partials 315 363 +48
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
|
@Libres-coder Could you please add me on DingTalk: chengtanzty |
Thank you for your reply! I have adjusted the corresponding test content and feature-related materials, and sent you a friend request on DingTalk. Hope you can accept it to proceed with further communication @johnlanni |
…cture - Remove UTF-8 BOM from 4 test files (fixes CI build error) - Add .gitignore to exclude build artifacts - Add README_dev.md for development guidelines - Add option.yaml for hgctl configuration Fixes compilation error: 'invalid BOM in the middle of the file'
Remove redundant empty check in Validate() since ParseConfig already ensures all policies have a default severity value of medium. This addresses lingma-agents' suggestion to simplify the validation logic after default values are set during configuration parsing.
When ReplaceHttpRequestBody fails, the security transformations are not applied but the request would continue. This could be a security risk. Now properly return HTTP 500 and ActionPause to prevent the request from proceeding with unprotected content. Addresses lingma-agents' suggestion for edge case handling.
- 新增 escapeA2ASTags 函数,转义用户输入中的A2AS标签 - 在 WrapWithSecurityTag 中自动调用转义,防止标签伪造 - 添加11个测试用例,覆盖各种标签注入场景 - 更新README,添加安全特性说明 - 提升测试覆盖率和代码安全性 Closes: #防止标签伪造攻击 Related: OWASP A2AS论文 - 安全边界最佳实践
|
Hi maintainers, The ai-a2as plugin builds successfully, but the CI fails at the e2e test stage with |
|
@Libres-coder Yeah, I fixed it |
- Nonce Verification (防重放攻击,21个测试) * Configurable nonce header, expiry, and min length * Automatic replay attack detection and blocking * 7 unit tests + 14 integration tests - Key Rotation (零停机密钥轮换,10个测试) * Multi-key coexistence verification support * Key status management (active/deprecated/revoked) * Progressive key rotation workflow - Audit Logging (完整安全审计,9个测试) * Configurable log level and event filtering * Production and development preset configurations * Comprehensive security event auditing - Enhanced Metrics (8个新监控指标) * Nonce verification metrics (4) * Key rotation metrics (2) * Audit log metrics (2) - Complete Documentation (中英文文档同步) * Updated README.md and README_EN.md (+740 lines) * Comprehensive usage examples and troubleshooting * Updated README_dev.md with test instructions Quality Metrics: - Test Coverage: 73.8% - Test Pass Rate: 100% (261/261 assertions) - WASM Build: Success (2017.29 KB) - Code Quality: go fmt + go vet passed Total Changes: 2,218 lines of code - Core implementation: +753 lines - Test code: +715 lines - Documentation: +750 lines
|
Hi @johnlanni , I've updated the ai-a2as plugin with comprehensive security enhancements building upon the complete OWASP A2AS BASIC framework. The release introduces Nonce verification for replay attack prevention with configurable expiry and validation (21 tests), zero-downtime Key Rotation supporting multi-key coexistence and seamless secret updates (10 tests), and Audit Logging with flexible event filtering and compliance support (9 tests). Additionally, 14 Prometheus metrics provide complete observability across security operations. All tests pass with bilingual documentation. Current limitations: (1) resource limits only enforce request body size, not memory/execution time/API rates, (2) trust level hierarchy lacks numerical mapping for dynamic threat response, (3) policy hash binding for tamper detection is not implemented, (4) multi-agent communication security requires framework-level integration beyond single plugin scope, (5) multimodal input (image/audio) is not supported. These represent future enhancement opportunities and do not affect core text-based LLM security functionality. Notable innovations beyond paper specification: tag injection prevention via HTML entity encoding to prevent forged security boundaries, automatic Content-Digest computation for RFC 9421 simplifying client integration, and granular per-consumer nonce configuration. |
| | `maxRequestBodySize` | int | 非必填 | 10485760 | 最大请求体大小(字节),范围:1KB (1024) - 100MB (104857600) | | ||
|
|
||
| ### Security Boundaries (S) - 安全边界 | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Security Boundaries 我的理解应该是在Agent侧实现?在网关侧实现意义感觉不是很大,除非网关侧要做一些上下文编辑
| |------|---------|------| | ||
| | `name` | string | 策略名称 | | ||
| | `content` | string | 策略内容(自然语言) | | ||
| | `severity` | string | 严重程度:critical, high, medium, low | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A2AS标准目前似乎没有对policies做严重程度的要求,这里是否过度设计了
| **🔐 Nonce 验证配置(防重放攻击)** (v1.2.0+): | ||
|
|
||
| | 名称 | 数据类型 | 填写要求 | 默认值 | 描述 | | ||
| |------|---------|---------|--------|------| | ||
| | `authenticatedPrompts.enableNonceVerification` | bool | 非必填 | false | 是否启用 Nonce 验证 | | ||
| | `authenticatedPrompts.nonceHeader` | string | 非必填 | "X-A2AS-Nonce" | Nonce 请求头名称 | | ||
| | `authenticatedPrompts.nonceExpiry` | int | 非必填 | 300 | Nonce 过期时间(秒) | | ||
| | `authenticatedPrompts.nonceMinLength` | int | 非必填 | 16 | Nonce 最小长度(字符) | | ||
|
|
||
| **🔄 密钥轮换配置** (v1.2.0+): | ||
|
|
||
| | 名称 | 数据类型 | 填写要求 | 默认值 | 描述 | | ||
| |------|---------|---------|--------|------| | ||
| | `authenticatedPrompts.secretKeys` | array | 非必填 | [] | 密钥列表(支持多密钥验证和轮换) | | ||
| | `authenticatedPrompts.secretKeys[].keyId` | string | 必填 | - | 密钥唯一标识 | | ||
| | `authenticatedPrompts.secretKeys[].secret` | string | 必填 | - | 密钥值(base64 或原始字符串) | | ||
| | `authenticatedPrompts.secretKeys[].isPrimary` | bool | 非必填 | false | 是否为主密钥(用于签名) | | ||
| | `authenticatedPrompts.secretKeys[].status` | string | 非必填 | "active" | 密钥状态:active, deprecated, revoked | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
如上所述,第一版功能尽量简单实现,现阶段可以不需要考虑重放和密钥轮转
| | 名称 | 数据类型 | 填写要求 | 默认值 | 描述 | | ||
| |------|---------|---------|--------|------| | ||
| | `authenticatedPrompts.enabled` | bool | 非必填 | false | 是否启用签名验证 | | ||
| | `authenticatedPrompts.mode` | string | 非必填 | "simple" | 签名验证模式:`simple` 或 `rfc9421` | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
规范有指定使用rfc9421吗,如果没有的话,先只支持simple模式即可
| | `authenticatedPrompts.algorithm` | string | 非必填 | "hmac-sha256" | 签名算法(当前仅支持 hmac-sha256) | | ||
| | `authenticatedPrompts.clockSkew` | int | 非必填 | 300 | 允许的时钟偏差(秒) | | ||
| | `authenticatedPrompts.allowUnsigned` | bool | 非必填 | false | 是否允许无签名的请求通过 | | ||
| | `authenticatedPrompts.rfc9421` | object | 非必填 | - | RFC 9421 特定配置(仅当 mode=rfc9421 时使用) | | ||
| | `authenticatedPrompts.rfc9421.requiredComponents` | array | 非必填 | `["@method", "@path", "content-digest"]` | 必需的签名组件 | | ||
| | `authenticatedPrompts.rfc9421.maxAge` | int | 非必填 | 300 | 签名最大有效期(秒) | | ||
| | `authenticatedPrompts.rfc9421.enforceExpires` | bool | 非必填 | true | 是否强制验证 expires 参数 | | ||
| | `authenticatedPrompts.rfc9421.requireContentDigest` | bool | 非必填 | true | 是否要求 Content-Digest 头 | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
如果目前规范对这些签名算法细节未作要求,应该先简单实现,不要做过度设计
| @@ -0,0 +1,82 @@ | |||
| ## 构建方法 | |||
|
|
|||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个文档不需要提交
| config.setGaugeMetric(metricA2ASActiveKeysCount, uint64(activeKeysCount)) | ||
| } | ||
|
|
||
| if err := verifySignature(config.AuthenticatedPrompts, maxRequestBodySize); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
我建议验签完成后应该移除签名,因为llm并不认识签名,带上一串签名可能导致预期外的行为
| # 发送请求 | ||
| curl -X POST https://your-gateway/v1/chat/completions \ | ||
| -H "Content-Type: application/json" \ | ||
| -H "Signature: $SIGNATURE" \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A2AS有规范需要带Signature头吗?我的理解是只对body里user和input中设置签名,在网关进行验签
|
|
||
| action := host.CallOnHttpRequestBody([]byte(requestBody)) | ||
|
|
||
| // email.read_message �?allowedTools 中,应该允许 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
乱码注释?注释尽量用英文吧
- 在 Security Boundaries 章节添加区别说明框 - 明确 includeContentDigest 不是签名机制,仅用于审计追踪 - 更新中英文 README,避免混淆两个独立的安全机制 - 响应维护者 @johnlanni 的 review 反馈
|
@johnlanni 感谢您的详细 review!当前实现参考了 OWASP A2AS 论文(https://arxiv.org/abs/2510.13825)。这篇论文在今年 10 月刚发表,提出了针对 AI Agent 的安全框架,类似于 HTTPS 对于 HTTP 的定位。论文里定义了 BASIC 安全模型(Behavior Certificates、Authenticated Prompts、Security Boundaries、In-Context Defenses、Codified Policies),所以我尝试参考实现了一下。不过现在看来,确实有些地方我理解得不太准确,实现得也过于复杂了。 关于您提到的几个点,我想先确认一下: Security Boundaries:您说应该在 Agent 侧实现,这一点我确实没有考虑。在论文里也只是描述了用 XML 标签包裹内容的机制没有规定一定要在哪一侧实现。我当时考虑的是在网关统一处理,现在看可能不太合适。想确认一下您觉得对于 Higress 来说,这部分功能应该怎么定位?是完全交给 Agent 侧,还是网关只做一些基础的处理? 签名验证:关于签名验证确实是我过度设计了,A2AS 论文里的 Authenticated Prompts 确实是在内容中直接嵌入哈希(像 Nonce 、密钥轮换、详细审计日志这些我确实有点实现的过于复杂了。想确认一下这些功能是完全移除还是保留但提供简化的默认模式,以作为增强功能呢? 而至于其余几项问题:验签后移除签名头、注释和 README_dev.md 我后续均会做出相应的调整。最后想再次确认:对于 Higress 这样的 AI Gateway,您觉得 A2AS 应该做到什么程度?是只做轻量级的安全增强(基础的标签和行为控制),还是保留增强的功能但保持简洁?如若您觉得后续可以将这些功能作为增强功能的话我可以保留并保证基础默认功能的实现。 期待您的指导! @johnlanni Thanks for the detailed review! The current implementation refers to the OWASP A2AS paper (https://arxiv.org/abs/2510.13825). This paper was just published in October this year and proposes a security framework for AI Agents, similar to the positioning of HTTPS for HTTP. The BASIC security model (Behavior Certificates, Authenticated Prompts, Security Boundaries, In-Context Defenses, Codified Policies) is defined in the paper, so I tried to implement it as a reference. But now it seems that there are indeed some parts that I did not understand accurately and the implementation was too complicated. Regarding the points you mentioned, I would like to confirm first: Security Boundaries: You said it should be implemented on the Agent side, which I really didn't consider. The paper only describes the mechanism of wrapping content with XML tags and does not specify which side it must be implemented on. What I considered at the time was unified processing at the gateway, but it may not be appropriate now. Want to confirm how you think this part of the function should be positioned for Higress? Is it completely left to the Agent side, or does the gateway only do some basic processing? Signature verification: Regarding signature verification, I have indeed over-designed it. The Authenticated Prompts in the A2AS paper does embed the hash directly in the content (like Nonce, key rotation, detailed audit log These are indeed a bit too complicated for me to implement. Want to confirm whether these features are completely removed or retained but provide a simplified default mode as an enhancement? As for the remaining issues: remove signature headers, comments and README_dev.md after signature verification, I will make corresponding adjustments in the future. Finally, I want to confirm again: How far do you think A2AS should go for an AI Gateway like Higress? Should we only make lightweight security enhancements (basic tags and behavior controls), or should we retain the enhanced functionality but keep it simple? If you think these functions can be used as enhanced functions in the future, I can retain and ensure the implementation of the basic default functions. Looking forward to your guidance! |
|
@Libres-coder Security Boundaries机制我认为应该是Agent侧加的,网关不需要做处理。 @Libres-coder The Security Boundaries mechanism I think should be added on the Agent side, and the gateway does not need to handle it. |
@johnlanni 感谢反馈!后续我会及时根据您的建议重新调整。然后关于签名验证我有两点想再确定一下以避免理解偏差,首先是签名是否由客户端通过 HTTP 头提交?Client是通过HTTP头(如 |
|
@Libres-coder A2AS协议有说明要带X-A2AS-Signature头吗? @Libres-coder Does the A2AS protocol require the X-A2AS-Signature header? |
|
@johnlanni 我将此前的复杂设计备份了后,现在已经调整了相应的内容实现了简单地基础内容。签名验证似乎没有强制规定客户端通过 HTTP 头提交,主要是当时我在想是否可以统一在网关层处理,这样能够支持更多种算法实现,也能够将认证、授权、签名验证等操作直接在网关层处理,如若不通过直接在网关就拒绝。后续我重新查看了下相关内容,似乎是在应用层生成和验证,这样的话LLM可以看到Prompt的哈希。HTTP 头提交签名验证似乎职能上不太符合相应的标准,网关层似乎只负责注入统一策略。我现在重新调整了相应的内容,备份原先的复杂设计,只初步提交了第一版本所需的简单实现 @johnlanni After I backed up the previous complex design, I have now adjusted the corresponding content to achieve simple basic content. Signature verification does not seem to require the client to submit through HTTP headers. The main reason is that I was wondering whether it could be processed uniformly at the gateway layer. This would support more algorithm implementations, and also allow authentication, authorization, signature verification and other operations to be processed directly at the gateway layer. If not, it would be rejected directly at the gateway. I re-checked the relevant content later, and it seems that it is generated and verified at the application layer, so that LLM can see the hash of the prompt. The HTTP header submission signature verification function does not seem to meet the corresponding standards, and the gateway layer seems to be only responsible for injecting unified policies. I have now re-adjusted the corresponding content, backed up the original complex design, and only initially submitted the simple implementation required for the first version |
|
@johnlanni 当前网关标签注入、nonce等内容已移除,策略注入、嵌入式 Hash 验签均已完成。然后关于resource limits我想higress作为网关会不会需要在网关侧实现统一限流和保护,这样可以避免后端资源滥用,在 behaviorCertificates 中添加计数和检查逻辑就好。还是说目前初版就已经够用了,等到后续再进行设计? @johnlanni The current gateway tag injection, nonce and other contents have been removed, and policy injection and embedded Hash signature verification have been completed. Then regarding resource limits, I wonder if higress, as a gateway, needs to implement unified current limiting and protection on the gateway side. This can avoid back-end resource abuse. Just add counting and checking logic in behaviorCertificates. Or is it that the first version is enough for now and the design will be done later? |



Ⅰ. Describe what this PR did
This PR implements the OWASP A2AS Framework as a standalone WASM plugin (
ai-a2as) to provide defense-in-depth protection against prompt injection attacks in AI/LLM applications.BASIC Security Model (5 Components):
<a2as:user>,<a2as:tool>)Key Features:
X-Mse-ConsumerheaderⅡ. Does this pull request fix one issue?
#3020
Reference: https://owasp.org/www-project-a2as/
Ⅲ. Why don't you add test cases (unit test/integration test)?
Test coverage is included:
main_test.go(100% pass)go test -v .(0.045s)Ⅳ. Describe how to verify it
Build and Test
Basic Configuration
Verify Metrics
Check Prometheus endpoint for:
a2as_requests_total,a2as_signature_verification_failed,a2as_tool_call_denied, etc.Ⅴ. Special notes for reviews
Architecture:
AUTHNat priority 200 (runs after auth, before ai-proxy)Review Focus:
@Phase,@Priority) correctnessReferences:
Files Changed:
plugins/wasm-go/extensions/ai-a2as/config.go(434L),main.go(396L),rfc9421.go(334L),main_test.go(553L)Makefile,VERSION(1.1.0),go.mod,go.sumREADME.md,README_EN.md