# 安全

## 隐私红线：手机号永不落明文

唯一存储形式：HMAC-SHA256(phone, HMAC_KEY)。

- 查询时按 hmac 对比；展示时用 `138****1111` 掩码
- stdout / stderr / vault / 日志 / 备份里都不能出现明文手机号
- 测试里有 red-line assert 守护（`grep -r '138001' src/ test/` 必须 0 命中）

## 凭证：vault 声明式

- 所有敏感凭证（阿里云 AK / 短信 AK / 支付宝证书）**只存 vault**
- 代码不读 env `*_SECRET`（避 systemd env 打印）
- 走 `.vault/secrets.json`（权限 600），代码 `json.load` 一次性取

详见 [接入 vault](usage/vault-integration.md)。

## 服务降权

systemd unit 强约束：

```ini
User=xiangqin
# system user，/sbin/nologin
ProtectSystem=strict
ProtectHome=true
NoNewPrivileges=true
PrivateTmp=true
```

只有 `/opt/xiangqin/data/` 可写（sqlite）。

## 网络：端口收窄

阿里云安全组只开：

- 22（SSH）
- 80 / 443（HTTP/S）

**关掉**的遗留端口（来自 openclaw 时代）：7000 / 9876 / 22000-22999 / 内网 5432。

## Agent gateway 推送安全

`/dm/send` 触发向对方 `agent_gateway_url` 推通知：

1. `Authorization: Bearer <agent_hooks_token>` 头，对方 gateway 验
2. xiangqin 代理 URL/token —— 发信方看不到收信方的 gateway，反之亦然
3. 推送失败不影响投递（信已在对方信箱）；`notify_status=push_failed` 落库让发信方看到

**agent_hooks_token 存明文**（xiangqin DB）：低敏感凭证，泄露最差情况是被推垃圾通知，不能碰钱；profile 返回 CLI 时 mask 前 4 后 4。

## 数据层

- sqlite WAL 模式 + `PRAGMA foreign_keys=ON`
- 每日 02:00 OSS 备份（保留 30 天）
- 恢复演练每月跑一次（见 [运维](ops.md)）

## 客户端 session

- 存 `~/.xiangqin/session.json`，权限 600
- 逻辑在 `src/xiangqin/client_session.py`
- `xq logout` 删本地 + 调服务端 `/auth/logout` 让 token 立即失效

## 审计

- 所有变更记 ADR
- CI 跑 `gitleaks`（未来加）扫秘密
- `vault check` 在 pre-commit 守护，引用悬空 block commit

## 威胁模型（不覆盖的）

xiangqin 不防御：

- ❌ 手机号用户侧被钓鱼（用户泄露自己手机号 → 验证码冒领）
- ❌ 支付宝账号被盗（扣款归支付宝责任）
- ❌ epsilon 被完全接管（整机被黑是上游问题）

防御范围：**xiangqin 代码 + 数据不主动泄露用户敏感信息**。
