> ## Documentation Index
> Fetch the complete documentation index at: https://waffo.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Portal 自助安全配置

> 如何在商户 Portal 中管理 API 安全设置：通过挑战字符串验证提交与轮换公钥、配置退款和拒付通知 URL，以及用 IP 白名单限制 API 访问。

本页介绍您可以在**商户 Portal → Integration** 自行管理的安全设置。请求签名机制见[认证与签名 FAQ](/docs/zh/support/auth-signature-faq)。

## 我能在商户 Portal 里自己添加或轮换公钥吗？

可以。生产环境公钥通过 Integration 页面在线提交。每次提交都会注册一条**新的**密钥记录并配有自己的 API key——不是就地编辑现有密钥。提交会经过 Waffo 审核：

| 状态 | 含义 |
| - | - |
| Pending | 已提交，等待 Waffo 审核 |
| Active | 已通过——用于验证您的请求签名 |
| Rejected | 未通过——您可以修正后重新提交 |

密钥激活或被拒绝时您会收到邮件（拒绝邮件包含原因）。要轮换密钥，请提交新公钥，等待其变为 Active，然后把您的集成切换到新的 API key。

## 为什么提交公钥需要对一个挑战字符串签名？

为了证明您确实持有与所上传公钥配对的私钥。Portal 会显示一个固定的挑战字符串，格式为 `WAFFO_VERIFY_{mid}`；请用您的私钥在本地对其签名，并把签名与公钥一起提交。Waffo 在接受公钥前会用所提交的公钥验证该签名。

| 项目 | 要求 |
| - | - |
| 密钥类型 | RSA 2048 位，X.509 格式，Base64 编码 |
| 签名算法 | SHA256withRSA（RSASSA-PKCS1-v1\_5） |
| 签名编码 | Base64 |

同一个公钥不能为同一商户提交两次。

## 我可以有多少个 API key 和公钥？

每个 API key 恰好对应**一个**公钥。一个商户可以持有多个 API key，按 API 操作类型划分范围：

| 操作类型 | 范围 |
| - | - |
| `PAYIN_ONLY` | 支付、退款和查询 API |
| `PAY_OUT_ONLY` | Payout 和转账 API |
| `PAYIN_AND_PAYOUT` | 所有 Payin 和 Payout API |
| `WITHDRAW` | 提现 API |

每种操作类型下可持有的公钥数量有上限；这个上限足够宽裕，可以在轮换期间让新旧密钥并行有效，达到上限时 Portal 会提示您。计数包含已被拒绝的提交，因此接近上限时请清理废弃的尝试。

## 退款和拒付通知 URL 在哪里配置？

同样在**商户 Portal → Integration**。与公钥不同，通知 URL 变更**无需审核**——URL 通过校验后立即生效。校验规则：URL 必须以 `http://` 或 `https://` 开头，符合 RFC 3986（不含空格或非 ASCII 字符），且不超过 512 个字符。清空字段并保存即删除该配置。

## 我能为不同 API key 设置不同的通知 URL 吗？

不能。每个 MID 有一个全局的 Refund Notify URL 和一个全局的 Chargeback Notify URL——它们不是按 API 操作类型存储的。Chargeback Notify URL 仅适用于卡收单。提现通知不使用这些设置：提现通知 URL 在 API 请求中按订单传入。

## 怎么把 API 访问限制到我服务器的 IP 地址？

在 Portal 中启用 **IP 白名单**——这是一项可选的安全措施，默认关闭。启用后，签名有效但来源 IP 不在白名单中的请求会被拒绝并返回错误 `A0046`（"Access denied: the request IP is not in the whitelist"，HTTP 401）。配置变更在您保存后很快生效——保存同时会使缓存的查询失效，因此实际上通常是立即生效。从未启用它的商户不会看到任何行为变化。

白名单在签名验证**之后**评估，因此签名错误的请求会以签名错误（`A0002`）而非 `A0046` 失败，即便其 IP 也不在名单上。

## IP 白名单支持哪些格式和限制？

* 条目接受 **IPv4 地址**和 **CIDR 段**（例如 `203.0.113.7` 或 `198.51.100.0/24`）。目前不支持 IPv6。
* 每个商户最多 **20 条**；重复条目会被拒绝。
* 每条可带标签，并可单独启用或停用。
* 没有任何已启用条目时白名单无法打开，删除或停用最后一条已启用条目会自动关闭总开关。

## 如果 Waffo 无法判断我请求的来源 IP 会怎样？

默认情况下，无法判断来源 IP 的请求会被**放行**并记录日志——只有能够判断且不在白名单中的 IP 才会被拦截。

Waffo 支持比这个默认更严格和更宽松的执行策略，但 Portal 只暴露总开关；策略本身在 Waffo 侧设置。如果您想先以仅观察模式运行，或者需要在无法判断来源 IP 时也拦截请求，请联系集成支持。

## 登录时的两步验证挑战是怎么工作的？

两步验证是一项**登录**控制，而不是 Integration 设置——账户侧的问题（谁能开启、验证码一直收不到怎么办）见[商户 Portal 操作](/docs/zh/support/portal-operations-faq)。机制上它是在登录调用*过程中*校验的，而不是登录之后：

1. 您照常提交登录表单。如果账户有已确认的两步验证方式，则不会签发会话：登录返回**需要挑战**的响应，同时验证码已发往账户的登录邮箱。
2. Portal 打开*Verification* 对话框，附带一个与本次登录尝试绑定的短期重发令牌。
3. 您输入验证码，Portal 重复**同一次登录**，这次带上验证码。只有此时才会签发会话。

只对账户的**默认**方式发起挑战。验证码错误或过期会导致登录本身失败，这就是为什么对话框让您重新输入验证码而不是密码。

## 为什么登录页开着不动一会儿，Resend 就不管用了？

此时您没有会话，所以 Resend 无法由会话授权。它由挑战时下发的重发令牌授权。该令牌属于单次登录尝试，一段时间后过期；刷新页面或开始新的尝试会丢弃它。如果 Resend 失败，请重新登录——这会签发新的挑战和新的令牌。

## 两步验证的每个控件实际做什么？

以下都是使用您的 **Portal 会话**执行的 Portal 操作——它们不属于 API key 签名的商户 API，无法用您的集成密钥编写脚本调用。

| 控件 | 作用 |
| - | - |
| **开启**（`Settings → Preference`） | 为邮箱方式打开一个绑定并发送首个验证码 |
| 绑定对话框内的 *Resend* | 为同一个绑定再发一个验证码 |
| 绑定对话框内的 *Verify* | 确认验证码并完成绑定 |
| **关闭** | 解绑该方式；要求输入您的账户密码 |
| 登录对话框内的 *Resend* | 使用重发令牌，为当前登录尝试再发一个验证码 |
| 操作人列表中的 `2-Step Verification` 列（Admin） | 为另一位操作人启用或停用邮箱方式 |

三点后果值得了解：

* \*\*只有验证码被验证后绑定才算生效。\*\*验证码发出后关闭对话框，会让该尝试停留在未确认状态，两步验证保持关闭；再次打开开关会开始新一轮。
* **您首个确认的方式成为默认**——而默认方式就是登录挑战使用的方式。
* **关闭由您的密码授权，而不是验证码**，密码以与登录表单密码相同的方式加密传输。密码错误会返回标准的密码错误，该方式保持绑定。


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.