Files
digital-me-history/digital-me-backend/test/store-idor.test.js
T
admin 0593ff7e62
nginx serve /uploads direct (audio speed) / patch-nginx (push) Failing after 1m34s
数字我 Digital Me:全量入库(大文件走 Git LFS)
2026-10-10 16:24:43 +08:00

63 lines
2.7 KiB
JavaScript

// 回归测试 #3:订单查询 IDOR。GET /store/order/:id 只有携带正确的一次性 pollSecret
// 才下发 redeemToken —— 枚举订单 id 偷不到他人登录令牌。
// 需要本地 MongoDB;连不上则整组 skip(不阻塞无 DB 的 CI)。
process.env.NODE_ENV = 'test'; // 非生产 → stub checkout 会立即开通,便于构造已支付订单
process.env.MONGO_DB = process.env.MONGO_DB_TEST || 'digital_me_test';
import { test, before, after } from 'node:test';
import assert from 'node:assert/strict';
import express from 'express';
import http from 'node:http';
let server, base, db, closeDb, mongoUp = true;
before(async () => {
const dbm = await import('../src/db.js');
closeDb = dbm.closeDb;
try { db = await dbm.connectDb(); }
catch { mongoUp = false; return; }
const { storeRouter } = await import('../src/routes/store.js');
const app = express();
app.use(express.json());
app.use('/api/store', storeRouter);
server = http.createServer(app).listen(0);
await new Promise((ok) => server.once('listening', ok));
base = `http://127.0.0.1:${server.address().port}`;
});
after(async () => {
if (server) server.close();
if (mongoUp && closeDb) await closeDb();
});
const j = async (p, opts) => (await fetch(base + p, opts)).json();
test('order IDOR:无/错 secret 不下发 redeemToken,正确 secret 才下发', async (t) => {
if (!mongoUp) return t.skip('无本地 MongoDB,跳过 DB 集成测试');
const prods = await j('/api/store/products');
const sku = (prods.products.find((p) => p.available) || {}).id;
if (!sku) return t.skip('无可售商品');
const co = await j('/api/store/checkout', {
method: 'POST', headers: { 'content-type': 'application/json' },
body: JSON.stringify({ sku, email: `buyer_${Date.now()}@example.com` }),
});
assert.ok(co.orderId, 'checkout 应返回 orderId');
// 攻击者视角:只有订单 id
const noSecret = await j(`/api/store/order/${co.orderId}`);
assert.equal(noSecret.status, 'paid');
assert.equal(noSecret.redeemToken, '', 'IDOR:无 secret 不应下发 redeemToken');
const wrong = await j(`/api/store/order/${co.orderId}?secret=not-the-secret`);
assert.equal(wrong.redeemToken, '', '错误 secret 也不应下发');
// 本人视角:拿到正确 pollSecret(stub 响应里不含,从 DB 取真实值)
const { ObjectId } = await import('mongodb');
const order = await db.collection('store_orders').findOne({ _id: new ObjectId(co.orderId) });
const ok = await j(`/api/store/order/${co.orderId}?secret=${order.pollSecret}`);
assert.ok(ok.redeemToken && ok.redeemToken.length > 0, '正确 secret 应下发 redeemToken');
await db.collection('store_orders').deleteOne({ _id: new ObjectId(co.orderId) });
});