Files
nezha_domains/cmd/dashboard/controller/mcp_audit.go
T
naibaandcloudcode ab25662ddd feat(auth): add PAT auth, scoped REST/MCP access, CSRF, and tenant isolation
Introduce Personal Access Tokens (nzp_*) as a stateless auth path alongside
JWT, gated per-endpoint by a scope middleware (nezha:{resource}:{verb}) with
fail-closed empty-scope defaults and a server-id whitelist. Self-management
endpoints (profile, api-tokens, oauth2 bind, refresh-token) explicitly reject
PATs to block privilege-escalation chains. A revoke registry tears down active
long-lived connections (terminal, fm, ws, transfer, mcp) the moment a PAT is
deleted, with a tombstone closing the revoke->register race.

Add an MCP endpoint that proxies tool calls (exec, fs read/write/delete,
transfer) to agents over gRPC, guarded by origin/DNS-rebinding checks, a
per-token rate limiter, audit logging, and a kill switch. Serialize all
sends through the IOStream wrapper to honour grpc-go's concurrency contract.

Add CSRF double-submit protection on unsafe cookie-authenticated methods,
exempting authenticated PAT requests by context identity (not a forgeable
Authorization header). Apply visibility/whitelist filtering consistently
across list, get-by-id, and mutate paths to enforce tenant isolation.

Migrate legacy mcp:* scopes: rewrite read/exec to nezha:* equivalents and
drop dangerous write/delete/wildcard grants.

Co-authored-by: cloudcode <cloudcode@users.noreply.github.com>
2026-05-30 15:56:44 +00:00

49 lines
1.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package controller
import (
"crypto/sha256"
"encoding/hex"
"log"
"time"
"github.com/nezhahq/nezha/model"
"github.com/nezhahq/nezha/service/singleton"
)
// mcpAuditWrite 异步写一条 MCP 审计日志。失败仅 log,不阻塞业务。
//
// argsBytestool 的 raw JSON 参数(dispatcher 已经反序列化过)。
// 只记录 sha256 全文哈希,不保留任何明文片段:server.exec 的 env/stdin、
// fs.write 的 content 等字段会包含 token、密码、密钥、文件内容等敏感数据,
// 任何长度的 peek 都可能让审计表本身成为 secret 仓库;以哈希做关联即可。
//
// 测试可以把 mcpAuditSync 置为 true 让写入同步,避免 goroutine 与测试 teardown
// 形成竞态(不同测试 swap 全局 singleton.DB 时尤其明显)。
func mcpAuditWrite(entry model.MCPAuditLog, argsBytes []byte) {
if len(argsBytes) > 0 {
sum := sha256.Sum256(argsBytes)
entry.ArgsHash = hex.EncodeToString(sum[:])
}
entry.ArgsPeek = ""
if entry.CreatedAt.IsZero() {
entry.CreatedAt = time.Now()
}
db := singleton.DB
write := func(e model.MCPAuditLog) {
if db == nil {
return
}
if err := db.Create(&e).Error; err != nil {
log.Printf("NEZHA>> mcp audit write failed: %v", err)
}
}
if mcpAuditSync {
write(entry)
return
}
go write(entry)
}
// mcpAuditSync 仅供测试切换为同步写入,生产保持 false。
var mcpAuditSync = false