FlawOpen

flawopen.com/Kerentanan/Prototype pollution JavaScript

Prototype pollution JavaScript

Tingkat keparahan tinggi CWE-1321 Rantai pasok dan runtime
Penjelasan sederhana — Buku aturan bersama

Bayangkan bengkel tempat setiap perangkat baru memeriksa buku aturan bersama ketika pengaturannya sendiri tidak menjawab pertanyaan. Jika petugas menulis aturan yang dikendalikan penyerang ke buku itu, perangkat lain mungkin membacanya sebagai nilai bawaan. Dalam prototype pollution, penulisan properti dinamis yang tidak aman dapat mengubah prototipe objek, terkadang Object.prototype. Dampaknya tidak otomatis bersifat global; kode aplikasi harus kemudian memercayai properti yang diwariskan.

Target:JavaScript server atau browser yang menggabungkan key tidak tepercaya atau menulis jalur properti yang dikendalikan pengguna
Vektor:Key tidak tepercaya seperti __proto__, atau jalur constructor.prototype yang mencapai penulisan tidak aman
Dampak:Bergantung pada gadget yang dapat dicapai: perubahan logika, denial of service, XSS, atau dalam sebagian kasus server-side eksekusi kode; semuanya tidak otomatis
Perbaikan:Validasi dengan schema atau allowlist; gunakan Map atau dictionary tanpa prototipe untuk key yang tidak tepercaya

Konsep inti dan istilah subsistem

Object.prototype
Prototipe bersama yang diwarisi objek biasa. Pencemarannya dapat berdampak pada banyak objek, tetapi tidak pada semua objek JavaScript atau semua realm.
__proto__
Accessor lama pada objek biasa untuk mengambil atau mengatur prototipe. Dalam teks JSON, ejaan yang sama awalnya hanyalah nama properti biasa sampai kode berikutnya menanganinya secara tidak aman.
Penggabungan mendalam rekursif
Fungsi penyalin yang menelusuri key bertingkat dan menulisnya ke objek lain. Fungsi ini berbahaya jika key tidak tepercaya dapat memilih properti terkait prototipe atau jalur tidak aman.
CWE-1321
Perubahan atribut prototipe objek yang tidak dikendalikan dengan semestinya. Kelemahannya adalah mutasi yang tidak terkendali; dampak berikutnya bergantung pada perilaku aplikasi yang dapat dicapai.

Alur serangan langkah demi langkah

Langkah 1

Input properti tidak tepercaya

Endpoint menerima key objek yang dikendalikan penyerang. Mem-parse JSON dengan properti own __proto__ saja tidak mengubah prototipe.

Langkah 2

Penulisan dinamis tidak aman

Recursive merge atau setter jalur mengikuti key tersebut dan menulis secara dinamis tanpa memvalidasi setiap segmen jalur.

Langkah 3

Perubahan prototipe target atau bersama

Bergantung pada target dan urutan penulisan, operasi mengubah prototipe target atau mencapai prototipe bersama seperti Object.prototype. Keduanya adalah hasil yang berbeda.

Langkah 4

Dampak ditentukan oleh gadget

Gadget berikutnya membaca nilai warisan dalam operasi yang sensitif terhadap keamanan. Dampaknya bergantung pada gadget itu; jangan mengasumsikan bypass autentikasi atau eksekusi kode.

Mekanisme dan akar masalah

Pencarian properti JavaScript mengikuti rantai prototipe. Merge rentan atau setter jalur dapat membiarkan key tidak tepercaya seperti __proto__ atau constructor.prototype mengarahkan penulisan ke prototipe. Field own __proto__ yang dibuat oleh JSON.parse bukan pencemaran dengan sendirinya; kode berikutnya harus menafsirkannya lewat assignment yang tidak aman. Perubahan prototipe target berdampak pada target itu; perubahan Object.prototype berdampak pada objek biasa yang mewarisinya. Gadget terpisah harus menggunakan properti warisan agar timbul dampak keamanan.

utils.js (Merge rekursif rentan)Rentan
// RENTAN: key yang dikendalikan penyerang mencapai penulisan rekursif
function merge(target, source) {
    for (const key in source) {
        const value = source[key];
        if (value && typeof value === 'object') {
            if (!target[key]) target[key] = {};
            merge(target[key], value);
        } else {
            target[key] = value;
        }
    }
    return target;
}
// JSON.parse membuat properti data own __proto__; merge yang tidak amanlah risikonya.
const input = JSON.parse('{"__proto__": {"isAdmin": true}}');
merge({}, input);
utils.js (Parser profil dengan allowlist)Diperkuat
// DIPERKUAT: salin hanya field yang memang diterima endpoint ini
const PROFILE_KEYS = new Set(['displayName', 'theme']);

function parseProfile(input) {
    if (!input || typeof input !== 'object' || Array.isArray(input)) {
        throw new TypeError('profile must be an object');
    }

    const profile = Object.create(null);
    for (const key of Object.keys(input)) {
        if (!PROFILE_KEYS.has(key)) continue;
        const value = input[key];
        if (typeof value !== 'string' || value.length > 80) {
            throw new TypeError('invalid profile field');
        }
        profile[key] = value;
    }
    return profile;
}

Urutan serangan dan eksploitasi

Rekayasa pertahanan dan aturan pencegahan

Pertanyaan umum

Apakah JSON.parse() sendiri mencemari prototipe?

Tidak. JSON.parse() membuat properti data milik sendiri bernama __proto__ dan tidak memanggil setter warisan. Risiko muncul jika merge atau assignment berikutnya memanggil setter tersebut. Lihat Apakah JSON.parse() menyebabkan Prototype Pollution?

Apakah Object.freeze(Object.prototype) memperbaikinya?

Ini dapat mencegah penulisan ke Object.prototype yang dibekukan itu sendiri, tetapi tidak menghentikan setter mengubah prototipe satu objek atau melindungi semua prototipe lain. Ini juga dapat merusak pustaka yang memperluas built-in. Gunakan hanya sebagai defense-in-depth, bukan perbaikan pengolahan data.

Apakah TypeScript terlindungi?

Tidak. Tipe dihapus saat runtime. Nilai bertipe Record<string, string> masih dapat memiliki kunci __proto__; validasi kunci tak tepercaya dan buat objek dengan aman.

Jelajahi topik keamanan dan analisis insiden terkait:Direktori keamanan lengkap →