Sanitizer-ul care scoate ../ o singură dată
TypeScript · Handler-ul de upload al unui serviciu de gestiune a documentelor · Securitate · dificultate 2/3 · ~8 min
Utilizatorii unui serviciu de gestiune a documentelor urcă fișiere în propriul folder de pe disc. Pot alege o cale relativă în interiorul acelui folder (de exemplu 2024/q1/report.pdf), deci subfolderele sunt permise. Handler-ul de upload scrie apoi în <uploads root>/<user id>/<sanitized path>.
Un coleg i-a cerut asistentului AI: „Scrie sanitizeUploadPath(input), care curăță calea primită de la utilizator ca să nu poată ieși niciodată din folderul lui. Păstrează literele, cifrele, punctele, cratimele, underscore-urile și slash-urile; transformă whitespace-ul în underscore; elimină orice altceva.”
Codul a venit cu teste care trec. Contractul promis de docstring:
- Rezultatul e o cale relativă, fără slash la început.
- Rezultatul nu conține niciodată un segment care urcă în arbore (
..), oricum ar fi arătat inputul. - Rămân doar
a-z,A-Z,0-9,.,_,-și/; whitespace-ul devine_. - Un input din care nu rămâne nimic utilizabil devine
file.
Înainte să ajungă pe branch-ul care scrie pe disc, fă-i review cu răbdarea unui atacator.
code.ts
Teste vizibile (trec pe codul primit)
import { describe, it, expect } from "@debunk/harness";
import { sanitizeUploadPath } from "./code";
describe("sanitizeUploadPath", () => {
it("keeps a normal relative path with subfolders", () => {
expect(sanitizeUploadPath("2024/q1/report.pdf")).toBe("2024/q1/report.pdf");
});
it("strips directory traversal and leading slashes", () => {
expect(sanitizeUploadPath("../secret.txt")).toBe("secret.txt");
expect(sanitizeUploadPath("/etc/passwd")).toBe("etc/passwd");
});
it("replaces whitespace and drops disallowed characters", () => {
expect(sanitizeUploadPath("report final <v2>.pdf")).toBe("report_final_v2.pdf");
});
});