修复严重鉴权绕过漏洞

This commit is contained in:
yemur 2026-02-27 10:27:08 +08:00
parent d53437d169
commit 4a494739ae
2 changed files with 12 additions and 6 deletions

2
.gitignore vendored
View File

@ -28,3 +28,5 @@ __pycache__
/shell/preload/notify.* /shell/preload/notify.*
/shell/preload/*-notify.json /shell/preload/*-notify.json
/shell/preload/__ql_notify__.* /shell/preload/__ql_notify__.*
docs/
docs/*

View File

@ -36,7 +36,8 @@ export default ({ app }: { app: Application }) => {
secret: config.jwt.secret, secret: config.jwt.secret,
algorithms: ['HS384'], algorithms: ['HS384'],
}).unless({ }).unless({
path: [...config.apiWhiteList, /^\/(?!api\/).*/], // Use case-insensitive regex to prevent bypassing JWT via uppercase paths like /Api/
path: [...config.apiWhiteList, /^\/(?!api\/)/i],
}), }),
); );
@ -51,22 +52,25 @@ export default ({ app }: { app: Application }) => {
}); });
app.use(async (req: Request, res, next) => { app.use(async (req: Request, res, next) => {
if (!['/open/', '/api/'].some((x) => req.path.startsWith(x))) { // Normalize path to lowercase to prevent case-sensitivity bypass (e.g. /Open/, /API/)
const normalizedPath = req.path.toLowerCase();
if (!['/open/', '/api/'].some((x) => normalizedPath.startsWith(x))) {
return next(); return next();
} }
const headerToken = getToken(req); const headerToken = getToken(req);
if (req.path.startsWith('/open/')) { if (normalizedPath.startsWith('/open/')) {
const apps = await shareStore.getApps(); const apps = await shareStore.getApps();
const doc = apps?.filter((x) => const doc = apps?.filter((x) =>
x.tokens?.find((y) => y.value === headerToken), x.tokens?.find((y) => y.value === headerToken),
)?.[0]; )?.[0];
if (doc && doc.tokens && doc.tokens.length > 0) { if (doc && doc.tokens && doc.tokens.length > 0) {
const currentToken = doc.tokens.find((x) => x.value === headerToken); const currentToken = doc.tokens.find((x) => x.value === headerToken);
const keyMatch = req.path.match(/\/open\/([a-z]+)\/*/); // Use case-insensitive match and normalize key to prevent scope bypass via uppercase paths
const key = keyMatch && keyMatch[1]; const keyMatch = req.path.match(/\/open\/([a-zA-Z]+)\/*/);
const key = keyMatch && keyMatch[1]?.toLowerCase();
if ( if (
doc.scopes.includes(key as any) && key && doc.scopes.includes(key as any) &&
currentToken && currentToken &&
currentToken.expiration >= Math.round(Date.now() / 1000) currentToken.expiration >= Math.round(Date.now() / 1000)
) { ) {