fix(api): sanitize incoming user session id's

This commit is contained in:
Pujit Mehrotra
2025-01-10 13:24:09 -05:00
committed by Pujit Mehrotra
parent fe98295496
commit 3b2d61efc2
2 changed files with 17 additions and 9 deletions

View File

@@ -46,15 +46,17 @@ describe.concurrent('CookieService', () => {
it('handles session names robustly', ({ expect }) => { it('handles session names robustly', ({ expect }) => {
const session = (name?: unknown) => service.getSessionFilePath(name as string); const session = (name?: unknown) => service.getSessionFilePath(name as string);
expect(session('foo')).toEqual('/tmp/php/sessions/sess_foo'); expect(session('foo')).toEqual('/tmp/php/sessions/sess_foo');
expect(session('foo123')).toEqual('/tmp/php/sessions/sess_foo123');
expect(session('/foo123*&/^\n\r\'"!;:/../~`+=@#$%(?) \t/~/.profile')).toEqual('/tmp/php/sessions/sess_foo123profile');
expect(session('')).toEqual('/tmp/php/sessions/sess_'); expect(session('')).toEqual('/tmp/php/sessions/sess_');
expect(session(null)).toEqual('/tmp/php/sessions/sess_null'); expect(session(null)).toEqual('/tmp/php/sessions/sess_');
expect(session(undefined)).toEqual('/tmp/php/sessions/sess_undefined'); expect(session(undefined)).toEqual('/tmp/php/sessions/sess_');
expect(session(1)).toEqual('/tmp/php/sessions/sess_1'); expect(session(1)).toEqual('/tmp/php/sessions/sess_');
expect(session(1.0)).toEqual('/tmp/php/sessions/sess_1'); expect(session(1.0)).toEqual('/tmp/php/sessions/sess_');
expect(session(1.1)).toEqual('/tmp/php/sessions/sess_1.1'); expect(session(1.1)).toEqual('/tmp/php/sessions/sess_');
expect(session({})).toEqual('/tmp/php/sessions/sess_[object Object]'); expect(session({})).toEqual('/tmp/php/sessions/sess_');
expect(session(['foo', 'bar'])).toEqual('/tmp/php/sessions/sess_foo,bar'); expect(session(['foo', 'bar'])).toEqual('/tmp/php/sessions/sess_');
expect(session('foo/bar')).toEqual('/tmp/php/sessions/sess_foo/bar'); expect(session('foo/bar')).toEqual('/tmp/php/sessions/sess_foobar');
}); });
it('can read an existing session & reject a non-existent one', async ({ expect }) => { it('can read an existing session & reject a non-existent one', async ({ expect }) => {

View File

@@ -83,6 +83,12 @@ export class CookieService {
* @returns the full path to the session file on disk. * @returns the full path to the session file on disk.
*/ */
public getSessionFilePath(sessionId: string): string { public getSessionFilePath(sessionId: string): string {
return join(this.opts.sessionDir, `sess_${sessionId}`); if (typeof sessionId !== 'string') {
return join(this.opts.sessionDir, `sess_`);
}
// sanitize incoming session id to prevent e.g. directory traversal attacks
// only allow alpha-numeric characters
const sanitizedSessionId = sessionId.replace(/[^a-zA-Z0-9]/g, '');
return join(this.opts.sessionDir, `sess_${sanitizedSessionId}`);
} }
} }