Security fixes pass #1
This commit is contained in:
parent
cb5126c947
commit
3b26292124
1
.gitignore
vendored
1
.gitignore
vendored
@ -182,3 +182,4 @@ __fixtures__
|
|||||||
/.dump
|
/.dump
|
||||||
/.vscode
|
/.vscode
|
||||||
/source.md
|
/source.md
|
||||||
|
SECURITY.md
|
||||||
@ -68,16 +68,16 @@ export default async function ({ req }: Params): Promise<Response> {
|
|||||||
|
|
||||||
const config = module.config as BunextServerRouteConfig | undefined;
|
const config = module.config as BunextServerRouteConfig | undefined;
|
||||||
|
|
||||||
|
const maxBodyBytes = config?.max_request_body_mb
|
||||||
|
? config.max_request_body_mb * MBInBytes
|
||||||
|
: ServerDefaultRequestBodyLimitBytes;
|
||||||
|
|
||||||
const contentLength = req.headers.get("content-length");
|
const contentLength = req.headers.get("content-length");
|
||||||
|
|
||||||
if (contentLength) {
|
if (contentLength) {
|
||||||
const size = parseInt(contentLength, 10);
|
const size = parseInt(contentLength, 10);
|
||||||
|
|
||||||
if (
|
if (size > maxBodyBytes) {
|
||||||
(config?.max_request_body_mb &&
|
|
||||||
size > config.max_request_body_mb * MBInBytes) ||
|
|
||||||
size > ServerDefaultRequestBodyLimitBytes
|
|
||||||
) {
|
|
||||||
return Response.json(
|
return Response.json(
|
||||||
{
|
{
|
||||||
success: false,
|
success: false,
|
||||||
@ -91,6 +91,26 @@ export default async function ({ req }: Params): Promise<Response> {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
} else if (req.method !== "GET" && req.method !== "HEAD") {
|
||||||
|
const body = await req.arrayBuffer();
|
||||||
|
if (body.byteLength > maxBodyBytes) {
|
||||||
|
return Response.json(
|
||||||
|
{
|
||||||
|
success: false,
|
||||||
|
msg: "Request Body Too Large!",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
status: 413,
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
routeParams.body = JSON.parse(
|
||||||
|
new TextDecoder().decode(body) || "{}",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const target_module = (module["default"] ||
|
const target_module = (module["default"] ||
|
||||||
|
|||||||
@ -1,8 +1,18 @@
|
|||||||
import EJSON from "./ejson";
|
import EJSON from "./ejson";
|
||||||
|
|
||||||
/**
|
const DANGEROUS_KEYS = new Set(["__proto__", "constructor", "prototype"]);
|
||||||
* # Convert Serialized Query back to object
|
|
||||||
*/
|
function sanitize<T>(value: T): T {
|
||||||
|
if (value === null || typeof value !== "object") return value;
|
||||||
|
if (Array.isArray(value)) return value.map(sanitize) as T;
|
||||||
|
const clean: Record<string, any> = Object.create(null);
|
||||||
|
for (const key of Object.keys(value as Record<string, any>)) {
|
||||||
|
if (DANGEROUS_KEYS.has(key)) continue;
|
||||||
|
clean[key] = sanitize((value as Record<string, any>)[key]);
|
||||||
|
}
|
||||||
|
return clean as T;
|
||||||
|
}
|
||||||
|
|
||||||
export default function deserializeQuery(
|
export default function deserializeQuery(
|
||||||
query: string | { [s: string]: any }
|
query: string | { [s: string]: any }
|
||||||
): {
|
): {
|
||||||
@ -17,12 +27,17 @@ export default function deserializeQuery(
|
|||||||
const key = keys[i];
|
const key = keys[i];
|
||||||
const value = queryObject[key];
|
const value = queryObject[key];
|
||||||
|
|
||||||
|
if (DANGEROUS_KEYS.has(key)) {
|
||||||
|
delete queryObject[key];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof value == "string") {
|
if (typeof value == "string") {
|
||||||
if (value.match(/^\{|^\[/)) {
|
if (value.match(/^\{|^\[/)) {
|
||||||
queryObject[key] = EJSON.parse(value);
|
queryObject[key] = sanitize(EJSON.parse(value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return queryObject;
|
return sanitize(queryObject);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user