shubhthorat/Phia
GitHub: shubhthorat/Phia
揭示生产环境中 5 个未认证 API 漏洞并提供修复方案的安全研究报告。
Stars: 0 | Forks: 0
# Phia API — 研究
**作者:** Shubh Thorat · **日期:** 2026年4月11日 · **目标:** `api.phia.com`
---
## 我发现了什么
**5 个端点在生产环境中无需身份验证即可接受请求。**
最关键的一个:`CreateMerchantUrl` 会生成关联到**任意**用户账户的联盟追踪链接,且无需令牌。我传入一个伪造的 UUID,却得到了一个实时的联盟 URL:
```
curl -X POST https://api.phia.com/v2/graphql \
-H "Content-Type: application/json" \
-H "x-platform: EXTENSION" \
-d '{
"operationName": "CreateMerchantUrl",
"variables": { "input": {
"phiaId": "00000000-0000-0000-0000-000000000000",
"url": "https://poshmark.com/listing/any-item",
"platform": "EXTENSION", "searchId": "test",
"productId": "ENTITY_TYPE_PRODUCT-abc123",
"secondhandRetailerId": "POSHMARK"
}},
"query": "mutation CreateMerchantUrl($input: CreateMerchantUrlInput!) { createMerchantUrl(input: $input) { id url } }"
}'
```
**响应 — `200 OK`,未进行身份验证检查:**
```
{
"data": {
"createMerchantUrl": {
"id": "1516e925-3864-43a1-ab2a-102a8ff0ebef",
"url": "https://www.anrdoezrs.net/click-101090659-15736479?url=..."
}
}
}
```
任何人都可以向任意用户的账户灌入联盟点击,污染其分析数据,并无限触发对 CJ 和 Impact.com 的调用——全程无需会话。
---
## 所有发现
| # | 端点 | 严重性 | 问题描述 |
| --- | ------------------------- | -------- | ---------------------------------------------------------------------------------------------- |
| 1 | `CreateMerchantUrl` | **严重** | 无身份验证,无 `phiaId` 归属检查 — 大规模的联盟欺诈 |
| 2 | `CreateResaleInsightsUrl` | 高 | 无身份验证 — `link` 参数原样反射到输出 URL |
| 3 | `GET /whitelist/validate` | 高 | `phiaId` 以 URL 查询参数形式暴露 — 泄露至服务器日志、浏览器历史记录、Referer 头部 |
| 4 | 分析令牌 | 中 | Mixpanel 令牌硬编码在公共的 `background.js` 中 — 任何人都可注入伪造事件 |
| 5 | GraphQL 自省 | 低 | `__schema` 返回 `500` 而非干净的禁用错误 |
---
## 负载测试
编写了一个 [Locust](https://locust.io) 脚本(`load_test.py`),并发地对全部 5 个未认证端点发起请求,针对生产环境。
| 端点 | 请求数 | 失败数 | 中位数 | p95 | p99 | 最大值 | 平均大小 |
| ------------------------- | :----: | :----: | --------: | --------: | ---------: | ------------: | --------: |
| `CreateMerchantUrl` | 19 | 0 | 210ms | 660ms | 660ms | 657ms | 314 B |
| `CreateResaleInsightsUrl` | 25 | 0 | 44ms | 58ms | 130ms | 127ms | 361 B |
| `GET /whitelist/validate` | 4 | 0 | 150ms | 180ms | 180ms | 177ms | 206 B |
| `GenerateEntityId` | 7 | 0 | 44ms | 49ms | 49ms | 49ms | 69 B |
| `SiteConfig` | 10 | 0 | 570ms | 1100ms | 1100ms | 1148ms | 63 B |
| **总计** | **65** | **0** | **130ms** | **590ms** | **1100ms** | **1148ms** | **260 B** |
**65 次请求,0 次失败。每次调用都返回了真实数据,无需身份验证。**
平均大小一栏证实了这些并非空错误。`CreateMerchantUrl` 每次调用返回 **314 字节的实时联盟数据**。`SiteConfig` 在少量流量下达到 **1148ms 最大值**——每次调用都会链式调用两个 gRPC 向下游。在真实负载下,这将是第一个瓶颈。
完整报告: [`Report/Locust.html`](Report/Locust.html)
---
## 如何修复
**1. 在 `CreateMerchantUrl` 上要求身份验证并检查归属**
```
@Authorized()
async createMerchantUrl(input, context) {
if (input.phiaId !== context.user.phiaId)
throw new ForbiddenError('phiaId mismatch');
}
```
**2. 将 `phiaId` 移出 URL 参数** — 使用 GraphQL 请求中已存在的 `x-phia-id` 头部。永远不要将永久用户标识符放在查询字符串中。
**3. 轮换并代理分析令牌** — `0707dbc4f9ae6bc96db7b740d1c4911a` 存在于公共扩展包中。轮换它,并在服务器端代理事件,使令牌永不触达客户端。
**4. 禁用生产环境中的自省**
```
new ApolloServer({ introspection: process.env.NODE_ENV !== "production" });
```
**5. 对未认证端点实施速率限制** — 每 IP 至少 30 请求/分钟。
---
## 方法论
未使用专有工具 — 仅依靠 DevTools、Python、curl 和 Locust。
```
Chrome DevTools → HAR export (597 entries captured)
Python → parsed every request, isolated unauthenticated endpoints
curl → manually confirmed each finding against production
Locust → load_test.py — concurrent load across all 5 endpoints
```
---
如需逐步讲解或对预发布环境进行更深入测试,我很乐意协助。
| 端点 | 请求数 | 失败数 | 中位数 | p95 | p99 | 最大值 | 平均大小 |
| ------------------------- | :----: | :----: | --------: | --------: | ---------: | ------------: | --------: |
| `CreateMerchantUrl` | 19 | 0 | 210ms | 660ms | 660ms | 657ms | 314 B |
| `CreateResaleInsightsUrl` | 25 | 0 | 44ms | 58ms | 130ms | 127ms | 361 B |
| `GET /whitelist/validate` | 4 | 0 | 150ms | 180ms | 180ms | 177ms | 206 B |
| `GenerateEntityId` | 7 | 0 | 44ms | 49ms | 49ms | 49ms | 69 B |
| `SiteConfig` | 10 | 0 | 570ms | 1100ms | 1100ms | 1148ms | 63 B |
| **总计** | **65** | **0** | **130ms** | **590ms** | **1100ms** | **1148ms** | **260 B** |
**65 次请求,0 次失败。每次调用都返回了真实数据,无需身份验证。**
平均大小一栏证实了这些并非空错误。`CreateMerchantUrl` 每次调用返回 **314 字节的实时联盟数据**。`SiteConfig` 在少量流量下达到 **1148ms 最大值**——每次调用都会链式调用两个 gRPC 向下游。在真实负载下,这将是第一个瓶颈。
完整报告: [`Report/Locust.html`](Report/Locust.html)
---
## 如何修复
**1. 在 `CreateMerchantUrl` 上要求身份验证并检查归属**
```
@Authorized()
async createMerchantUrl(input, context) {
if (input.phiaId !== context.user.phiaId)
throw new ForbiddenError('phiaId mismatch');
}
```
**2. 将 `phiaId` 移出 URL 参数** — 使用 GraphQL 请求中已存在的 `x-phia-id` 头部。永远不要将永久用户标识符放在查询字符串中。
**3. 轮换并代理分析令牌** — `0707dbc4f9ae6bc96db7b740d1c4911a` 存在于公共扩展包中。轮换它,并在服务器端代理事件,使令牌永不触达客户端。
**4. 禁用生产环境中的自省**
```
new ApolloServer({ introspection: process.env.NODE_ENV !== "production" });
```
**5. 对未认证端点实施速率限制** — 每 IP 至少 30 请求/分钟。
---
## 方法论
未使用专有工具 — 仅依靠 DevTools、Python、curl 和 Locust。
```
Chrome DevTools → HAR export (597 entries captured)
Python → parsed every request, isolated unauthenticated endpoints
curl → manually confirmed each finding against production
Locust → load_test.py — concurrent load across all 5 endpoints
```
---
如需逐步讲解或对预发布环境进行更深入测试,我很乐意协助。标签:API安全, ATT&CK T1190, CISA项目, CreateMerchantUrl, curl, GraphQL, HAR分析, JSONLines, JSON输出, Locust压力测试, 修复建议, 后端开发, 接口测试, 未认证访问, 漏洞披露, 生产环境, 负载测试, 逆向工具, 附属营销欺诈, 零信任