ASCII ".. /"

3 Cevap php

Ben dosya sistemi üzerinde JS / CSS dosyaları seçmek için bir $_GET parametresini kullanan bir PHP uygulaması var.

Ben giriş dizesi içerdiği tüm isteklerini inkar ederse ./, \ veya görünür 7-bitlik ASCII aralığının dışında bir byte, bu yeterli yol olduğu ana dizin traversals önlemek için PHP'nin temel (C tabanlı) dosya işlevlerine geçti?

I null-byte vulnerabilities farkındayım, ancak bu kontroller tarafından gıcırtı olabilecek diğer alternatif / biçimlendirilmiş karakter kodlamaları hile vardır?

Burada temel fikir (değil üretim kodu) bulunuyor:

$f = $_GET['f']; // e.g. "path/to/file.js"

// goal: select only unhidden CSS/JS files within DOC_ROOT
if (! preg_match('@^[\x20-\x7E]+$@', $f)     // outside visible ASCII
   || false !== strpos($f, "./")             // has ./
   || false !== strpos($f, "\\")             // has \
   || 0 === strpos(basename($f), ".")        // .isHiddenFile
   || ! preg_match('@\\.(css|js)$i@', $f)    // not JS/CSS
   || ! is_file($_SERVER['DOCUMENT_ROOT'] . '/' . $f)) {
    die();
}
$content = file_get_contents($_SERVER['DOCUMENT_ROOT'] . '/' . $f);

Update: Benim soru (belgesiz kaçış dizileri varsa örneğin) C dosya sistemi fonksiyonları keyfi ASCII dizileri nasıl yorumlamak konusunda gerçekten, ama bu büyük olasılıkla fark sistem bağımlı pratikte ve belki de çözümsüz.

Benim aktif doğrulama ek realpath($fullPath) dosya doc_root içinde olduğunu sağlanması, realpath($_SERVER['DOCUMENT_ROOT']) ile başlamak gerekir, ancak bu mesajın bir hedefi realpath() (o hendek oldu Hala gibi sıradışı, ama geçerli URI'lere verirken) çeşitli ortamlarda güvenilmez kanıtlanmış /~user/[my files]/file.plugin.js.

3 Cevap

Bunu kendiniz söz, ama realpath bilinen bir kök girdi karşılaştırarak Aklıma en iyi çözümdür. Realpath yollarda dahil olmak üzere yol / dosya sisteminin herhangi bir gizli özellikleri, çözecektir.

Güvenlik için giriş süzme, her zaman beyaz listeler, değil backlists kullanın.

Sen /^([A-Za-z0-9_-]+\/?)*[A-Za-z0-9_-]+\.(js)|(css)?$/ eşleşmiyor tüm yolları reddetmek gerekir.

Bu sadece her kesimi harf, sayı veya _- var, normal kesimli yolları sağlayacaktır.

Biraz rearchitecting gerektirir, ama geçti bile ../../passwd Olabilir, basename() onu tecrit olacaktır. Sonra, size bir klasöre hizmet etmek isteyen tüm dosyaları yer olabilir.

../../././././a/b/c/d.txt, basename($f) d.txt olacak göz önüne alındığında; Bu yaklaşım yerine kullanıcıyı zekâsı çalışıyor ve bir delik unutmadan, bana akıllıca görünüyor.