diff --git a/std/http/cookie.ts b/std/http/cookie.ts index 75d70f74ec..f8025d3287 100644 --- a/std/http/cookie.ts +++ b/std/http/cookie.ts @@ -32,11 +32,14 @@ export interface Cookie { export type SameSite = "Strict" | "Lax" | "None"; +const FIELD_CONTENT_REGEXP = /^(?=[\x20-\x7E]*$)[^()@<>,;:\\"\[\]?={}\s]+$/; + function toString(cookie: Cookie): string { if (!cookie.name) { return ""; } const out: string[] = []; + validateCookieName(cookie.name); out.push(`${cookie.name}=${cookie.value}`); // Fallback for invalid Set-Cookie @@ -79,6 +82,17 @@ function toString(cookie: Cookie): string { return out.join("; "); } +/** + * Validate Cookie property. + * @param key Name of the cookie. + * @param value Value of the cookie. + */ +function validateCookieName(value: string | undefined | null): void { + if (value && !FIELD_CONTENT_REGEXP.test(value)) { + throw new TypeError(`Invalid cookie name: "${value}".`); + } +} + /** * Parse the cookies of the Server Request * @param req An object which has a `headers` property diff --git a/std/http/cookie_test.ts b/std/http/cookie_test.ts index 0f7c68635c..0f42a9381f 100644 --- a/std/http/cookie_test.ts +++ b/std/http/cookie_test.ts @@ -1,7 +1,7 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. import { Response, ServerRequest } from "./server.ts"; import { deleteCookie, getCookies, setCookie } from "./cookie.ts"; -import { assert, assertEquals } from "../testing/asserts.ts"; +import { assert, assertEquals, assertThrows } from "../testing/asserts.ts"; Deno.test({ name: "Cookie parser", @@ -31,6 +31,40 @@ Deno.test({ }, }); +Deno.test({ + name: "Cookie Name Validation", + fn(): void { + const res: Response = {}; + const tokens = [ + '"id"', + "id\t", + "i\td", + "i d", + "i;d", + "{id}", + "[id]", + '"', + "id\u0091", + ]; + res.headers = new Headers(); + tokens.forEach((name) => { + assertThrows( + (): void => { + setCookie(res, { + name, + value: "Cat", + httpOnly: true, + secure: true, + maxAge: 3, + }); + }, + Error, + 'Invalid cookie name: "' + name + '".', + ); + }); + }, +}); + Deno.test({ name: "Cookie Delete", fn(): void {