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_folder/$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($filepath); Jenže na většině hostingů
narazíte tady na nastavení –memory_limit.
Proto se musí použít drobný work-around:
function readfile_chunked($filename,$retbytes=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.
Home
Březen 8th, 2007 at 20.31
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.
Červen 15th, 2009 at 16.15
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);
Červen 15th, 2009 at 16.29
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.
Červen 15th, 2009 at 16.30
Jo a header(”Content-Length: “.(filesize($file))); taky IE moc nevoněl, ničil konec souboru.