mirror of
https://github.com/Unleash/unleash.git
synced 2025-04-24 01:18:01 +02:00
security: Reject multiple successive slashes in path (#3880)
This commit is contained in:
parent
ab11ce9886
commit
3d872cf7a2
@ -29,6 +29,7 @@ import maintenanceMiddleware from './middleware/maintenance-middleware';
|
|||||||
import { unless } from './middleware/unless-middleware';
|
import { unless } from './middleware/unless-middleware';
|
||||||
import { catchAllErrorHandler } from './middleware/catch-all-error-handler';
|
import { catchAllErrorHandler } from './middleware/catch-all-error-handler';
|
||||||
import NotFoundError from './error/notfound-error';
|
import NotFoundError from './error/notfound-error';
|
||||||
|
import { rejectDoubleSlashesInPath } from './middleware/reject-double-slashes-in-path';
|
||||||
|
|
||||||
export default async function getApp(
|
export default async function getApp(
|
||||||
config: IUnleashConfig,
|
config: IUnleashConfig,
|
||||||
@ -92,7 +93,7 @@ export default async function getApp(
|
|||||||
if (config.enableOAS && services.openApiService) {
|
if (config.enableOAS && services.openApiService) {
|
||||||
services.openApiService.useDocs(app);
|
services.openApiService.useDocs(app);
|
||||||
}
|
}
|
||||||
|
app.use(`${baseUriPath}/`, rejectDoubleSlashesInPath);
|
||||||
// Support CORS preflight requests for the frontend endpoints.
|
// Support CORS preflight requests for the frontend endpoints.
|
||||||
// Preflight requests should not have Authorization headers,
|
// Preflight requests should not have Authorization headers,
|
||||||
// so this must be handled before the API token middleware.
|
// so this must be handled before the API token middleware.
|
||||||
|
11
src/lib/middleware/reject-double-slashes-in-path.ts
Normal file
11
src/lib/middleware/reject-double-slashes-in-path.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { RequestHandler } from 'express';
|
||||||
|
|
||||||
|
const MULTIPLE_SLASHES = /\/\/+/;
|
||||||
|
|
||||||
|
export const rejectDoubleSlashesInPath: RequestHandler = (req, res, next) => {
|
||||||
|
if (req.path.match(MULTIPLE_SLASHES)) {
|
||||||
|
res.status(404).send();
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,59 @@
|
|||||||
|
import getLogger from '../../../fixtures/no-logger';
|
||||||
|
import dbInit, { ITestDb } from '../../helpers/database-init';
|
||||||
|
import { IUnleashTest, setupAppWithAuth } from '../../helpers/test-helper';
|
||||||
|
import { IAuthType, IUnleashStores } from '../../../../lib/types';
|
||||||
|
import { ApiTokenType } from '../../../../lib/types/models/api-token';
|
||||||
|
|
||||||
|
let app: IUnleashTest;
|
||||||
|
let appWithBaseUrl: IUnleashTest;
|
||||||
|
let stores: IUnleashStores;
|
||||||
|
let db: ITestDb;
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
db = await dbInit(
|
||||||
|
'multiple_leading_slashes_are_still_authed_serial',
|
||||||
|
getLogger,
|
||||||
|
);
|
||||||
|
stores = db.stores;
|
||||||
|
app = await setupAppWithAuth(stores, {
|
||||||
|
authentication: { enableApiToken: true, type: IAuthType.DEMO },
|
||||||
|
});
|
||||||
|
appWithBaseUrl = await setupAppWithAuth(stores, {
|
||||||
|
server: { baseUriPath: '/demo' },
|
||||||
|
authentication: { enableApiToken: true, type: IAuthType.DEMO },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
await app.destroy();
|
||||||
|
await db.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Access to /api/client/features are refused no matter how many leading slashes', async () => {
|
||||||
|
await app.request.get('/api/client/features').expect(401);
|
||||||
|
await app.request.get('/////api/client/features').expect(404);
|
||||||
|
await app.request.get('//api/client/features').expect(404);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Multiple slashes anywhere in the path is not a URL that exists', async () => {
|
||||||
|
await app.request.get('/api/admin///projects/default/features').expect(404);
|
||||||
|
await app.request.get('/api/client///features').expect(404);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('multiple slashes after base path is also rejected with 404', async () => {
|
||||||
|
await appWithBaseUrl.request.get('/demo///api/client/features').expect(404);
|
||||||
|
await appWithBaseUrl.request.get('/demo/api/client/features').expect(401);
|
||||||
|
});
|
||||||
|
|
||||||
|
test(`Access with API token is granted`, async () => {
|
||||||
|
let token = await app.services.apiTokenService.createApiTokenWithProjects({
|
||||||
|
environment: 'default',
|
||||||
|
projects: ['default'],
|
||||||
|
tokenName: 'test',
|
||||||
|
type: ApiTokenType.CLIENT,
|
||||||
|
});
|
||||||
|
await app.request
|
||||||
|
.get('/api/client/features')
|
||||||
|
.set('Authorization', token.secret)
|
||||||
|
.expect(200);
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user