improved cookie security
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2022-01-08 22:10:02 +01:00
parent 8f047f2700
commit 3aaaf10fd9
6 changed files with 121 additions and 60 deletions

View File

@ -37,6 +37,10 @@ interface AccessResponse {
type AuthHandler =
(req: IncomingMessage, res: ServerResponse) => Promise<boolean>;
function build_cookie (name: string, value: string): string {
return `${name}=${value}; Secure; HttpOnly; SameSite=Strict`;
}
class AuthRequest {
public request: IncomingMessage;
public response: ServerResponse;
@ -87,7 +91,7 @@ class AuthRequest {
this.response.setHeader ('Content-Type', 'application/json');
}
// eslint-disable-next-line max-lines-per-function
// eslint-disable-next-line max-statements, max-lines-per-function
public async allow_access ({
access_token_expires_in,
include_refresh_token,
@ -116,7 +120,7 @@ class AuthRequest {
const cookies = [];
if (typeof this._cookie_name === 'string')
cookies.push (`${this._cookie_name}=${at.signature}`);
cookies.push (build_cookie (this._cookie_name, at.signature));
if (include_refresh_token) {
logger ('including refresh token');
@ -132,7 +136,8 @@ class AuthRequest {
result.refresh_token_id = rt.id;
if (typeof this._refresh_cookie_name === 'string')
cookies.push (`${this._refresh_cookie_name}=${rt.signature}`);
// eslint-disable-next-line max-len
cookies.push (build_cookie (this._refresh_cookie_name, rt.signature));
}
if (cookies.length > 0) {

View File

@ -6,10 +6,10 @@
*/
import { IncomingMessage, ServerResponse } from 'http';
import { run_regex } from '@sapphirecode/utilities';
import authority from './Authority';
import { AuthRequest, AccessSettings } from './AuthHandler';
import { debug } from './debug';
import { extract_cookie } from './cookie';
const logger = debug ('gateway');
@ -32,11 +32,6 @@ interface GatewayOptions {
refresh_settings?: RefreshSettings;
}
interface AuthCookies {
access_cookie: string | null;
refresh_cookie: string | null;
}
class GatewayClass {
private _options: GatewayOptions;
@ -81,37 +76,11 @@ class GatewayClass {
return auth.groups?.data;
}
public get_cookie_auth (req: IncomingMessage): AuthCookies {
logger ('extracting tokens from cookies');
const result: AuthCookies = {
access_cookie: null,
refresh_cookie: null
};
const cookie_regex = /(?:^|;)\s*(?<name>[^;=]+)=(?<value>[^;]+)/gu;
run_regex (
cookie_regex,
req.headers.cookie,
(res: RegExpMatchArray) => {
logger ('parsing cookie %s', res.groups?.name);
if (res.groups?.name === this._options.cookie_name)
result.access_cookie = res.groups?.value as string;
else if (res.groups?.name === this._options.refresh_cookie_name)
result.refresh_cookie = res.groups?.value as string;
}
);
logger ('parsed cookies: %O', result);
return result;
}
public try_access (req: IncomingMessage): boolean {
logger ('authenticating incoming request');
const cookies = this.get_cookie_auth (req);
let auth = this.get_header_auth (req);
if (auth === null)
auth = cookies.access_cookie;
auth = extract_cookie (this._options.cookie_name, req.headers.cookie);
if (auth === null) {
logger ('found no auth token');
return false;
@ -139,7 +108,10 @@ class GatewayClass {
logger ('trying to apply refresh token');
const refresh = this.get_cookie_auth (req).refresh_cookie;
const refresh = extract_cookie (
this._options.refresh_cookie_name,
req.headers.cookie
);
if (refresh === null) {
logger ('could not find refresh token');
return false;

35
lib/cookie.ts Normal file
View File

@ -0,0 +1,35 @@
import { run_regex } from '@sapphirecode/utilities';
import { debug } from './debug';
const logger = debug ('cookies');
function build_cookie (name: string, value: string): string {
return `${name}=${value}; Secure; HttpOnly; SameSite=Strict`;
}
function extract_cookie (
name: string|undefined,
header: string|undefined
): string| null {
logger (`extracting cookie ${name}`);
const cookie_regex = /(?:^|;)\s*(?<name>[^;=]+)=(?<value>[^;]+)/gu;
let result = null;
run_regex (
cookie_regex,
header,
(res: RegExpMatchArray) => {
logger ('parsing cookie %s', res.groups?.name);
if (res.groups?.name === name) {
logger ('found cookie');
result = res.groups?.value as string;
}
}
);
return result;
}
export { build_cookie, extract_cookie };