FlawOpen

flawopen.com/Prototype pollution/JSON.parse()

Apakah JSON.parse() menyebabkan prototype pollution?

CWE-1321: Prototype PollutionPanduan referensi
Jawaban singkat

Tidak. JSON.parse() membuat properti data milik sendiri bernama __proto__; proses parsing tidak memanggil setter warisan atau mengubah prototipe. Risiko muncul kemudian jika kode menyalin kunci itu melalui setter, menggabungkan kunci tak tepercaya secara rekursif, atau menulis ke jalur objek yang dikendalikan penyerang.

SALINAN TIDAK AMAN — TARGET LOKAL
// JSON.parse membuat data; tidak mencemari prototipe.
const input = '{"__proto__":{"isAdmin":true}}';
const parsed = JSON.parse(input);

// Object.assign menggunakan Set pada target. Di sini hanya
// prototipe objek demo lokal ini yang berubah.
const copied = Object.assign({}, parsed);

Object.getPrototypeOf(copied).isAdmin; // true
Object.prototype.isAdmin;              // undefined
PENANGANAN AMAN — BENTUK DIKENAL
// Parse lalu bentuk hanya bidang yang diizinkan aplikasi.
const input = '{"theme":"dark","locale":"en","__proto__":{"isAdmin":true}}';
const parsed = JSON.parse(input);
const config = {
  theme:  parsed.theme,
  locale: parsed.locale,
};

// Untuk peta berkunci tak tepercaya, hindari setter warisan.
const options = Object.assign(Object.create(null), parsed);

Mengapa JSON.parse() bukan titik pencemaran

Kunci JSON dan setter prototipe pada object literal adalah operasi berbeda. Parsing JSON mendefinisikan properti milik sendiri pada nilai baru; proses itu tidak menjalankan obj.__proto__ = value. Operasi berikutnya dapat berperilaku lain: Object.assign(target, source) melakukan assignment ke target, sehingga kunci milik sendiri __proto__ dapat memanggil setter warisan target. Ini mengubah prototipe objek target; tindakan ini saja tidak mengubah Object.prototype.

Setelah const o = JSON.parse('{"__proto__":{"a":1}}'), Object.hasOwn(o, "__proto__") bernilai true dan Object.prototype.a tetap undefined. Penyalinan berikutnya ke target biasa dapat mengubah prototipe target tersebut. Object spread membuat properti milik sendiri tanpa memanggil setter, tetapi bukan perlindungan terhadap merge rekursif atau penulisan jalur yang tidak aman.

Di mana risiko sebenarnya muncul

JSON yang telah diparse adalah data tak tepercaya, bukan prototipe yang tercemari. Risikonya bergantung pada sink penulisan berikutnya: merge rekursif, setter jalur, atau loop penyalinan yang mengassign kunci ke objek biasa. Merge rekursif yang rentan dapat menelusuri __proto__ atau constructor.prototype hingga prototipe bersama; penyalinan satu tingkat mungkin hanya mengubah target. Telusuri helper dan objek target yang sebenarnya sebelum menyimpulkan dampak.

Tinjau tempat kunci tak tepercaya ditulis, bukan hanya tempat JSON diparse: helper deep-merge, setter jalur objek, dan loop for...in yang melakukan assignment. Tolak __proto__, constructor, dan prototype jika pengguna mengendalikan kunci; lebih baik bangun ulang bentuk tervalidasi atau gunakan kamus tanpa prototipe.

Pertanyaan umum

Haruskah selalu memakai reviver untuk membuang __proto__?

Reviver dapat membuang kunci itu saat parsing jika aplikasi tidak membutuhkannya. Ini pertahanan berlapis, bukan pengganti perbaikan merge dan penulisan jalur yang tidak aman; constructor.prototype dan sumber non-JSON juga perlu diperiksa.

Apakah Express atau body-parser melindungi saya?

Parser body menghasilkan nilai JavaScript; parser tidak membuat penyalinan atau merge setelahnya aman. Tinjau parser yang benar-benar digunakan dan operasi lanjutan. Beberapa parser query string juga membangun objek bertingkat dari sintaks kurung siku, jalur input yang berbeda.

Apakah JSON.stringify() berisiko menyebabkan prototype pollution?

Tidak. Serialisasi membaca nilai dan menghasilkan teks JSON; ia tidak mengubah prototipe. Risiko dapat muncul kembali jika teks itu diparse lalu diteruskan ke sink yang tidak aman.

Referensi

Lihat juga Prototype Pollution JavaScript: penyebab dan perbaikan Apakah JSON.parse() lebih aman daripada eval()? Apakah lodash.merge() aman dari prototype pollution? Object.assign() dan Prototype Pollution: apa yang aman?