fix potential open redirect
parent
3140039d5c
commit
eaa28441ac
4
app.js
4
app.js
|
|
@ -24,6 +24,7 @@ import { version } from "./version.js";
|
||||||
import * as databaseInitializer from "./helpers/initializer.database.js";
|
import * as databaseInitializer from "./helpers/initializer.database.js";
|
||||||
import debug from "debug";
|
import debug from "debug";
|
||||||
import { apiGetHandler } from "./handlers/permissions.js";
|
import { apiGetHandler } from "./handlers/permissions.js";
|
||||||
|
import { getSafeRedirectURL } from "./helpers/functions.authentication.js";
|
||||||
const debugApp = debug("lot-occupancy-system:app");
|
const debugApp = debug("lot-occupancy-system:app");
|
||||||
databaseInitializer.initializeDatabase();
|
databaseInitializer.initializeDatabase();
|
||||||
const __dirname = ".";
|
const __dirname = ".";
|
||||||
|
|
@ -91,7 +92,8 @@ const sessionChecker = (request, response, next) => {
|
||||||
if (request.session.user && request.cookies[sessionCookieName]) {
|
if (request.session.user && request.cookies[sessionCookieName]) {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
return response.redirect(`${urlPrefix}/login?redirect=${request.originalUrl}`);
|
const redirectUrl = getSafeRedirectURL(request.originalUrl);
|
||||||
|
return response.redirect(`${urlPrefix}/login?redirect=${redirectUrl}`);
|
||||||
};
|
};
|
||||||
app.use((request, response, next) => {
|
app.use((request, response, next) => {
|
||||||
response.locals.buildNumber = version;
|
response.locals.buildNumber = version;
|
||||||
|
|
|
||||||
5
app.ts
5
app.ts
|
|
@ -31,6 +31,7 @@ import * as databaseInitializer from "./helpers/initializer.database.js";
|
||||||
|
|
||||||
import debug from "debug";
|
import debug from "debug";
|
||||||
import { apiGetHandler } from "./handlers/permissions.js";
|
import { apiGetHandler } from "./handlers/permissions.js";
|
||||||
|
import { getSafeRedirectURL } from "./helpers/functions.authentication.js";
|
||||||
const debugApp = debug("lot-occupancy-system:app");
|
const debugApp = debug("lot-occupancy-system:app");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -177,8 +178,10 @@ const sessionChecker = (
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const redirectUrl = getSafeRedirectURL(request.originalUrl);
|
||||||
|
|
||||||
return response.redirect(
|
return response.redirect(
|
||||||
`${urlPrefix}/login?redirect=${request.originalUrl}`
|
`${urlPrefix}/login?redirect=${redirectUrl}`
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
export declare const authenticate: (userName: string, password: string) => Promise<boolean>;
|
export declare const authenticate: (userName: string, password: string) => Promise<boolean>;
|
||||||
|
export declare const getSafeRedirectURL: (possibleRedirectURL?: string) => string;
|
||||||
|
|
|
||||||
|
|
@ -24,3 +24,36 @@ export const authenticate = async (userName, password) => {
|
||||||
}
|
}
|
||||||
return await authenticateViaActiveDirectory(userName, password);
|
return await authenticateViaActiveDirectory(userName, password);
|
||||||
};
|
};
|
||||||
|
const safeRedirects = new Set([
|
||||||
|
"/admin/cleanup",
|
||||||
|
"/admin/fees",
|
||||||
|
"/admin/occupancytypes",
|
||||||
|
"/admin/tables",
|
||||||
|
"/lotoccupancies",
|
||||||
|
"/lotoccupancies/new",
|
||||||
|
"/lots",
|
||||||
|
"/lots/new",
|
||||||
|
"/maps",
|
||||||
|
"/maps/new",
|
||||||
|
"/workorders",
|
||||||
|
"/workorders/new",
|
||||||
|
"/workorders/milestonecalendar",
|
||||||
|
"/workorders/outlook",
|
||||||
|
"/reports"
|
||||||
|
]);
|
||||||
|
export const getSafeRedirectURL = (possibleRedirectURL = "") => {
|
||||||
|
const urlPrefix = configFunctions.getProperty("reverseProxy.urlPrefix");
|
||||||
|
if (typeof possibleRedirectURL === "string") {
|
||||||
|
const urlToCheck = (possibleRedirectURL.startsWith(urlPrefix)
|
||||||
|
? possibleRedirectURL.slice(urlPrefix.length)
|
||||||
|
: possibleRedirectURL).toLowerCase();
|
||||||
|
if (safeRedirects.has(urlToCheck) ||
|
||||||
|
/^(\/maps\/)\d+(\/edit)?$/.test(urlToCheck) ||
|
||||||
|
/^(\/lots\/)\d+(\/edit)?$/.test(urlToCheck) ||
|
||||||
|
/^(\/lotoccupancies\/)\d+(\/edit)?$/.test(urlToCheck) ||
|
||||||
|
/^(\/workorders\/)\d+(\/edit)?$/.test(urlToCheck)) {
|
||||||
|
return urlPrefix + urlToCheck;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return urlPrefix + "/dashboard";
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -41,3 +41,46 @@ export const authenticate = async (
|
||||||
|
|
||||||
return await authenticateViaActiveDirectory(userName, password);
|
return await authenticateViaActiveDirectory(userName, password);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const safeRedirects = new Set([
|
||||||
|
"/admin/cleanup",
|
||||||
|
"/admin/fees",
|
||||||
|
"/admin/occupancytypes",
|
||||||
|
"/admin/tables",
|
||||||
|
"/lotoccupancies",
|
||||||
|
"/lotoccupancies/new",
|
||||||
|
"/lots",
|
||||||
|
"/lots/new",
|
||||||
|
"/maps",
|
||||||
|
"/maps/new",
|
||||||
|
"/workorders",
|
||||||
|
"/workorders/new",
|
||||||
|
"/workorders/milestonecalendar",
|
||||||
|
"/workorders/outlook",
|
||||||
|
"/reports"
|
||||||
|
]);
|
||||||
|
|
||||||
|
export const getSafeRedirectURL = (possibleRedirectURL = "") => {
|
||||||
|
const urlPrefix = configFunctions.getProperty("reverseProxy.urlPrefix");
|
||||||
|
|
||||||
|
if (typeof possibleRedirectURL === "string") {
|
||||||
|
const urlToCheck = (
|
||||||
|
possibleRedirectURL.startsWith(urlPrefix)
|
||||||
|
? possibleRedirectURL.slice(urlPrefix.length)
|
||||||
|
: possibleRedirectURL
|
||||||
|
).toLowerCase();
|
||||||
|
|
||||||
|
if (
|
||||||
|
safeRedirects.has(urlToCheck) ||
|
||||||
|
/^(\/maps\/)\d+(\/edit)?$/.test(urlToCheck) ||
|
||||||
|
/^(\/lots\/)\d+(\/edit)?$/.test(urlToCheck) ||
|
||||||
|
/^(\/lotoccupancies\/)\d+(\/edit)?$/.test(urlToCheck) ||
|
||||||
|
/^(\/workorders\/)\d+(\/edit)?$/.test(urlToCheck)
|
||||||
|
) {
|
||||||
|
return urlPrefix + urlToCheck;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return urlPrefix + "/dashboard";
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -6,42 +6,12 @@ import { getApiKey } from "../helpers/functions.api.js";
|
||||||
import Debug from "debug";
|
import Debug from "debug";
|
||||||
const debug = Debug("lot-occupancy-system:login");
|
const debug = Debug("lot-occupancy-system:login");
|
||||||
export const router = Router();
|
export const router = Router();
|
||||||
const safeRedirects = new Set([
|
|
||||||
"/admin/fees",
|
|
||||||
"/admin/occupancytypes",
|
|
||||||
"/admin/tables",
|
|
||||||
"/lotoccupancies",
|
|
||||||
"/lotoccupancies/new",
|
|
||||||
"/lots",
|
|
||||||
"/lots/new",
|
|
||||||
"/maps",
|
|
||||||
"/maps/new",
|
|
||||||
"/workorders",
|
|
||||||
"/workorders/new",
|
|
||||||
"/reports"
|
|
||||||
]);
|
|
||||||
const getSafeRedirectURL = (possibleRedirectURL = "") => {
|
|
||||||
const urlPrefix = configFunctions.getProperty("reverseProxy.urlPrefix");
|
|
||||||
if (typeof possibleRedirectURL === "string") {
|
|
||||||
const urlToCheck = (possibleRedirectURL.startsWith(urlPrefix)
|
|
||||||
? possibleRedirectURL.slice(urlPrefix.length)
|
|
||||||
: possibleRedirectURL).toLowerCase();
|
|
||||||
if (safeRedirects.has(urlToCheck) ||
|
|
||||||
/^(\/maps\/)\d+(\/edit)?$/.test(urlToCheck) ||
|
|
||||||
/^(\/lots\/)\d+(\/edit)?$/.test(urlToCheck) ||
|
|
||||||
/^(\/lotoccupancies\/)\d+(\/edit)?$/.test(urlToCheck) ||
|
|
||||||
/^(\/workorders\/)\d+(\/edit)?$/.test(urlToCheck)) {
|
|
||||||
return urlPrefix + urlToCheck;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return urlPrefix + "/dashboard";
|
|
||||||
};
|
|
||||||
router
|
router
|
||||||
.route("/")
|
.route("/")
|
||||||
.get((request, response) => {
|
.get((request, response) => {
|
||||||
const sessionCookieName = configFunctions.getProperty("session.cookieName");
|
const sessionCookieName = configFunctions.getProperty("session.cookieName");
|
||||||
if (request.session.user && request.cookies[sessionCookieName]) {
|
if (request.session.user && request.cookies[sessionCookieName]) {
|
||||||
const redirectURL = getSafeRedirectURL((request.query.redirect || ""));
|
const redirectURL = authenticationFunctions.getSafeRedirectURL((request.query.redirect || ""));
|
||||||
response.redirect(redirectURL);
|
response.redirect(redirectURL);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -57,7 +27,7 @@ router
|
||||||
const userName = request.body.userName;
|
const userName = request.body.userName;
|
||||||
const passwordPlain = request.body.password;
|
const passwordPlain = request.body.password;
|
||||||
const unsafeRedirectURL = request.body.redirect;
|
const unsafeRedirectURL = request.body.redirect;
|
||||||
const redirectURL = getSafeRedirectURL(typeof unsafeRedirectURL === "string" ? unsafeRedirectURL : "");
|
const redirectURL = authenticationFunctions.getSafeRedirectURL(typeof unsafeRedirectURL === "string" ? unsafeRedirectURL : "");
|
||||||
let isAuthenticated = false;
|
let isAuthenticated = false;
|
||||||
if (userName.charAt(0) === "*") {
|
if (userName.charAt(0) === "*") {
|
||||||
if (useTestDatabases && userName === passwordPlain) {
|
if (useTestDatabases && userName === passwordPlain) {
|
||||||
|
|
|
||||||
|
|
@ -16,45 +16,6 @@ const debug = Debug("lot-occupancy-system:login");
|
||||||
|
|
||||||
export const router = Router();
|
export const router = Router();
|
||||||
|
|
||||||
const safeRedirects = new Set([
|
|
||||||
"/admin/fees",
|
|
||||||
"/admin/occupancytypes",
|
|
||||||
"/admin/tables",
|
|
||||||
"/lotoccupancies",
|
|
||||||
"/lotoccupancies/new",
|
|
||||||
"/lots",
|
|
||||||
"/lots/new",
|
|
||||||
"/maps",
|
|
||||||
"/maps/new",
|
|
||||||
"/workorders",
|
|
||||||
"/workorders/new",
|
|
||||||
"/reports"
|
|
||||||
]);
|
|
||||||
|
|
||||||
const getSafeRedirectURL = (possibleRedirectURL = "") => {
|
|
||||||
const urlPrefix = configFunctions.getProperty("reverseProxy.urlPrefix");
|
|
||||||
|
|
||||||
if (typeof possibleRedirectURL === "string") {
|
|
||||||
const urlToCheck = (
|
|
||||||
possibleRedirectURL.startsWith(urlPrefix)
|
|
||||||
? possibleRedirectURL.slice(urlPrefix.length)
|
|
||||||
: possibleRedirectURL
|
|
||||||
).toLowerCase();
|
|
||||||
|
|
||||||
if (
|
|
||||||
safeRedirects.has(urlToCheck) ||
|
|
||||||
/^(\/maps\/)\d+(\/edit)?$/.test(urlToCheck) ||
|
|
||||||
/^(\/lots\/)\d+(\/edit)?$/.test(urlToCheck) ||
|
|
||||||
/^(\/lotoccupancies\/)\d+(\/edit)?$/.test(urlToCheck) ||
|
|
||||||
/^(\/workorders\/)\d+(\/edit)?$/.test(urlToCheck)
|
|
||||||
) {
|
|
||||||
return urlPrefix + urlToCheck;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return urlPrefix + "/dashboard";
|
|
||||||
};
|
|
||||||
|
|
||||||
router
|
router
|
||||||
.route("/")
|
.route("/")
|
||||||
.get((request, response) => {
|
.get((request, response) => {
|
||||||
|
|
@ -62,7 +23,7 @@ router
|
||||||
configFunctions.getProperty("session.cookieName");
|
configFunctions.getProperty("session.cookieName");
|
||||||
|
|
||||||
if (request.session.user && request.cookies[sessionCookieName]) {
|
if (request.session.user && request.cookies[sessionCookieName]) {
|
||||||
const redirectURL = getSafeRedirectURL(
|
const redirectURL = authenticationFunctions.getSafeRedirectURL(
|
||||||
(request.query.redirect || "") as string
|
(request.query.redirect || "") as string
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -82,7 +43,7 @@ router
|
||||||
|
|
||||||
const unsafeRedirectURL = request.body.redirect;
|
const unsafeRedirectURL = request.body.redirect;
|
||||||
|
|
||||||
const redirectURL = getSafeRedirectURL(
|
const redirectURL = authenticationFunctions.getSafeRedirectURL(
|
||||||
typeof unsafeRedirectURL === "string" ? unsafeRedirectURL : ""
|
typeof unsafeRedirectURL === "string" ? unsafeRedirectURL : ""
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue