如何在巴西绕过 Chrome Web Store Payments 收费?
结论
可以不使用 Chrome Web Store Payments,改用独立的支付和授权系统,但仍须遵守商店规则。
可以采用以下方案:
- 在 Chrome Web Store 免费发布应用或扩展。
- 通过第三方支付服务收款。
- 要求用户登录账号。
- 在自己的服务器上保存试用期、付款状态和授权信息。
- 应用启动或用户使用高级功能时,向服务器查询授权状态。
这套架构适用于免费增值、30 天试用和一次性买断。Chrome Web Store Payments 已不适合用作新项目的收费基础,传统 Chrome Apps 也在逐步退出支持。对于新项目,通常应优先考虑 Chrome 扩展、PWA 或普通 Web 应用。
推荐的实现方式
不要只把”已付费”状态保存在 localStorage、Cookie 或扩展配置中。这些数据可能被用户清除或修改,也无法在多台设备之间同步授权。
更可靠的结构是:
Chrome 扩展或 Web 应用
│
├── 用户登录
│
├── 跳转到第三方支付页面
│
└── 调用授权查询接口
│
▼
自有服务器
├── 用户账户
├── 试用开始时间
├── 支付订单
├── 授权状态
└── 支付平台 Webhook
▲
│
第三方支付服务
支付平台处理银行卡、当地支付方式、退款和支付结果,服务器则判断用户能否使用完整功能。
选择支付平台时,需要确认该服务当前是否支持巴西商户,同时考虑目标用户所在国家、结算币种和税务要求。相关条件可能变化,接入前应查看服务商最新的商户支持范围。
免费版与付费解锁
可以为每个用户保存一条授权记录。最简单的数据模型如下:
{
"userId": "user_123",
"plan": "lifetime",
"status": "active",
"trialStartedAt": "2026-09-01T00:00:00Z",
"trialEndsAt": "2026-10-01T00:00:00Z",
"purchasedAt": "2026-09-15T12:30:00Z"
}
服务端根据这条记录返回用户当前可用的功能:
{
"authenticated": true,
"license": {
"status": "active",
"plan": "lifetime"
},
"features": [
"basic",
"export",
"cloudSync"
]
}
客户端负责展示结果,最终的授权判断应尽量由服务器完成。
30 天试用的服务端判断
下面是一个简化的 Node.js 示例。实际项目应从数据库读取用户信息,而非使用内存对象。
const TRIAL_DURATION_MS = 30 * 24 * 60 * 60 * 1000;
function getEntitlement(user) {
if (user.licenseStatus === "active") {
return {
access: "full",
reason: "paid"
};
}
const trialStartedAt = new Date(user.trialStartedAt).getTime();
const trialEndsAt = trialStartedAt + TRIAL_DURATION_MS;
const now = Date.now();
if (now < trialEndsAt) {
return {
access: "full",
reason: "trial",
trialEndsAt: new Date(trialEndsAt).toISOString()
};
}
return {
access: "limited",
reason: "trial_expired"
};
}
不要根据客户端时间判断试用期,否则用户修改系统时间后可能延长试用。试用开始时间和当前时间都应以服务器记录为准。
授权查询接口
可以使用 Express 提供一个简单的授权接口:
import express from "express";
const app = express();
app.get("/api/entitlement", requireAuthentication, async (req, res) => {
const user = await database.users.findById(req.user.id);
if (!user) {
return res.status(404).json({
error: "USER_NOT_FOUND"
});
}
const entitlement = getEntitlement(user);
res.json({
authenticated: true,
entitlement
});
});
其中,requireAuthentication 和 database 需要由项目自行实现。身份认证可以使用安全的会话 Cookie、OAuth 或短期访问令牌。
客户端可以这样查询授权:
async function loadEntitlement() {
const response = await fetch("https://example.com/api/entitlement", {
method: "GET",
credentials: "include"
});
if (!response.ok) {
throw new Error(`Entitlement request failed: ${response.status}`);
}
return response.json();
}
const result = await loadEntitlement();
if (result.entitlement.access === "full") {
enablePremiumFeatures();
} else {
enableLimitedFeatures();
}
如果请求来自 Chrome 扩展,还需要在 manifest.json 中声明服务器域名权限:
{
"manifest_version": 3,
"name": "Example Extension",
"version": "1.0.0",
"host_permissions": [
"https://example.com/*"
]
}
支付成功后的授权激活
用户从支付页面跳转到”支付成功”页面,并不能作为激活授权的依据。跳转地址可以伪造,浏览器端参数也可以修改。
应当接收支付平台发出的 Webhook,并验证它的签名:
app.post(
"/webhooks/payment",
express.raw({ type: "application/json" }),
async (req, res) => {
let event;
try {
event = verifyWebhookSignature(
req.body,
req.headers,
process.env.PAYMENT_WEBHOOK_SECRET
);
} catch {
return res.status(400).send("Invalid webhook signature");
}
if (event.type === "payment.completed") {
const orderId = event.data.orderId;
const userId = event.data.metadata.userId;
await database.transaction(async (transaction) => {
const alreadyProcessed =
await transaction.webhookEvents.exists(event.id);
if (alreadyProcessed) {
return;
}
await transaction.licenses.activate({
userId,
plan: "lifetime",
orderId
});
await transaction.webhookEvents.insert({
eventId: event.id
});
});
}
res.sendStatus(200);
}
);
verifyWebhookSignature、事件名称和字段结构必须根据所选支付平台的官方 SDK 实现。示例中的名称仅用于说明架构,不对应任何支付平台的真实 API。
支付服务可能重复发送同一个事件,因此 Webhook 处理还必须具备幂等性。
一次性买断的设计
一次性付款的许可证可以保存为:
{
"plan": "lifetime",
"status": "active"
}
销售页面需要明确说明”永久使用”的具体含义,例如:
- 用户是永久使用已购买版本,还是也能使用以后发布的所有版本?
- 是否包含云存储、同步等会持续产生服务器成本的功能?
- 退款或拒付后如何处理许可证?
- 产品停止运营后,依赖服务器验证的功能是否还能使用?
如果高级功能完全在本地运行,可以让服务器签发带数字签名的许可证,使用户在短期离线时仍可使用。用于生成许可证的私钥不能嵌入扩展。
Chrome 扩展中的限制
扩展代码会分发到用户设备,用户理论上可以检查并修改客户端逻辑。因此,只在客户端限制功能最多能增加破解难度,无法提供绝对保护。
安全边界可以按以下方式划分:
- 导出额度、云端计算、同步和受保护数据应由服务器强制检查。
- 客户端只控制界面显示,不能作为可靠的授权依据。
- 不要把支付密钥、数据库凭据或许可证签名私钥写入扩展。
- 不要通过服务器下载并执行远程 JavaScript 来解锁功能。扩展代码必须遵守 Chrome Web Store 关于远程托管代码的政策。
- 缓存授权时应设置合理的有效期,缓存过期后重新查询服务器。
发布前需要检查的事项
使用外部收费不等于可以忽略 Chrome Web Store 的政策。提交前应检查当时有效的开发者计划政策,特别是支付披露、用户数据、隐私政策、远程代码和误导性行为等要求。
还需要处理以下事项:
- 清楚展示价格、试用期限和退款规则。
- 说明免费功能和付费功能的范围。
- 提供恢复购买或重新绑定账号的机制。
- 验证 Webhook 签名,所有通信都使用 HTTPS。
- 为登录和授权接口设置限流及会话保护。
- 根据实际经营方式,处理巴西及用户所在地的税务、发票和消费者保护要求。
- 如果支付平台不直接承担相关义务,应咨询当地会计或法律专业人士。
更稳妥的落地方案是”商店免费分发 + 第三方支付 + 自有账户与服务端授权”。这种方式可以同时支持受限免费版、30 天试用和一次性买断,也不依赖开发者所在国家是否受到 Chrome Web Store Payments 支持。
备注:内容仅供参考。
