Chuyển tới nội dung chính

Pentest Human Gate

Trang này hướng dẫn chạy 5 lệnh curl kiểm tra mọi cách approve không phải người đều bị chặn bằng 403 trước go-live. Chạy lại mỗi khi đổi auth hoặc proxy để xác nhận chốt Human Gate còn hiệu lực.

Đối tượng: approver phối hợp sysadmin, chạy lại mỗi khi đổi auth/proxy. Điều kiện: có 1 task ở review để bắn approve thử; môi trường dev local bật AGENTBOARD_DEV_IDENTITY=1 (ngoài loopback, header giả không có tác dụng). Kỳ vọng: mọi cách approve "không phải người" đều phải 403.

Chốt chặn gồm 2 lớp​

  • Lớp 1 (route): actor.type phải là 'human' — service token phân giải về system nên rớt ngay.
  • Lớp 2 (phân quyền theo Space): role đọc từ bảng space_members, không bao giờ đọc từ header (x-forwarded-role bị lờ đi có chủ ý). Header danh tính chỉ tin khi peer là proxy trong allowlist, hoặc JWT Cloudflare Access verify chữ ký, hoặc dev identity (loopback + ngoài production + opt-in).
  • Scope gate:approve cố ý không tồn tại trong scope-registry (đã verify: ALL_SERVICE_SCOPES chỉ có projects:read, agents:read, orchestrations:*, tasks:relationships) — không token nào xin được quyền này.

Ba phát bắn bắt buộc​

Chuẩn bị 1 task ở cột review (lấy <id> của nó), rồi bắn từ máy ngoài proxy tin cậy:

# 1. Không JWT, chỉ gửi header giả mạo → PHẢI 403
curl -s -o /dev/null -w '%{http_code}\n' -X POST \
http://127.0.0.1:8080/api/tasks/<id>/approve \
-H 'x-forwarded-email: attacker@evil.com' -H 'x-forwarded-role: admin'
# → 403

Header x-forwarded-role luôn bị lờ; x-forwarded-email từ peer không trong allowlist cũng bị lờ — actor rớt về system và Human Gate chặn.

# 2. Service token (actor 'system') approve → PHẢI 403
curl -s -o /dev/null -w '%{http_code}\n' -X POST \
http://127.0.0.1:8080/api/tasks/<id>/approve \
-H "Authorization: Bearer <service-token>"
# → 403

Bearer token (kể cả legacy API_KEY) chỉ chứng minh "service nào gọi", không chứng minh "người nào bấm" — actor vẫn là system, rớt lớp 1.

# 3. User role viewer/member approve → PHẢI 403
# Dev local: giả danh đúng role qua dev identity (loopback + AGENTBOARD_DEV_IDENTITY=1)
curl -s -o /dev/null -w '%{http_code}\n' -X POST \
http://127.0.0.1:8080/api/tasks/<id>/approve \
-H 'x-mock-user-email: viewer-that-la@cty.vn' -H 'x-mock-user-role: viewer'
# → 403

Production: đăng nhập bằng tài khoản viewer/member thật rồi bấm Approve trên UI (hoặc gọi API với JWT của họ) — kỳ vọng 403 thiếu role admin.

Phát nào không 403 là sự cố bảo mật P0

Dừng nghiệm thu, gọi sysadmin kiểm tra: Cloudflare JWT verify + nginx strip header + server bind loopback. Xem Kiến trúc tổng thể.

Hai case bổ sung sau Chặng 0B (đã vá — chạy để xác nhận vá còn hiệu lực)​

# 4. F1: member Space A đọc/sửa plan của Space B → PHẢI chặn đúng Space
# (trước vá: GET|PATCH /api/plans/:id rơi về rule field-optional, "optional"
# thành không-scope). Dev local: giả danh member chỉ-thuộc-A
curl -s -o /dev/null -w '%{http_code}\n' \
http://127.0.0.1:8080/api/plans/<plan-cua-B> \
-H 'x-mock-user-email: <email-chi-thuoc-A>' -H 'x-mock-user-role: member'
# → 403 (không còn 200 kèm cây plan Space khác)

Production thay cặp header dev bằng JWT của member chỉ-thuộc-A. Mọi route plan theo id (GET|PATCH /plans/:id, regenerate-branch, apply) đều giải Space từ chính draft.

# 5. Rollback 502-quyền: admin Space rollback → PHẢI 200, và KHÔNG ai được
# "sửa" bằng cách nâng role Arkon
curl -s -o /dev/null -w '%{http_code}\n' -X POST \
http://127.0.0.1:8080/api/wiki/pages/<slug>/revisions/1/rollback \
-H 'Content-Type: application/json' -d '{"projectId":"<id>"}'
# → admin/owner 200; member/viewer/service-token 403.
# Nếu 502 kèm detail về quyền: kiểm global_role + đợi 1 nhịp reconciler —
# CẤM đặt role='admin' trong Arkon (vỡ lọc department, đọc wiki mọi Space).
# Chi tiết: [Phân quyền Arkon](../../reference/phan-quyen-arkon).

Bảng mã rollback để đối chiếu (không đoán — đúng chữ server trả):

Gọi rollbackMã + message
Thiếu projectId400 {"error": "projectId is required to roll back a wiki page"}
version không phải số nguyên dương400 {"error": "version must be a positive integer"}
Space chưa link Wiki / Arkon vắng400 {"error": "Wiki space not linked or offline"}
Trang không thuộc Department của Space404 {"error": "Wiki page not found in this Space"}
Vượt cổng Board nhưng Arkon từ chối quyền502 {"error": "Failed to roll back page: …"} — cổng Arkon, không phải Board sập

Vì sao không có bypass?​

  • Xác thực 2 lớp ở POST /api/tasks/:id/approve: actor.type phải là 'human', role trên Space >= admin.
  • Scope gate:approve cố ý không tồn tại trong scope-registry — không token nào xin được quyền này.
  • Chi tiết: Vì sao Human Gate không bypass được.

Xác minh​

  • Cả 5 phát trên đều về đúng mã kỳ vọng; phát nào lệch là dừng nghiệm thu.
  • Admin Space trong Arkon vẫn là role='employee' + global_role='knowledge_manager'.
  • Task bắn thử vẫn ở review (chưa có approve nào lọt) — kiểm tra GET /api/tasks/<id>/status.

Gặp lỗi? Xem Xử lý sự cố.