Mostrando las entradas con la etiqueta Seguridad Web. Mostrar todas las entradas
Mostrando las entradas con la etiqueta Seguridad Web. Mostrar todas las entradas

viernes, 7 de setiembre de 2012

ASP.NET–Detecta las vulnerabilidades de tu aplicacion web

aspnet-attacksUna de las preguntas obligatorias que se hace un desarrollador de aplicaciones es:
“mi aplicación web será vulnerable en algún punto a ataques de delincuentes del ciberespacio?”
Y si no tienes mucha experiencia desarrollando sitios web, pues no tendrás idea por dónde empezar para detectar esas vulnerabilidades.
Y es posible que efectivamente estés haciendo una bomba de tiempo… por eso es necesario que encuentres alguna manera de testear si tu sitio web tiene agujeros de seguridad y puede ser hackeado.
Conforme un desarrollador va adquiriendo más experiencia, va aprendiendo cuáles pueden ser los puntos débiles que puede tener una aplicación web y entonces se preocupa por evitar que vulneren dichos agujeros… y le hará exigentes pruebas hasta encontrar cero vulnerabilidades (eso espero Guio).
Pero mientras tanto qué hacen?
Mientras tanto, pueden apoyarse de herramientas que realizan exámenes en línea, tal como lo hace https://asafaweb.com/
Así es, este web site le hace un examen integral a tu sitio ASP.NET en línea y te entrega un informe completo de las vulnerabilidades que halló en tu web site, y además te dice cómo puedes solucionar dichas fallas, añadiéndote enlaces para que estudies dichas vulnerabilidades y solucionarlas.
https://asafaweb.com/ es una herramienta muy útil, la cual se las recomiendo, al menos en una etapa inicial.
Espero que les sea de utilidad Guio

sábado, 26 de junio de 2010

ASP.NET - Subir y descargar archivos del servidor mediante pagina aspx intermedia

download_file Lo prometido es deuda (lean los comentarios de este otro post), así que vamos con el desarrollo del post.
En esta ocasión vamos a realizar el proceso de:
1.- Guardar, en una carpeta del servidor, archivos, los cuales deben guardarse con otros nombres (nombres autogenerados, por ejemplo: 3F2504E0-4F89-11D3-9A0C-0305E82C3301).

2.- Guardar en la base de datos, el nombre original del archivo y el nuevo nombre.

3.- Recuperar los nombres y rutas de los archivos subidos al servidor y listarlos en un gridview.

4.- Basado en los puntos 2 y 3, permitir descargar los archivos con su original nombre.

Para completar este ciclo voy a crear en la base de datos una tabla llamada document_attachment y los respectivos procedimientos almacenados para la gestión de archivos.
Entonces, este es el script T-SQL que uso para el caso ( una tabla y 3 procedimientos almacenados):
CREATE TABLE [dbo].[document_attachment](
[attachmentid] [int] IDENTITY(1,1) NOT NULL,
[filename] [varchar](250),
[fileguid] [varchar](50),
CONSTRAINT [pk_document_attachment] PRIMARY KEY CLUSTERED 
([attachmentid] ASC)
)
GO
--------------------------------------------------
CREATE PROCEDURE[dbo].[document_attachment_GetAll]
AS

SELECT
[attachmentid],
[filename],
[fileguid]
FROM [dbo].[document_attachment]

GO
--------------------------------------------------
CREATE PROCEDURE[dbo].[document_attachment_Insert]
@attachmentid int output,
@filename varchar(250),
@fileguid varchar(50)

AS
INSERT INTO[dbo].[document_attachment](
[filename],
[fileguid]
)
VALUES(
@filename,
@fileguid
)
SET @attachmentid = SCOPE_IDENTITY()
GO

--------------------------------------------------
CREATE PROCEDURE[dbo].[document_attachment_GetByGuid]
@guid varchar(50)
AS

SELECT
[filename],
[fileguid]
FROM [dbo].[document_attachment]
WHERE [fileguid] = @guid
--------------------------------------------------
Antes de pasar al código ASP.NET, les recomiendo que guarden la cadena de conexión a la base de datos en el web config (para el ejemplo está sin encriptar, …pero uds deben encriptarlo)

<connectionStrings>
<add name="DB" connectionString="server=.\SQLEXPRESS;database=my_database;uid=sa;pwd=xxxxxxxxxxxxxxx" />
</connectionStrings>

Otra cosa, deben crear una carpeta llamada Uploads (en la raiz de su aplicación), que es donde se guardarán los archivos que se suben… a esta carpeta hay que darle permisos de lectura/escritura al usuario SERVICIO DE RED.
uploads_folder

Ahora sí, necesitamos dos páginas aspx:
1.- Uploader.aspx, que es la página que permite subir los archivos al servidor e, inmediatamente después actualiza el contenido del gridview con los archivos subidos.

2.- Downloader.aspx, que es la página intermedia para descargar archivos… gracias a esta página podemos evitar que el usuario sepa desde qué carpeta se descargan los archivos y además en el código de esta página pueden hacer las verificaciones que quieran antes de permitirle al usuario descargar el archivo. Tú me preguntarás: puedo usar un archivo ashx (que es más ligero) en lugar de una pagina aspx para descargar? la respuesta es sí.

Este es el código completo:
Uploader.aspx
uploader

<!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>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div style="width: 350px; background-color: #f2ceea; padding: 10px; margin: 20px">
Seleccione archivo:<asp:FileUpload ID="FileUpload1" runat="server" />
<hr />
<asp:Button ID="btnUpload" runat="server" Text="Guardar archivo" />
</div>
<asp:GridView ID="griddocument_attachment" BackColor="lightgreen" Width="400px" runat="server"
AutoGenerateColumns="False" DataKeyNames="fileguid" HeaderStyle-HorizontalAlign="Left"
HeaderStyle-VerticalAlign="Top" RowStyle-VerticalAlign="Top">
<Columns>
<asp:TemplateField HeaderStyle-Width="3%">
<ItemTemplate>
<asp:Image ID="Image1" ImageUrl="~/images/file.png" runat="server" />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Archivo">
<ItemTemplate>
<%# Eval("filename")%>
                </ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Descargar" HeaderStyle-Width="5%">
<ItemTemplate>
<asp:HyperLink ID="hplAttachment" Text='<%# Eval("filename")%>' NavigateUrl='<%# String.Format("~/Downloader.aspx?guid={0}", Eval("fileguid")) %>'
ImageUrl="~/images/download.png" runat="server"></asp:HyperLink>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>    
</form>
</body>
</html>

En el gridview, el hyperlink con la imagen download.png es quien tiene el enlace de descarga, parecido a esto:
http://localhost/Test_UI/Downloader.aspx?guid=ee4a00fa-cfa9-490e-a65c-12d652fd2c00

código VB.NET:
Imports System.Data
Imports System.Data.SqlClient

Partial Public Class Uploader
Inherits System.Web.UI.Page

Private GlobalDBConnection As String = ConfigurationManager.ConnectionStrings("DB").ConnectionString
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If IsPostBack Then Return

document_attachment_GetAll()

End Sub

Protected Sub btnUpload_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnUpload.Click
If Not FileUpload1.HasFile Then Return

Dim fileguid As String = Guid.NewGuid.ToString
Dim FileName As String = FileUpload1.FileName

Try
FileUpload1.SaveAs(Server.MapPath("./Uploads/") & fileguid)
Catch
'error....
Return
End Try

Dim i As Integer = document_attachment_Insert(FileName, fileguid)
If i = 0 Then
'error....
Else
document_attachment_GetAll()
End If

End Sub

Sub document_attachment_GetAll()
Dim connection As New SqlConnection(GlobalDBConnection)
Dim command As New SqlDataAdapter("document_attachment_GetAll", connection)
command.SelectCommand.CommandType = CommandType.StoredProcedure

Dim dt As New DataTable()
command.Fill(dt)

griddocument_attachment.DataSource = dt
griddocument_attachment.DataBind()

End Sub

Function document_attachment_Insert(ByVal filename As String, ByVal fileguid As String) As Integer
Dim connection As New SqlConnection(GlobalDBConnection)
Dim command As New SqlCommand("document_attachment_Insert", connection)
command.CommandType = CommandType.StoredProcedure

Dim p_attachmentid As New SqlParameter("@attachmentid", SqlDbType.Int)
p_attachmentid.Direction = ParameterDirection.Output
command.Parameters.Add(p_attachmentid)
command.Parameters.AddWithValue("@filename", filename)
command.Parameters.AddWithValue("@fileguid", fileguid)

command.Connection.Open()
Try
command.ExecuteNonQuery().ToString()
Catch
Return 0
Finally
command.Connection.Close()
End Try

If Not IsDBNull(p_attachmentid.Value) Then
Return CInt(p_attachmentid.Value)
Else
Return 0
End If
End Function

End Class

Downloader.aspx
 en el lado aspx tiene absolutamente nada, excepto el tag Page:
<%@ Page Language="vb" …………………………………………………… %>
 código VB.NET:
Imports System.Data
ImportsSystem.Data.SqlClient

Partial Public Class Downloader
Inherits System.Web.UI.Page

Private GlobalDBConnection As String= ConfigurationManager.ConnectionStrings("DB").ConnectionString
Protected SubPage_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim guid As String= Request.QueryString("guid")

If String.IsNullOrEmpty(guid) Then Return

' aquí puedes poner las validaciones que quieras

'............   ....................

Dim dt As DataTable = document_attachment_GetByGuid(guid)
If dt.Rows.Count = 0 Then Return

Dim
OriginalFileName As String= dt.Rows(0)("filename")
 DownloadFile(Server.MapPath("./Uploads/") & guid, OriginalFileName)
End Sub

Public Sub
DownloadFile(ByVal FilePath As String, ByVal OriginalFileName As String)
Dim fs As IO.FileStream = Nothing

'obtenemos el archivo del servidor
fs = IO.File.Open(FilePath, IO.FileMode.Open, IO.FileAccess.Read)
Dim byteBuffer(CInt(fs.Length - 1)) As Byte
fs.Read(byteBuffer, 0, CInt(fs.Length))
 fs.Close()

Using ms As New IO.MemoryStream(byteBuffer)
'descargar con su nombre original
Response.AddHeader("Content-Disposition", "attachment; filename=" & OriginalFileName)
 ms.WriteTo(Response.OutputStream)
End Using

End Sub

Function
document_attachment_GetByGuid(ByVal guid As String) As DataTable
Dim connection As New SqlConnection(GlobalDBConnection)
Dim command As New SqlDataAdapter("document_attachment_GetByGuid", connection)
 command.SelectCommand.CommandType = CommandType.StoredProcedure
 command.SelectCommand.Parameters.AddWithValue("@guid", guid)
Dim dt As New DataTable()
 command.Fill(dt)

Return dt
End Function

 End Class


ACTUALIZACIÓN:
Debido a las preguntas que constantemente estoy recibiendo acerca de este post, veo que no ha quedado muy claro... entonces, estoy añadiendo el proyecto completo para que lo descarguen y lo analicen con más calma. 
Debido a que estoy incluyendo la base de datos en la carpeta app_data, lo único que tendrían que modificar en el we.config antes de correr el proyecto es el nombre del servidor de su bd... osea reemplacen .\SS2008 por el nombre del servidor que Uds le hayan puesto.
Es todo, espero que les sea de utilidad.
 ;)

lunes, 21 de junio de 2010

ASP.NET - Expresiones regulares para contraseñas seguras

form_validate_re El tema de crear una política de constraseñas seguras para los aplicativos es un tema de amplia discusión en las empresas.
Hay ocasiones en los que simplemente se le crea una cuenta a un usuario y se le asigna una contraseña segura, luego este usuario puede cambiar esa contraseña… pero igual debe elegir una contraseña segura.
Y este es el asunto, no todos los usuarios quieren trabajar con contraseñas seguras. Tú dirás:
Se les obliga a usar contraseñas seguras y punto, pero eso no siempre funciona en la vida real.
Muchas veces los dueños de la empresa o la alta dirección quieren usar el password de toda su vida. Tú puedes hacer denodados esfuerzos: les explicas con ejemplos, con videos, con pruebas, etc… hasta que al fin los convences… luego de tu gran esfuerzo te dicen:
pata, yo quiero seguir usando mi viejo password ya?
Qué te queda? renegar y acatar la orden (previo: Yo se lo advertí!!).
Pero como nosotros estamos del lado de los sensatos, vamos a invertir nuestro tiempo creando una funcionalidad que nos genera una expresión regular para exigir contraseñas seguras, basado en las condiciones que elijas.
Código aspx:
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<style type="text/css">
*
{
font-family: Verdana, Arial;
font-size: 11px;
height: 21px;
}
table
{
border-collapse: collapse;
background-color: Orange;
}
th
{
background-color: Gray;
color: White;
font-size: 13px;
}
th, td
{
padding: 5px;
white-space: nowrap;
}
</style>
</head>
<body>
<form id="form1" runat="server">
<table>
<tr>
<th>
Expresiones Regulares para contraseñas seguras
</th>
</tr>
<tr>
<td>
<asp:CheckBox ID="chkUpper" runat="server" Text="Incluir mayúsculas" />

</td>
</tr>
<tr>
<td>
<asp:CheckBox ID="chkLower" runat="server" Text="Incluir minúsculas" />

</td>
</tr>
<tr>
<td>
<asp:CheckBox ID="chkDigits" runat="server" Text="Incluir dígitos" />
</td>
</tr>
<tr>
<td>
<asp:CheckBox ID="chkSpecialChars" runat="server" Text="Incluir Caracteres especiales (!@#$%^&amp;*_+-/)" />
</td>
</tr>
<tr>
<td>
<strong>Longitud</strong>
<br />
Mínima: &nbsp;<asp:TextBox ID="txtMin" runat="server" Width="54px"></asp:TextBox> 
<br />
Máxima: <asp:TextBox ID="TxtMax" runat="server" Width="54px"></asp:TextBox>  
<br />
Nota: Si desean una longitud exacta, pongan la misma longitud en ambos textboxes              
</td>
</tr>
<tr>
<td style="text-align: right">
<asp:Button ID="btnGenerate" runat="server" Text="Generar Expresión Regular" />
</td>
</tr>
<tr>
<td style="text-align: center">
<asp:TextBox ID="txtRegularExpression" Width="95%" Rows="5" TextMode="MultiLine"
runat="server"></asp:TextBox>
</td>
</tr>
</table>

<div style="background-color: yellow; margin-top: 30px; height: 70px; width: 500px">
Haga sus pruebas aquí:
<br />
Texto a validar: <asp:TextBox ID="TextBox1" ValidationGroup="test" runat="server"></asp:TextBox>
<asp:RegularExpressionValidator ID="RegularExpressionValidator1" ValidationGroup="test" runat="server" 
ControlToValidate="TextBox1" ValidationExpression=""
ErrorMessage="*"></asp:RegularExpressionValidator>
<asp:Button ID="Button1" runat="server" ValidationGroup="test" Text="Validar expresión..." />
</div>

</form>
</body>
</html>

Código VB.NET:

Protected Sub btnGenerate_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnGenerate.Click
Dim RegExp As New StringBuilder

'longitud
If txtMin.Text.Length > 0 AndAlso IsNumeric(txtMin.Text) Then
RegExp.Append("(?=^.{" & txtMin.Text)

If txtMin.Text <> TxtMax.Text Then
RegExp.Append(",")
If TxtMax.Text.Length > 0 AndAlso IsNumeric(TxtMax.Text) Then
RegExp.Append(TxtMax.Text)
End If
End If

RegExp.Append("}$)")
End If

'dígitos
If chkDigits.Checked Then RegExp.Append("(?=.*\d)")

'caracteres especiales
If chkSpecialChars.Checked Then RegExp.Append("(?=.*\W+)")

'mayúsculas
If chkUpper.Checked Then RegExp.Append("(?=.*[A-Z])")

'minúsculas
If chkLower.Checked Then RegExp.Append("(?=.*[a-z])")

RegExp.Append(".*$")

txtRegularExpression.Text = RegExp.ToString
RegularExpressionValidator1.ValidationExpression = RegExp.ToString

End Sub

Es todo, el código está completo, sólo añadan una página aspx y peguen el código respectivo. Luego ejecuten la página, y marquen algunas de las opciones… presionen el botón Generar Expression Regular y la expresión se mostrará en la caja de texto mostrada, Uds pueden usar esta funcionalidad para generar las expresiones regulares que luego le asignarán a su control  asp:RegularExpressionValidator

Aprovecho para recomendarles una herramienta imprescindible para construir / validar expresiones regulares: Expresso.

Como para finalizar el post, te dejo un enlace que genera contraseñas seguras, como para que te ahorres el uso de neuronas generando contraseñas: http://strongpasswordgenerator.com/

;)

lunes, 14 de junio de 2010

ASP.NET - Pagina intermedia para descargar archivos

Bien, vamos a suponer que ya hemos subido varios archivos al servidor y que están guardados por separado en varias carpetas.
Ahora, resulta fácil poner un link al archivo de manera que puedan descargarlo, correcto? por ejemplo, digamos que tenemos una carpeta llamada Uploads dentro de la carpeta donde se aloja nuestra aplicación web… y dentro de la carpeta Uploads hay subcarpetas con archivos que hemos ido  subiendo… por ejemplo:
Uploads\Documents\Excel1.xls
Uploads\Documents\Excel2.xls
Uploads\KB\Excel3.xls
Uploads\KB\Excel4.xls

La manera más fácil de poner a disposición estos archivos, es poner links como éstos:
http://www.midominio.com/uploads/documents/excel1.xls
http://www.midominio.com/uploads/KB/excel3.xls

Pero, estoy creando agujeros de seguridad, sin querer estoy diciéndole a todos mis usuarios (en voz alta): POR SI ACASO, TODOS LOS ARCHIVOS IMPORTANTES Y CONFIDENCIALES QUE NADIE DEBE REVISAR ESTÁN EN LA CARPETA UPLOADS/DOCUMENTS AH?, REPITOOOOOOOOOO EN  LA CARPETA UPLOADS/DOCUMENTS… ASÍ QUE YA SABEN, NO TOQUEN NADA.
Obviamente, nadie te va a hacer caso y al poco tiempo ya tendrías que estar buscando otro trabajo ;)
Pero como aquí queremos que conserves tu trabajo, te vamos a enseñar cómo deberías construir los enlaces para distribuir archivos a descargar, sin delatar la verdadera ruta del archivo.

Otra práctica que recomiendo es guardar el archivo con otro nombre y sin extensión, sólo con un codigo generado… esto me permite guardar subir varios archivos con el mismo nombre sin tener que preocuparme por ello… dado que el verdadero nombre se guarda en una tabla y se le restituye ese nombre al momento de descargar el usuario.

Nota: vamos a asumir que uds, queridos lectores, ya guardan los archivos con otro nombre y que para ello usan una tabla como ésta en la bd:
filetable
si no les parece claro, me lo indican en un comentario y a ver si hacemos un post al respecto.
Ahora sí, empecemos con los pasos para descargar archivos:
Paso 1.- Crear una clase llamada Upload.vb, y dentro de ella una enumeración con los distintos módulos que manejan descarga de archivos en mi sistema:
Public ClassUpload

Public EnumType
Document = 1
KB = 2
End Enum

End Class

Paso 2.- Cada vez que construya una url para descargar archivos, debe seguir este formato:
http://www.midominio.com/downloader.aspx?type=1&guid=927826ff-2a59-48ac-a38d-272e64f78658

donde el parámetro type representa el tipo de archivo, en este caso 1, osea que vamos a descargar un archivo de tipo Documento.

Luego, el parámetro guid es el identificador del archivo. Asimismo, este identificador me permitirá recuperar el nombre del archivo.

Paso 3.- Añadir una pagina aspx adicional llamada Downloader.aspx, que contenga el siguiente código:




Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim type As String = Request.QueryString("type")
If String.IsNullOrEmpty(type) Then Return
If Not
IsNumeric(type) Then Return

Dim
guid As String = Request.QueryString("guid")
If String.IsNullOrEmpty(guid) Then Return

Dim
Folder As String = String.Empty

Dim dt As New DataTable


Select Case type
Case Upload.Type.Document
'Recupero de la bd, basado en el parámetro guid
dt = document_attachment.GetByGuid(guid)
'indico cómo se llama el folder donde se encuentra el archivo
Folder = "Document"


Case Upload.Type.KB
'Recupero de la bd, basado en el parámetro guid
dt = KB_attachment.GetByGuid(guid)
'indico cómo se llama el folder donde se encuentra el archivo
Folder = "KB"
End Select


If dt.Rows.Count = 0 Then Return
'este es el nombre guid
Dim OldFileName As String = dt.Rows(0)("fileguid")
'éste es su original nombre
Dim OriginalFileName As String = dt.Rows(0)("filename")
'descargo el archivo
DownloadFile(Server.MapPath("~") & "\Uploads\" & Folder & "\" & OldFileName, OriginalFileName)
End Sub


Public Sub DownloadFile(ByVal FilePath As String, ByVal OriginalFileName As String)


Dim fs As IO.FileStream = Nothing

'obtenemos el archivo del servidor
fs = IO.File.Open(FilePath, IO.FileMode.Open, IO.FileAccess.Read)

Dim byteBuffer(CInt(fs.Length - 1)) As Byte
fs.Read(byteBuffer, 0, CInt(fs.Length))
fs.Close()

Using ms As New IO.MemoryStream(byteBuffer)
'descargar con su nombre original
Response.AddHeader("Content-Disposition", "attachment; filename=" & OriginalFileName)
ms.WriteTo(Response.OutputStream)
End Using

End Sub

Es todo, espero que les sea de utilidad ;)

viernes, 11 de julio de 2008

Nivel de confianza Medium en ASP.NET - II

Decíamos en el anterior post que la manera recomendada de hostear múltiples aplicaciones ASP.NET sobre un servidor compartido era configurando el nivel de confianza a Medium. Esto, hay que decirlo, limita el uso de los recursos a los que se puede acceder... por ejemplo:
--No se puede acceder al proveedor de datos administrado ADO.NET OLEDB para acceder a bases de datos.
--No se puede acceder al log de eventos de Windows.
--No se puede usar reflection.
--No se puede acceder al registro de Windows.
--Sólo se puede comunicar con direcciones web externas especificadas en el elemento [trust] del web.config.
--Sólo se puede acceder a archivos que están dentro del directorio virtual de la aplicación.

Esas son las limitaciones, pero no es el fin del mundo... como ves también tiene muchos beneficios... y es que no podrán eliminarse tu aplicación web, ni hurgar en ella.
En realidad, decir que no se puede acceder al registro, ni al log de windows, etc...es mentir, sí se puede... a través de los que se llama políticas personalizadas. Sigue leyendo para que entiendas.

Digamos que tu aplicación necesita acceder a una base de datos ACCESS, para ello habría que usar OLEDB cierto?
pero hemos dicho que en un nivel de confianza Medium no se puede acceder a OLEDB... les mentí.... sí se puede... pero no por default, hay que crear una política personalizada del nivel Medium.
Veamos cómo se crea una política personalizada que lo haga:
1.- Ve a la ruta %windir%\Microsoft.NET\Framework\{Version}\CONFIG y copia el archivo web_MediumTrust.config... luego pégalo en la misma carpeta, ponle otro nombre... digamos oledb_mediumtrust.config
2.- Abre el archivo, fíjate que hay una sección [SecurityClasses], y dentro de ella están los elementos [SecurityClass... ahí debes añadir
[SecurityClass Name="OleDbPermission" Description="System.Data.OleDb.OleDbPermission, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/]
3.- Luego, busca el elemento [NamedPermissionSets], dentro hay elementos [PermissionSet... allí debes añadir
[IPermission class="OleDbPermission" version="1" Unrestricted="true"/]

4.- Ahora modifica el archivo web.config que está en esa misma carpeta, añadiremos la nueva política personalizada que acabamos de crear. Para ello nos vamos a la zona del elemento [securityPolicy] y añadimos el trustLevel de name = CustomOleDB, referenciamos el archivo copiado y renombrado inicialmente, así quedaría:

[securityPolicy]
[trustLevel name="Full" policyFile="internal"/]
[trustLevel name="High" policyFile="web_hightrust.config"/]
[trustLevel name="Medium" policyFile="web_mediumtrust.config"/]
[trustLevel name="Low" policyFile="web_lowtrust.config"/]
[trustLevel name="Minimal" policyFile="web_minimaltrust.config"/]
[trustLevel name="CustomOleDB" policyFile="oledb_mediumtrust.config" /]
[/securityPolicy]


5.- Nada más, acabamos de crear una política personalizada... ahora para usarlo desde tu aplicación web, simplemente pones en tu web.config lo sgte:
[trustLevel = "CustomOleDB" /]

Papayita verdad??
Eso es todo, para despedirme quería recordarles algo: si Ud quiere comprobar si su aplicación está preparada para desenvolverse al 100% en un ambiente Medium, haga las pruebas necesarias en su servidor de pruebas... para esto sólo añade a tu web.config:
[trust level="Medium" originUrl="" /]

domingo, 6 de julio de 2008

Nivel de confianza Medium en ASP.NET - I

Podemos decir que los niveles de confianza (Trust levels) se refieren a los permisos que una aplicación web ASP.NET tiene desde/sobre la computadora que hace de servidor web. Osea, qué puedes hacer y qué no puedes hacer.

Estos niveles de confianza se configuran en la máquina que hace de servidor web, en un archivo llamado web.config... el cual usualmente está ubicado en %windir%\Microsoft.NET\Framework\{version}\CONFIG, y como es de suponerse hay varios niveles de confianza. Estos niveles de confianza se especifican en el elemento trust del web.config, y son los sgtes:
-Full
-High
-Medium
-Low
-Minimal

No voy a explicar cada uno de ellos porque para eso basta y sobra documentación en Internet. Lo que sí haremos es una tertulia sobre el tema y algún qué, cómo y por qué al respecto.

Digamos que el nivel de confianza está configurado a Full, entonces no habrían restricciones... por lo tanto la aplicación ASP.NET tendría acceso ilimitado a los recursos de esa computadora que hace de servidor, como manipular archivos fuera del directorio virtual o leer /escribir en el registro... y el acceso a los recursos serían solamente restringidos por las políticas de seguridad del propio sistema operativo.

Como es obvio, sería raro que algún proveedor de hosting compartido estuviera tan loco para permitir Full acceso a su servidor... podrían ocurrir catástrofes, por ejemplo una de las aplicaciones ASP.NET hosteadas podría tener un código malicioso que les permite obtener las cadenas de conexión a la base de datos de las otras aplicaciones ASP.NET o inclusive eliminar archivos fuera de su directorio... se puede hacer eso? sí.

Entonces, lo que usualmente hacen los proveedores de hosting es asignar un nivel de confianza Medium, con lo que se aseguran que cada aplicación ASP.NET tenga control sólo sobre su carpeta alojada y acceso restringido a ciertos recursos del sistema... como el servidor SQL SERVER, el GAC, el log de windows, consultas http fuera del dominio, etc.

Nosotros, nos estamos enfocando principalmente en el nivel de confianza Medium, porque es básicamente el que nos importa conocer más a profundidad y porque es el exigido por los proveedores de hosting compartido.

Vamos a continuar con este tema en el próximo post.

viernes, 13 de junio de 2008

ASP.NET - Encriptar el web.config - II

Hemos visto en este previo post lo fácil que resulta encriptar la sección connectionStrings del web.config...

Esta es una excelente manera de ocultar nuestra información a los malvados... claro!! si alguien logra hurtar nuestro web.config y luego intenta decriptarlo desde otra PC: no podrá hacerlo!! porque la encriptación se hizo utilizando identificadores únicos de la PC inicial.... jojolete!!

La única forma de revertir el proceso de encriptado sería ejecutar esta sentencia desde la línea de comandos (y lógicamente en la PC original):
aspnet_regiis -pd "connectionStrings" -app "/Tests2008"

Eeeeeeeexacto, lo único que ha cambiado es un parámetro... quitamos -pe y pusimos -pd

De esta manera nuestras connectionStrings del web.config retornarían a su estado inicial (osea, no encriptado).

Todo bien? todos contentos? siiiiiiiiiiiiiiiii... excellent!!
qué pasa niño Juanito? por qué pone puchero?
Juanito: es que mi proveedor de hosting nunca me va a dejar manipular la línea de comandos... por lo tanto no podré encriptar mi web.config... buuuuuuuu buuuuuuuu...

Tranquilo niño Juanito... todo tiene solución... para casos como el tuyo hay otras formas de encriptación al web.config...


Entonces haremos lo mismo pero de otra manera... presten atención,

1.- Añadimos una página llamada encriptar.aspx... y le añadimos dos botones:
btnEncriptar y btnDesencriptar, los cuales encriptarán y desencriptarán el web.config respectivamente...
Previamente hay que importar los espacios de nombres:
Imports System.Configuration
Imports System.Web.Configuration












Y eso es todo, nada del otro mundo.

martes, 10 de junio de 2008

ASP.NET - Encriptar el web.config - I

En el web.config guardamos información muy sensitiva, digamos la cadena de conexión a la base de datos, otras veces la lista de usuarios con que se puede acceder a la aplicación, y así sucesivamente... y obviamente debemos darle toda la seguridad del caso.

Ante este tipo de información hay que extremar la medidas de seguridad, si bien es cierto que desde el browser no es posible que te hurten la información del web.config, también es cierto que no es la única manera de que lo obtengan.
A través de FTP pueden descargarse sin problemas el web.config... y para ello sólo se necesita un descuido de tu parte.

La pregunta es: Cómo protejo mi web.config?
Hay varias formas... una de ellas puede ser tener un web.config que simplemente haga referencia a archivos de configuración externos (fuera del directorio virtual), estos archivos de configuración externos guardarán la información sensitiva de manera más segura. Este tema se ha abordado en
previos post.

Otra manera es encriptando la información sensitiva del web.config. Pareciera que esta tarea fuera muy difícil... nada de eso!!! es lo más simple del mundo, veamos:


Digamos que tienes una aplicación web llamada "Tests", ubicada en la siguiente ruta: G:\Inetpub\wwwroot\Tests
Y esta aplicación web guarda en su web.config esta cadena de conexión:








Vamos a empezar encriptando esta cadena de conexión, para eso hacemos lo sgte:

1.-Abrimos la línea de comandos y nos movemos de directorio, vamos a la carpeta v2.0.50727 (porque estamos trabajando con el framework 2.0 para adelante), así debe quedar:







2.- Ahí Escribimos
aspnet_regiis -pef "connectionStrings" "G:\Inetpub\wwwroot\Tests"

o
aspnet_regiis -pe "connectionStrings" -app "/Tests"
Hay que escribir "connectionStrings" tal como se ve... con S mayúscula, sino no reconocerá la orden.

Y presionamos enter, esta sentencia encriptará la sección "connectionStrings" del web.config
El resultado será algo similar a esto:














Si hubiéramos querido encriptar la sección appSettings del web.config... pues hacíamos igual que el ejemplo de arriba... sólo que reemplazábamos la palabra "connectionStrings" x "appSettings".


Nota: la operación de encriptar el web.config se debe realizar sobre la misma máquina de producción... ya que si encriptas el webconfig en una PC y luego la subes encriptada a otra PC: No funcionará... porque el algoritmo de encriptación usa algunos identficadores únicos de la PC para el encriptado... lo cual impedirá que se pueda leer desde otra PC.

Para recuperar la cadena de conexión no hay que hacer magia... no hay que decriptar nada, leyeron?? repito: no hay que decriptar nada... el framework lo hará por nosotros de manera automática... entonces para recuperar la cadena de conexión simplemente hacemos esto:




Esto tiene para rato... la seguimos en el próximo post:
Encriptar el web.config II

viernes, 3 de agosto de 2007

Inyecciones HTML (XSS) - IV

Me ha dado un remordimiento terrible de conciencia:
"No creo que sea buena idea enviar un XSS a nuestros amigos". No lo haremos.Mas bien les explicaré cómo evitar caer en una trampa XSS. Ojo que no hay una única manera de inyectar XSS.

Dado que cada página web tiene diferente código HTML, cada XSS se construye de manera diferente... luego de un cuidadoso examen al HTML que contiene una página.
Las páginas más atacadas son precisamente las de login, osea las que se usan para entrar a un sitio web.

Para que en una página funcione el XSS inyectado, debemos confirmar que el código inyectado se ha ubicado dentro de las etiquetas FORM y, además debemos reconocer los nombres de los controles que nos interesa obtener su información, en este caso: txtUser y txtPwd. Observe la imagen: Ya que el atacante intentará robar el usuario y password, chequeen este XSS:





Exacto... lo que hace este XSS es cerrar el tag FORM original y crear un nuevo tag FORM.Si te das cuenta, el tag FORM no ha cambiado mucho,,, simplemente se le ha añadido un poco de código javascript, el cual se deberá ejecutar cuando el usuario presione el botón Submit.





Pero, qué hace exactamente ese código javascript?
Primero crea un objecto imagen al vuelo y luego para mostrar una imagen en ella, realiza una petición silenciosa al sitio
http://www.SitioHackeador.com/ ... al pedir la imagen está pasándole el nombre del usuario y su password sin que éste lo note.
Ahora, para que esto funcione, previamente a tu correo debería llegarte la invitación a que te loguees desde un sitio web que cotidianamente visitas... como ya les había mencionado anteriormente.Una url más o menos así:








Nota que la url es tremendamente extensa, por lo cual dificilmente te darías cuenta que ese sitio web frecuentemente visitado por ti, incluye en su url... una inyección HTML.


Estas invitaciones funestas que llegan a nuestros correos casi diariamente, siempre terminan haciendo caer por lo menos a una persona de tantas que reciben el email.


Lo desastroso de todo esto es que una persona, si no examina la url cuidadosamente, nunca se dará cuenta que fue timada... ya que él se logueará en el sitio web de manera legítima y correcta e ingresará al sitio conocido... y nunca sabrá que sus datos fueron hurtados.


Cómo nos libramos de los ataques por inyección HTML?


Para el desarrollador de sitios web:
-Chequear cuidadosamente la data ingresada por el usuario en las cajas de texto.
-Todos los caracteres no alfanuméricos deben ser convertidos a caracteres HTML.
-Contínuo testeo.
Para los usuarios de los sitios web:
-Desactivar los lenguajes script de los browsers.


Pero esto no siempre da resultado porque no funcionaría como en el caso que les planteé hoy ( de reemplazar el tag FORM).


-Cuando se trate de visitar un sitio web, lo mejor es acceder directamente desde el browser y no pinchando en un link que insperadamente recibimos vía email o, en todo caso... debemos examinar el link con mucho cuidado.
Les dejo un sitio como ejemplo (para que practiquen):

jueves, 26 de julio de 2007

Inyecciones HTML (XSS) - III

Como les decía en el post anterior:

"No has logrado ingresar a un sitio web porque olvidaste el password, pero has notado algo muy peculiar en esa página".
Y cuál es ese algo muy peculiar?


Pues que cada vez que escribes algo en un control html... éste luego pasa a formar parte del contenido de la página web, cierto?

Ciertoooooooooo!! oye tienes razón!!, hace un rato puse como usuario 'XXX' y luego que presioné el botón ingresar, había un mensaje dentro de la página que decía "Bienvenido XXX".

Luego, si yo erraba el password, se mostraba un texto en rojo sobre la página web que me decía que el password 'xyz' que acababa de ingresar no era válido.

Qué significa todo esto?

Que si un developer no ha validado los textos que puede ingresar un usuario... entonces tiene un hueco de seguridad, y, además, si tú logras ejecutar un script allí... entonces decimos que estamos realizando un ataque XSS o inyección HTML.

Vamos a crear un caso similar y bastante simple, cuya finalidad será mostrar otro ataque XSS.

Imagina que un usuario intenta ingresar a un sitio web, pero no recuerda su usuario ni/o password.
Debido a esto, recibe un mensaje que dice: "datos incorrectos, inténtelo de nuevo."

Lo peculiar es que este mensaje se muestra en la url, algo así:
http://www.misitioweb.com/login.asp?msg=datos%20incorrectos,%20intentelo%20de%20nuevo
Y tú deduces, "si la página web me está mostrando un mensaje que estaba en la url... entonces, si yo cambio el mensaje en la url... hmmm.... será??"

Y todo curioso, modificas la url a esto:


Te imaginas el resultado:
una mensaje de alerta que dice "XSS",
Eureka!! otro hueco donde inyectar XSS...
cómo?? digo esteeeee, qué mal... hay que corregir esto jeje.

Ahora crearemos un ataque XSS, armaremos un XSS bien bonito y, se lo enviaremos a nuestros mejores amigos.

Pero eso será en la próxima entrega.

Inyecciones HTML (XSS) - iii

Chau.

sábado, 21 de julio de 2007

Inyecciones HTML (XSS) - II

Hola, les decía en el anterior post que...
sí había forma de que roben tu información y de que te logren engañar con el XSS.
Cómo así?
Es que el XSS opera sobre el sitio web original. No sobre dominios desconocidos.

Quiero decir que sería posible que un día te llegue un correo de Microsoft comunicándote que acabas de ganar el premio mayor del Imagecup (por poner un ejemplo) y, que lo único que tienes que hacer es confirmar tus datos accediendo al link que te adjuntan.
Nuevamente, tú astutamente pasas el mouse sobre el link y... diablos ¡Es cierto! es de Microsoft ese link... es una dirección web de microsoft...YEEEEEE!!! he ganado!!! gané!! gané!! mamá, papá abuela, por fin compraremos el terrenito en las Casuarinas!!!
uuuuuuuuuuun momento... pero si yo nunca participé!!... hmmm... se habrán confundido?? sí, eso debe ser...
no importa, cobraré el premio y, la culpa es de ellos... no les dolerá perder unos miles de dólarillos, verdad?
y pink... presionas el link y vas a la página web para confirmar tus datos y, confirmas tus datos y,(música melancólica) se jodió todo... le estás dando tus datos a los amigos de lo ajeno.
Acabas de ser una víctima del XSS.
Tú me dirás... en qué momento me pueden haber robado la información? si el link era de Microsoft?

Verás...(para esto hay que saber un poquito de HTML y un poquito de javascript)
Muchos sitios web le dan al usuario la opción de ingresar data en un formulario y, según esa data, devuelven una respuesta.
Ejemplo: si tú escribes XXX, el resultado podría ser "Bienvenido XXX", me entiendes?
Esto puede parecer una cosa inofensiva, pero no lo es: es el punto de entrada para los XSS...

Imagina que el usuario en lugar de escribir XXX... escribe


... entonces, como el browser reconoce el javascript generará un mensaje javascript que dirá "Habla sanazo!!" vamos bien?
Otro ejemplito: está intentando loguearte en un sitio web y, no recuerdas tu password... y por cada intento que haces, se muestra un texto en rojo en la página que dice: "la contraseña ZZZ es incorrecta, inténtalo de nuevo".

Has fracasado en tus 80 intentos de ingresar al sitio web, y no lograste ingresar, pero te has dado cuenta de algo...verdad?
La seguimos en la próxima.

Inyecciones HTML (XSS) - ii

Chau.