Mafia II

Zabezpečené stahování souborů

Březen 6th, 2007

Jistě jste se už setkali s problémem, že potřebujete zajistit, aby se nikdo nedostal k souborum v určite složce na webu. Ale někdy mu přístup chcete povolit. Šancí je, ošetřit přístup k souborům pomocí PHP. Standartne:

$file = basename($file); $filepath = „$download_fol­der/$file“; // tady nějaký test, jestli je uživatel opravněn header(„Content-type: application/x-octet-stream“); header(„Content-Disposition: attachment; filename=$file“); readfile($file­path); Jenže na většině hostingů narazíte tady na nastavení –memory_limit. Proto se musí použít drobný work-around:

function readfile_chun­ked($filename,$ret­bytes=true) {
$chunksize = 1(10241024); // how many bytes per chunk
$buffer = '';
$cnt =0;
// $handle = fopen($filename, ‚rb‘);
$handle = fopen($filename, ‚rb‘);
if ($handle === false) {
return false;
}
while (!feof($handle)) {
$buffer = fread($handle, $chunksize);
echo $buffer;
ob_flush();
flush();
if ($retbytes) {
$cnt += strlen($buffer);
}
}
$status = fclose($handle);
if ($retbytes && $status) {
return $cnt; // return num. bytes delivered like readfile() does.
}
return $status; } 

Tenhle kód je k dispozici v diskuzi o readfile() na PHP.net Jenže stále není vyhráno, protože stále může potenciální útočník zjistit nýzev souboru a přistoupit k němu přímo. Tomu opět zamezíme poměrně jednoduchým nastavením.

Vytvoříme .htaccess, který dáme do složky s downloady.

<files *>
Order Deny,Allow
Deny from All </files> <files ~ „\.php$“> Order Deny,Allow Allow from all </files> 

To zaručí, že pro všechny soubory bude odmítnut přístup (Error 403 – Forbidden), kromě těch s koncovkou „.php“. A je to. Ochránili jsme složku proti jakémukoli pokusu o získání jejího obsahu. Kromě přístupu přes FTP, samozřejmně.

EDIT – BEZPEČNOSTNÍ DÍRA: Se skriptu jsem našel bezpečnostní díru. A to, že skriuptem se dají získat i soubory *.php z danného adresáře. To je třeba ošetřit podmínkou.

if(strpos($file, ‚.php‘)){
die(‚Pokus o zneužití‘); }

EDIT2 – Nefunkčnost v IE: Zjistil jsem, že skript nefunguje ze záhadného důvodu v IE. Je třeba do hlavičky poslat ještě:

header(„Pragma: public“); header(„Expires: 0“); header(„Cache-Control: must-revalidate, post-check=0, pre-check=0“); header(„Cache-Control: private“,false); header(„Content-Transfer-Encoding: binary“);; header(„Content-type: image/jpg“); // zde konkretni MIME-typ, ne stream.

4 Responses to “Zabezpečené stahování souborů”

  1. tomas Says:

    První bezpečnostní díra mě upozornila na to, že jsem, co se bezpečnosti týče, poměrně laxní. Takže pokud najdete nějaké další díry, tak se nestyďte mi to napsat a pořádně mě zbuznout. Kontakty najdete na mé stránce nahoře v menu.

  2. stareksoft Says:

    Zkusil jsem nize uvedene, ale v IE se mi to nechová korektně. Posíl zkrze to ZIP a při rozbalování přes IE mi to zahlásí nekorektní konec archyvu. Když přes totalcommander porovnám obsahy, dost se od staženého přes FireFox lyší a z IE je dokonce delší. Nevíte kde by mohla být chyba?

    header(”Content-type: application/x-octet-stream”);
    header(”Content-Disposition: attachment; filename=$filepseudo”);
    header(”Pragma: public”);
    header(”Expires: 0″);
    header(”Cache-Control: must-revalidate, post-check=0, pre-check=0″);
    header(”Cache-Control: private”,false);
    header(”Content-Transfer-Encoding: binary”);
    header(”Content-type: application/zip”);
    header(”Content-Length: “.(filesize($file)));

    function readfile_chunked($filename,$retbytes=true) {
    $chunksize = 1*(1024*1024);
    $buffer = “”;
    $cnt =0;
    $handle = fopen($filename, “rb”);
    if ($handle === false) {
    return false;
    }
    while (!feof($handle)) {
    $buffer = fread($handle, $chunksize);
    echo $buffer;
    ob_flush();
    flush();
    if ($retbytes) {
    $cnt += strlen($buffer);
    }
    }
    $status = fclose($handle);
    if ($retbytes && $status) {
    return $cnt;
    }
    return $status;
    }
    readfile_chunked($file,true);

  3. stareksoft Says:

    Tak se zdá že vynecháním obou řádků
    header(”Content-type: …..
    byl problém vyřešen a nyní to funguje jak v IE tak FF.

  4. stareksoft Says:

    Jo a header(”Content-Length: “.(filesize($file))); taky IE moc nevoněl, ničil konec souboru.

Vložty komentář