fix: sanitize password and cookie key

This commit is contained in:
Joe Previte 2021-06-07 14:46:59 -07:00
parent deaa2242ca
commit 3b50bfc17d
No known key found for this signature in database
GPG Key ID: 2C91590C6B742C24
6 changed files with 30 additions and 6 deletions

View File

@ -3,7 +3,7 @@ set -euo pipefail
# This is due to an upstream issue with RHEL7/CentOS 7 comptability with node-argon2 # This is due to an upstream issue with RHEL7/CentOS 7 comptability with node-argon2
# See: https://github.com/cdr/code-server/pull/3422#pullrequestreview-677765057 # See: https://github.com/cdr/code-server/pull/3422#pullrequestreview-677765057
npm_config_build_from_source=true export npm_config_build_from_source=true
main() { main() {
cd "$(dirname "${0}")/../.." cd "$(dirname "${0}")/../.."

View File

@ -20,7 +20,7 @@ detect_arch() {
ARCH="${NPM_CONFIG_ARCH:-$(detect_arch)}" ARCH="${NPM_CONFIG_ARCH:-$(detect_arch)}"
# This is due to an upstream issue with RHEL7/CentOS 7 comptability with node-argon2 # This is due to an upstream issue with RHEL7/CentOS 7 comptability with node-argon2
# See: https://github.com/cdr/code-server/pull/3422#pullrequestreview-677765057 # See: https://github.com/cdr/code-server/pull/3422#pullrequestreview-677765057
npm_config_build_from_source=true export npm_config_build_from_source=true
main() { main() {
# Grabs the major version of node from $npm_config_user_agent which looks like # Grabs the major version of node from $npm_config_user_agent which looks like

View File

@ -7,7 +7,7 @@ import { normalize, Options } from "../common/util"
import { AuthType, DefaultedArgs } from "./cli" import { AuthType, DefaultedArgs } from "./cli"
import { commit, rootPath } from "./constants" import { commit, rootPath } from "./constants"
import { Heart } from "./heart" import { Heart } from "./heart"
import { getPasswordMethod, IsCookieValidArgs, isCookieValid } from "./util" import { getPasswordMethod, IsCookieValidArgs, isCookieValid, sanitizeString } from "./util"
declare global { declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace // eslint-disable-next-line @typescript-eslint/no-namespace
@ -72,7 +72,7 @@ export const authenticated = async (req: express.Request): Promise<boolean> => {
const passwordMethod = getPasswordMethod(hashedPasswordFromArgs) const passwordMethod = getPasswordMethod(hashedPasswordFromArgs)
const isCookieValidArgs: IsCookieValidArgs = { const isCookieValidArgs: IsCookieValidArgs = {
passwordMethod, passwordMethod,
cookieKey: req.cookies.key as string, cookieKey: sanitizeString(req.cookies.key),
passwordFromArgs: req.args.password || "", passwordFromArgs: req.args.password || "",
hashedPasswordFromArgs: req.args["hashed-password"], hashedPasswordFromArgs: req.args["hashed-password"],
} }

View File

@ -4,7 +4,7 @@ import { RateLimiter as Limiter } from "limiter"
import * as path from "path" import * as path from "path"
import { rootPath } from "../constants" import { rootPath } from "../constants"
import { authenticated, getCookieDomain, redirect, replaceTemplates } from "../http" import { authenticated, getCookieDomain, redirect, replaceTemplates } from "../http"
import { getPasswordMethod, handlePasswordValidation, humanPath } from "../util" import { getPasswordMethod, handlePasswordValidation, humanPath, sanitizeString } from "../util"
export enum Cookie { export enum Cookie {
Key = "key", Key = "key",
@ -61,7 +61,7 @@ router.get("/", async (req, res) => {
}) })
router.post("/", async (req, res) => { router.post("/", async (req, res) => {
const password = req.body.password const password = sanitizeString(req.body.password)
const hashedPasswordFromArgs = req.args["hashed-password"] const hashedPasswordFromArgs = req.args["hashed-password"]
try { try {

View File

@ -274,6 +274,17 @@ export async function isCookieValid(isCookieValidArgs: IsCookieValidArgs): Promi
return isValid return isValid
} }
/** Ensures that the input is sanitized by checking
* - it's a string
* - greater than 0 characters
* - trims whitespace
*/
export function sanitizeString(str: string): string {
// Very basic sanitization of string
// Credit: https://stackoverflow.com/a/46719000/3015595
return typeof str === "string" && str.trim().length > 0 ? str.trim() : ""
}
const mimeTypes: { [key: string]: string } = { const mimeTypes: { [key: string]: string } = {
".aac": "audio/x-aac", ".aac": "audio/x-aac",
".avi": "video/x-msvideo", ".avi": "video/x-msvideo",

View File

@ -7,6 +7,7 @@ import {
hashLegacy, hashLegacy,
isHashLegacyMatch, isHashLegacyMatch,
isCookieValid, isCookieValid,
sanitizeString,
} from "../../../src/node/util" } from "../../../src/node/util"
describe("getEnvPaths", () => { describe("getEnvPaths", () => {
@ -382,3 +383,15 @@ describe.only("isCookieValid", () => {
expect(isValid).toBe(false) expect(isValid).toBe(false)
}) })
}) })
describe.only("sanitizeString", () => {
it("should return an empty string if passed a type other than a string", () => {
expect(sanitizeString({} as string)).toBe("")
})
it("should trim whitespace", () => {
expect(sanitizeString(" hello ")).toBe("hello")
})
it("should always return an empty string", () => {
expect(sanitizeString(" ")).toBe("")
})
})