<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
		>
<channel>
	<title>Comentarios en: Cómo validar correctamente la descarga de un archivo en php</title>
	<atom:link href="http://blog.zerial.org/seguridad/como-validar-correctamente-la-descarga-de-un-archivo-en-php/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.zerial.org/seguridad/como-validar-correctamente-la-descarga-de-un-archivo-en-php/</link>
	<description>Informática, GNU/Linux, Seguridad, Hacking, Programación, Ocio</description>
	<lastBuildDate>Thu, 09 Feb 2012 18:22:44 +0000</lastBuildDate>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
	<item>
		<title>Por: Jotape</title>
		<link>http://blog.zerial.org/seguridad/como-validar-correctamente-la-descarga-de-un-archivo-en-php/comment-page-1/#comment-100197</link>
		<dc:creator>Jotape</dc:creator>
		<pubDate>Wed, 17 Aug 2011 16:26:32 +0000</pubDate>
		<guid isPermaLink="false">http://blog.zerial.org/?p=1009#comment-100197</guid>
		<description>Encontré este código que modifiqué levemente (http://forum.codecall.net/classes-code-snippets/10316-php-directory-traversal-prevention.html) que puede ser útil para prevenir el directory transversal... solamente pasa el código si el directorio desde donde se va a bajar el archivo se encuentra más abajo (en profundidad)

$path_parts = pathinfo($archivo);
$directory = $path_parts[&quot;dirname&quot;];
	
	$root = explode ( DIRECTORY_SEPARATOR, realpath ( dirname ( __FILE__ ) ) );
	
	if (! is_dir ( $directory )) {
		die ( &quot;Ubicación invalida.&quot; );
	}
	
	$request = explode ( DIRECTORY_SEPARATOR, realpath ( $directory ) );
	
	empty ( $request [0] ) ? array_shift ( $request ) : $request;
	empty ( $root [0] ) ? array_shift ( $root ) : $root;
	
	if (count ( array_diff_assoc ( $root, $request ) ) &gt; 0) {
		die ( &quot;Ubicación invalida.&quot; );
	} 


Lo otro que me resultó útil fue modificar el case de este código (http://us2.php.net/manual/en/function.header.php#102175) de manera que el default tirara un die ( &quot;Archivo invalido.&quot; ); para evitar extensiones no deseadas..

Saludos</description>
		<content:encoded><![CDATA[<p>Encontré este código que modifiqué levemente (<a href="http://forum.codecall.net/classes-code-snippets/10316-php-directory-traversal-prevention.html" rel="nofollow">http://forum.codecall.net/classes-code-snippets/10316-php-directory-traversal-prevention.html</a>) que puede ser útil para prevenir el directory transversal&#8230; solamente pasa el código si el directorio desde donde se va a bajar el archivo se encuentra más abajo (en profundidad)</p>
<p>$path_parts = pathinfo($archivo);<br />
$directory = $path_parts["dirname"];</p>
<p>	$root = explode ( DIRECTORY_SEPARATOR, realpath ( dirname ( __FILE__ ) ) );</p>
<p>	if (! is_dir ( $directory )) {<br />
		die ( &#8220;Ubicación invalida.&#8221; );<br />
	}</p>
<p>	$request = explode ( DIRECTORY_SEPARATOR, realpath ( $directory ) );</p>
<p>	empty ( $request [0] ) ? array_shift ( $request ) : $request;<br />
	empty ( $root [0] ) ? array_shift ( $root ) : $root;</p>
<p>	if (count ( array_diff_assoc ( $root, $request ) ) &gt; 0) {<br />
		die ( &#8220;Ubicación invalida.&#8221; );<br />
	} </p>
<p>Lo otro que me resultó útil fue modificar el case de este código (<a href="http://us2.php.net/manual/en/function.header.php#102175" rel="nofollow">http://us2.php.net/manual/en/function.header.php#102175</a>) de manera que el default tirara un die ( &#8220;Archivo invalido.&#8221; ); para evitar extensiones no deseadas..</p>
<p>Saludos</p>
]]></content:encoded>
	</item>
	<item>
		<title>Por: Zerial</title>
		<link>http://blog.zerial.org/seguridad/como-validar-correctamente-la-descarga-de-un-archivo-en-php/comment-page-1/#comment-83173</link>
		<dc:creator>Zerial</dc:creator>
		<pubDate>Fri, 20 Aug 2010 13:49:15 +0000</pubDate>
		<guid isPermaLink="false">http://blog.zerial.org/?p=1009#comment-83173</guid>
		<description>@fossie: Hola!

Yo creo que la razon de no usar el &quot;@&quot; es bastante simple, pues el desarrollo de aplicaciones requieren &quot;debug&quot; para detectar problemas y errores, existe un &quot;bit&quot; para activar y desactivar los errores, se puede hacer por el php.ini, por .htaccess o bien desde el mismo codigo php, si queremos quitar los errores simplemente se desactiva la muestra de errores. Si usamos las &quot;@&quot; para ocultar errores, cuando queramos activar y desactivar los errores tendriamos que editar todo el codigo fuente para agregar o quitar las @ de cada metodo o funcion que utilicemos.

saludos</description>
		<content:encoded><![CDATA[<p>@fossie: Hola!</p>
<p>Yo creo que la razon de no usar el &#8220;@&#8221; es bastante simple, pues el desarrollo de aplicaciones requieren &#8220;debug&#8221; para detectar problemas y errores, existe un &#8220;bit&#8221; para activar y desactivar los errores, se puede hacer por el php.ini, por .htaccess o bien desde el mismo codigo php, si queremos quitar los errores simplemente se desactiva la muestra de errores. Si usamos las &#8220;@&#8221; para ocultar errores, cuando queramos activar y desactivar los errores tendriamos que editar todo el codigo fuente para agregar o quitar las @ de cada metodo o funcion que utilicemos.</p>
<p>saludos</p>
]]></content:encoded>
	</item>
	<item>
		<title>Por: fossie</title>
		<link>http://blog.zerial.org/seguridad/como-validar-correctamente-la-descarga-de-un-archivo-en-php/comment-page-1/#comment-83169</link>
		<dc:creator>fossie</dc:creator>
		<pubDate>Fri, 20 Aug 2010 10:40:25 +0000</pubDate>
		<guid isPermaLink="false">http://blog.zerial.org/?p=1009#comment-83169</guid>
		<description>Y digo yo ¿porque nadie usa @readfile y @filesize ? poniendo la arroba antes de la función se eliminan los mensajes de error y de esta forma no apareceria el Full Path Disclosure

También se me ocurre que podriamos tener en la carpeta (o carpetas) desde la que permitimos la descarga un fichero del tipo &quot;fichero.txt_descarga&quot; (un fichero vacio por ejemplo) para indicar si se puede descargar o no, por ejemplo, si queremos descargar 
$folder = &quot;archivos/&quot;;
$archivo = &quot;docu.pdf&quot;;
$enlace = &quot;archivos/docu.pdf&quot;;
$verificacion =&quot;archivos/docu.pdf_descarga&quot;
if (file_exists($verificacion)&amp;&amp;file_exists($enlace))
{ @readfile ($enlace); }

Es una dia, tal vez algo cutrecilla pero pienso que efectiva ya que si intentan descargar el /etc/passwd jamas existira el fichero /etc/passwd_descargar (si existe es que nos han vulnerado el servidor por otro lado ;D )</description>
		<content:encoded><![CDATA[<p>Y digo yo ¿porque nadie usa @readfile y @filesize ? poniendo la arroba antes de la función se eliminan los mensajes de error y de esta forma no apareceria el Full Path Disclosure</p>
<p>También se me ocurre que podriamos tener en la carpeta (o carpetas) desde la que permitimos la descarga un fichero del tipo &#8220;fichero.txt_descarga&#8221; (un fichero vacio por ejemplo) para indicar si se puede descargar o no, por ejemplo, si queremos descargar<br />
$folder = &#8220;archivos/&#8221;;<br />
$archivo = &#8220;docu.pdf&#8221;;<br />
$enlace = &#8220;archivos/docu.pdf&#8221;;<br />
$verificacion =&#8221;archivos/docu.pdf_descarga&#8221;<br />
if (file_exists($verificacion)&amp;&amp;file_exists($enlace))<br />
{ @readfile ($enlace); }</p>
<p>Es una dia, tal vez algo cutrecilla pero pienso que efectiva ya que si intentan descargar el /etc/passwd jamas existira el fichero /etc/passwd_descargar (si existe es que nos han vulnerado el servidor por otro lado ;D )</p>
]]></content:encoded>
	</item>
	<item>
		<title>Por: Jac</title>
		<link>http://blog.zerial.org/seguridad/como-validar-correctamente-la-descarga-de-un-archivo-en-php/comment-page-1/#comment-72485</link>
		<dc:creator>Jac</dc:creator>
		<pubDate>Tue, 27 Oct 2009 14:01:27 +0000</pubDate>
		<guid isPermaLink="false">http://blog.zerial.org/?p=1009#comment-72485</guid>
		<description>Sobre proteger un directorio.

Pero sin .htaccess, sino con php, por ej cuando validas si la sesión no está activa en un php. Validar que la sesión no vea contenido de un directorio si no está activa. 
Nosé si se puede con php.</description>
		<content:encoded><![CDATA[<p>Sobre proteger un directorio.</p>
<p>Pero sin .htaccess, sino con php, por ej cuando validas si la sesión no está activa en un php. Validar que la sesión no vea contenido de un directorio si no está activa.<br />
Nosé si se puede con php.</p>
]]></content:encoded>
	</item>
	<item>
		<title>Por: Jac</title>
		<link>http://blog.zerial.org/seguridad/como-validar-correctamente-la-descarga-de-un-archivo-en-php/comment-page-1/#comment-72484</link>
		<dc:creator>Jac</dc:creator>
		<pubDate>Tue, 27 Oct 2009 13:58:47 +0000</pubDate>
		<guid isPermaLink="false">http://blog.zerial.org/?p=1009#comment-72484</guid>
		<description>jajaja no me mustra el código, ahora sí:


function safe($value){
   return mysql_real_escape_string($value);
}


Then, when I am using my code, I simply use:

$name = safe($_POST[&quot;name&quot;]);
$password = safe($_POST[&quot;password&quot;]);</description>
		<content:encoded><![CDATA[<p>jajaja no me mustra el código, ahora sí:</p>
<p>function safe($value){<br />
   return mysql_real_escape_string($value);<br />
}</p>
<p>Then, when I am using my code, I simply use:</p>
<p>$name = safe($_POST["name"]);<br />
$password = safe($_POST["password"]);</p>
]]></content:encoded>
	</item>
	<item>
		<title>Por: Jac</title>
		<link>http://blog.zerial.org/seguridad/como-validar-correctamente-la-descarga-de-un-archivo-en-php/comment-page-1/#comment-72483</link>
		<dc:creator>Jac</dc:creator>
		<pubDate>Tue, 27 Oct 2009 13:57:56 +0000</pubDate>
		<guid isPermaLink="false">http://blog.zerial.org/?p=1009#comment-72483</guid>
		<description>Buscando proteger mis archivos de sql inyec. encontré esto, se bastante útil, q opinan:



Then, when I am using my code, I simply use:

</description>
		<content:encoded><![CDATA[<p>Buscando proteger mis archivos de sql inyec. encontré esto, se bastante útil, q opinan:</p>
<p>Then, when I am using my code, I simply use:</p>
]]></content:encoded>
	</item>
	<item>
		<title>Por: Zerial</title>
		<link>http://blog.zerial.org/seguridad/como-validar-correctamente-la-descarga-de-un-archivo-en-php/comment-page-1/#comment-72481</link>
		<dc:creator>Zerial</dc:creator>
		<pubDate>Tue, 27 Oct 2009 12:57:20 +0000</pubDate>
		<guid isPermaLink="false">http://blog.zerial.org/?p=1009#comment-72481</guid>
		<description>@corridear: Hola! La variable $contenido tampoco se que funcion cumple :P (yo copie y pegue un download.php que me descargue de un sitio).

Sobre lo que dices en tu comentario anterior, pues si, tienes razon, pero yo solo busco &quot;encaminar&quot; para que encuentren el mejor metodo de validacion segun sus requerimientos.
Es cierto lo que dices de que no se puede confiar en los parametros de entrada del usuario (como el ID), pero lo que busco yo es que no puedan hacer directory transversal, lfi o rfi

saludos!</description>
		<content:encoded><![CDATA[<p>@corridear: Hola! La variable $contenido tampoco se que funcion cumple <img src='http://blog.zerial.org/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' />  (yo copie y pegue un download.php que me descargue de un sitio).</p>
<p>Sobre lo que dices en tu comentario anterior, pues si, tienes razon, pero yo solo busco &#8220;encaminar&#8221; para que encuentren el mejor metodo de validacion segun sus requerimientos.<br />
Es cierto lo que dices de que no se puede confiar en los parametros de entrada del usuario (como el ID), pero lo que busco yo es que no puedan hacer directory transversal, lfi o rfi</p>
<p>saludos!</p>
]]></content:encoded>
	</item>
	<item>
		<title>Por: corrideat</title>
		<link>http://blog.zerial.org/seguridad/como-validar-correctamente-la-descarga-de-un-archivo-en-php/comment-page-1/#comment-72468</link>
		<dc:creator>corrideat</dc:creator>
		<pubDate>Mon, 26 Oct 2009 21:05:37 +0000</pubDate>
		<guid isPermaLink="false">http://blog.zerial.org/?p=1009#comment-72468</guid>
		<description>Otra cosa que no me queda clara es la función de la variable $contenido.</description>
		<content:encoded><![CDATA[<p>Otra cosa que no me queda clara es la función de la variable $contenido.</p>
]]></content:encoded>
	</item>
	<item>
		<title>Por: corrideat</title>
		<link>http://blog.zerial.org/seguridad/como-validar-correctamente-la-descarga-de-un-archivo-en-php/comment-page-1/#comment-72466</link>
		<dc:creator>corrideat</dc:creator>
		<pubDate>Mon, 26 Oct 2009 20:56:35 +0000</pubDate>
		<guid isPermaLink="false">http://blog.zerial.org/?p=1009#comment-72466</guid>
		<description>Francamente no creo que el segundo script resuelva el problema, porque seguirá arrojando un error cuando no exista el fichero.
La comprobación sobre los .., las barras etc. se deberían seguir haciendo aún cuando se use una base de datos, porque ninguna entrada del &quot;usuario&quot; debería ser confiable. Ni siquiera la base de datos. Por ejemplo, podría haber sido comprometida y estar siendo usada para obtener información sensible...
Lo que yo haría es una función que elimine los caracteres no permitidos (en general lo que no es alfanumérico), junto con otra función para la ruta (no es una mala idea usar usar el DOCUMENT_ROOT como un inicio, para no llegar a comprometer a los otros sitios, aún cuando guardáramos en una base de datos el nombre del directorio de descarga) y para verificar la existencia del archivo en primer lugar. Si se necesita seguridad adicional, se podría comprobar el uid/gid del fichero en cuestión.</description>
		<content:encoded><![CDATA[<p>Francamente no creo que el segundo script resuelva el problema, porque seguirá arrojando un error cuando no exista el fichero.<br />
La comprobación sobre los .., las barras etc. se deberían seguir haciendo aún cuando se use una base de datos, porque ninguna entrada del &#8220;usuario&#8221; debería ser confiable. Ni siquiera la base de datos. Por ejemplo, podría haber sido comprometida y estar siendo usada para obtener información sensible&#8230;<br />
Lo que yo haría es una función que elimine los caracteres no permitidos (en general lo que no es alfanumérico), junto con otra función para la ruta (no es una mala idea usar usar el DOCUMENT_ROOT como un inicio, para no llegar a comprometer a los otros sitios, aún cuando guardáramos en una base de datos el nombre del directorio de descarga) y para verificar la existencia del archivo en primer lugar. Si se necesita seguridad adicional, se podría comprobar el uid/gid del fichero en cuestión.</p>
]]></content:encoded>
	</item>
	<item>
		<title>Por: Zerial</title>
		<link>http://blog.zerial.org/seguridad/como-validar-correctamente-la-descarga-de-un-archivo-en-php/comment-page-1/#comment-72243</link>
		<dc:creator>Zerial</dc:creator>
		<pubDate>Tue, 20 Oct 2009 16:33:22 +0000</pubDate>
		<guid isPermaLink="false">http://blog.zerial.org/?p=1009#comment-72243</guid>
		<description>@Jac: Con el ID pueden probar e ir cambiando el ID para descargar otro archivo, si, pero a lo que voy yo, es que con ese &quot;id&quot;, aunque lo cambies, no podras descargar un archivo arbitrariamente, menos que este en otro directorio como /etc.

Sobre lo que preguntas.. proteger un directorio de qe forma? Puedes hacerlo por el htaccess.

saludos</description>
		<content:encoded><![CDATA[<p>@Jac: Con el ID pueden probar e ir cambiando el ID para descargar otro archivo, si, pero a lo que voy yo, es que con ese &#8220;id&#8221;, aunque lo cambies, no podras descargar un archivo arbitrariamente, menos que este en otro directorio como /etc.</p>
<p>Sobre lo que preguntas.. proteger un directorio de qe forma? Puedes hacerlo por el htaccess.</p>
<p>saludos</p>
]]></content:encoded>
	</item>
	<item>
		<title>Por: Jac</title>
		<link>http://blog.zerial.org/seguridad/como-validar-correctamente-la-descarga-de-un-archivo-en-php/comment-page-1/#comment-72238</link>
		<dc:creator>Jac</dc:creator>
		<pubDate>Tue, 20 Oct 2009 14:34:06 +0000</pubDate>
		<guid isPermaLink="false">http://blog.zerial.org/?p=1009#comment-72238</guid>
		<description>Wena, pero con ID igual pueden probar. Si quisiéramos que no hagan una descargar directa podría ser colocando el archivo fuera de la carpeta web y que se sólo accesible desde el archivo para descargar?
Saben si con sesiones php se puede proteger un directorio?
Eso, saludos.</description>
		<content:encoded><![CDATA[<p>Wena, pero con ID igual pueden probar. Si quisiéramos que no hagan una descargar directa podría ser colocando el archivo fuera de la carpeta web y que se sólo accesible desde el archivo para descargar?<br />
Saben si con sesiones php se puede proteger un directorio?<br />
Eso, saludos.</p>
]]></content:encoded>
	</item>
	<item>
		<title>Por: Zerial</title>
		<link>http://blog.zerial.org/seguridad/como-validar-correctamente-la-descarga-de-un-archivo-en-php/comment-page-1/#comment-72208</link>
		<dc:creator>Zerial</dc:creator>
		<pubDate>Sun, 18 Oct 2009 19:18:13 +0000</pubDate>
		<guid isPermaLink="false">http://blog.zerial.org/?p=1009#comment-72208</guid>
		<description>@Josep: Sep, estas en lo correcto. Para evitar eso podrías agregar una validación de que no existan &quot;../&quot; en la variable, pero ya tendrias un código lleno de parches y eso es asqueroso! Mejor hacerlo bien, mediante una query sql (pasando un ID) o derechamente usando el link duro hacia el fichero que deseas descargar.</description>
		<content:encoded><![CDATA[<p>@Josep: Sep, estas en lo correcto. Para evitar eso podrías agregar una validación de que no existan &#8220;../&#8221; en la variable, pero ya tendrias un código lleno de parches y eso es asqueroso! Mejor hacerlo bien, mediante una query sql (pasando un ID) o derechamente usando el link duro hacia el fichero que deseas descargar.</p>
]]></content:encoded>
	</item>
	<item>
		<title>Por: Josep</title>
		<link>http://blog.zerial.org/seguridad/como-validar-correctamente-la-descarga-de-un-archivo-en-php/comment-page-1/#comment-72206</link>
		<dc:creator>Josep</dc:creator>
		<pubDate>Sun, 18 Oct 2009 18:45:56 +0000</pubDate>
		<guid isPermaLink="false">http://blog.zerial.org/?p=1009#comment-72206</guid>
		<description>Apuesto a que en la segunda version puedes pasarle igualmente ../../../passwd por el parametro $_GET[‘archivo’] sin problemas.</description>
		<content:encoded><![CDATA[<p>Apuesto a que en la segunda version puedes pasarle igualmente ../../../passwd por el parametro $_GET[‘archivo’] sin problemas.</p>
]]></content:encoded>
	</item>
</channel>
</rss>

