mirror of
https://github.com/whyour/qinglong.git
synced 2026-03-29 19:11:02 +08:00
Merge branch 'develop' into copilot/fix-security-vulnerability
This commit is contained in:
commit
974865ad9a
|
|
@ -13,9 +13,29 @@ import { isValidToken } from '../shared/auth';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|
||||||
export default ({ app }: { app: Application }) => {
|
export default ({ app }: { app: Application }) => {
|
||||||
|
// Security: Enable strict routing to prevent case-insensitive path bypass
|
||||||
|
app.set('case sensitive routing', true);
|
||||||
|
app.set('strict routing', true);
|
||||||
app.set('trust proxy', 'loopback');
|
app.set('trust proxy', 'loopback');
|
||||||
app.use(cors());
|
app.use(cors());
|
||||||
|
|
||||||
|
// Security: Path normalization middleware to prevent case variation attacks
|
||||||
|
app.use((req, res, next) => {
|
||||||
|
const originalPath = req.path;
|
||||||
|
const normalizedPath = originalPath.toLowerCase();
|
||||||
|
|
||||||
|
// Block requests with case variations on protected paths
|
||||||
|
if (originalPath !== normalizedPath &&
|
||||||
|
(normalizedPath.startsWith('/api/') || normalizedPath.startsWith('/open/'))) {
|
||||||
|
return res.status(400).json({
|
||||||
|
code: 400,
|
||||||
|
message: 'Invalid path format'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
// Rewrite URLs to strip baseUrl prefix if configured
|
// Rewrite URLs to strip baseUrl prefix if configured
|
||||||
// This allows the rest of the app to work without baseUrl awareness
|
// This allows the rest of the app to work without baseUrl awareness
|
||||||
if (config.baseUrl) {
|
if (config.baseUrl) {
|
||||||
|
|
@ -36,7 +56,7 @@ export default ({ app }: { app: Application }) => {
|
||||||
secret: config.jwt.secret,
|
secret: config.jwt.secret,
|
||||||
algorithms: ['HS384'],
|
algorithms: ['HS384'],
|
||||||
}).unless({
|
}).unless({
|
||||||
path: [...config.apiWhiteList, /^\/(?!api\/).*/],
|
path: [...config.apiWhiteList, /^(\/(?!api\/).*)$/i],
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -51,19 +71,20 @@ 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))) {
|
const pathLower = req.path.toLowerCase();
|
||||||
|
if (!['/open/', '/api/'].some((x) => pathLower.startsWith(x))) {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
const headerToken = getToken(req);
|
const headerToken = getToken(req);
|
||||||
if (req.path.startsWith('/open/')) {
|
if (pathLower.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]+)\/*/);
|
const keyMatch = pathLower.match(/\/open\/([a-z]+)\/*/);
|
||||||
const key = keyMatch && keyMatch[1];
|
const key = keyMatch && keyMatch[1];
|
||||||
if (
|
if (
|
||||||
doc.scopes.includes(key as any) &&
|
doc.scopes.includes(key as any) &&
|
||||||
|
|
@ -98,6 +119,7 @@ export default ({ app }: { app: Application }) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
app.use(async (req, res, next) => {
|
app.use(async (req, res, next) => {
|
||||||
|
const pathLower = req.path.toLowerCase();
|
||||||
if (
|
if (
|
||||||
![
|
![
|
||||||
'/api/user/init',
|
'/api/user/init',
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user