En la anterior entrega (Protección de archivos con ASP.NET 2 y IIS 6), vimos que a partir de IIS 6, es posible proteger archivos que no son procesados directamente por ASP.NET; si bien es cierto que este método es fácil de implementar, tiene el inconveniente que en hostings compartidos es difícil o imposible hacer eso ya que generalmente no se tiene acceso a la configuración de IIS.
Otra forma de proteger la descarga de archivos de usuarios anónimos, es crear una página intermedia que antes de entregar los contenidos de éstos, realice las validaciones pertinentes al usuario que hace la petición. Para evitar que los usuarios descarguen directamente los recursos protegidos (por si conocen la ruta) es mejor que éstos estén ubicados en lugares no accesibles directamente desde el navegador (Ejemplo: App_Data
o el directorio padre de la aplicación).
El siguiente ejemplo, ilustra de manera básica como proteger los archivos que están ubicados en App_Data\Protected
:.
Inherits="_Default" Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Download</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Label ID="messageLabel" runat="server"></asp:Label>
<asp:Repeater ID="filesRepeater" runat="server">
<HeaderTemplate>
<ul>
</HeaderTemplate>
<ItemTemplate>
<li><a href='?file=<%# HttpUtility.UrlEncode(Container.DataItem.ToString()) %>'><%# Container.DataItem %></a></li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
</div>
</form>
</body>
</html>
using System.IO;
using System.Web;
public partial class _Default : System.Web.UI.Page
{
readonly static string basePath = HttpContext.Current.Server.MapPath("~/App_Data/Protected");
protected void Page_Load(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(Request.Params["file"]))
{
DownloadFile(Request.Params["file"]);
}
LoadFiles();
}
void LoadFiles()
{
string[] files = Directory.GetFiles(basePath);
for (int i = 0; i < files.Length; i++)
{
files[i] = Path.GetFileName(files[i]);
}
filesRepeater.DataSource = files;
filesRepeater.DataBind();
}
void DownloadFile(string file)
{
}
}
Al implementar este tipo de cosas, hay que validar bien el archivo a descargar, puesto que por un descuido, podemos hacer que el código de nuestra aplicación esté disponible a todo el mundo. 🙂