miércoles, agosto 30, 2006

El WEB.CONFIG

Vamos a darle un vistaso al webconfig de asp.net 2.


<?xml version="1.0"
?>
<configuration>
<connectionStrings>
<!-- En esta seccion como podemos ver podemos definir todas las cadenas de conexion que necesitemos para accesar a las bases de datos, cabe mencionar la forma en la que estoy llamando al server, ya que lo hago especificando el protocolo, la ip y el puerto por el cual estoy accediendo al servidor de SQL, esto es ya que me he topado con problemas con aplicaciones de asp.net2 que corren con el sistema operativo de Windows XP SP2, y Windows 2000 SP 4 ya que marcaban que no encontraban el servidor al utilizar name pipes -->

<add name="MiBase" connectionString=" server=TCP:192.162.1.3,1433; database=MiBase; UID=muusuario; PWD=mipass; Connect Timeout=60;Connection LifeTime=5" providerName="System.Data.SqlClient"
/>

</connectionStrings>

</configuration>

<!--Bueno aqui estoy definiendo un tema que aplicara a todo el sitio -->
<pages theme="Default">
<!--aqui importamos todos los name spaces que normalmente utilizo, y con esto me ahorro el estar importando los namespaces pagina por pagina, ya que se importan en toda la aplicacion-->
<namespaces>

<add namespace="System.Data"/>
<add namespace="System.Data.SQLClient"/>
<add namespace="System.Web"/>
<add namespace="System.Net"/>
<add namespace="System.IO"/>
<add namespace="System.Collections.Generic"/>
<add namespace="System.Globalization"/>

</namespaces>


<!--Aqui se estan importando controles que he creado y que se pueden importar como las etiquetas de asp.net-->
<controls>
<add tagPrefix="MiControl" namespace="Tabstrip"/>
<add tagPrefix="MiControl" namespace="datepicker"/>


<!--Aqui se estan importando web user Controls que he creado y que se pueden importar como las etiquetas de asp.net-->
<add tagPrefix="MiControl" namespace="WebMenu"/>
</controls>



Poco a poco voy a ir indroduciendo mas informacion del webconfig

miércoles, agosto 23, 2006

AutoPostBack en FORMS con JavaScript

Esta página HTML tiene la capacidad de recibir un parámetro que puede definir el "action" de un formulario y además recibir varios parámetros para enviarlos al URL del action.

Ejemplifiquemos esto.

Tenemos 3 páginas A.htm, M.htm y Z.htm.

La página A contendrá un link hacia M que enviará ciertos parámetros, por ejemplo:
<a target="_blank" href="M.htm?action=Z.htm
&param1=value1&param2=value2&param2=value2"></a>

De ese modo M (que es la página que vamos a crear) recibirá todos los parámetros y los enviará a Z.htm.


<script language="javascript">
<!--//
function Envia()
{
var query = window.location.search.substring(1);
var vars = query.split("&");
var BlnHayAction = 0;

for (var i=0;i<vars.length;i++)
{
var pair = vars[i].split("=");
{
if (pair[0] == "action"){document.Form1.action = pair[1]; BlnHayAction = 1;}
}
}

if (BlnHayAction == 1)
{
for (var i=0;i<vars.length;i++)
{
var pair = vars[i].split("=");
if (pair[0] == "param1"){document.getElementById("param1").value = pair[1];}
if (pair[0] == "param2"){document.getElementById("param2").value = pair[1];}
if (pair[0] == "param3"){document.getElementById("param3").value = pair[1];}
}

document.Form1.submit();
}
}

//-->
</script>

<html><body onload="Envia()">

<form id="Form1" name="Form1" method="post">
<input name="param1" type="hidden" id="param1">
<input name="param2" type="hidden" id="param2">
<input name="param3" type="hidden" id="param3">
</form>

</body></html>

Validar el tipo de archivo a subir

Bueno vamos a ver una manera rapida de hacer una revision del tipo de archivo que deseamos cargar a nuestro servidor, para que de esta manera decidamos si es valido el tipo de archivo que el usuario desea subir.

Este codigo va en el botón de cargar los archivos

Dim MyFileCollection As HttpFileCollection = Request.Files
Response.Write(Request.Files.Count)
For Loop1 as integer = 0 To MyFileCollection.Count - 1
If MyFileCollection(Loop1).ContentType = "video/mpeg" Then 'no pasa
Response.Write("mpg
")
ElseIf MyFileCollection(Loop1).ContentType = "audio/mpeg" Then 'no pasa
Response.Write("mp3
")
ElseIf MyFileCollection(Loop1).ContentType = "text/plain" Then 'no pasa
'accion
ElseIf MyFileCollection(Loop1).ContentType = "image/jpeg" Then
'accion
ElseIf MyFileCollection(Loop1).ContentType = "image/gif" Then
'accion
ElseIf MyFileCollection(Loop1).ContentType = "application/xml" Then
'accion
ElseIf MyFileCollection(Loop1).ContentType = "application/msword" Then
'accion
ElseIf MyFileCollection(Loop1).ContentType = "application/x-zip-compressed" Then 'no pasa
'accion
ElseIf MyFileCollection(Loop1).ContentType = "video/x-ms-wmv" Then
'accion
ElseIf MyFileCollection(Loop1).ContentType = "application/octet-stream" Then
'accion
ElseIf MyFileCollection(Loop1).ContentType = "application/vnd.ms-excel" Then
'accion
ElseIf MyFileCollection(Loop1).ContentType = "video/x-ms-wmv" Then
'accion
End If
Next Loop1

En cuanto tenga mas informacion ampliare este ejemplo.

jueves, agosto 17, 2006

Una estrategia para evitar SQL Injection

Cuando accesamos a la base de datos buscando información o bien insertando nueva información corremos el riesgo de ser atacados mediante SQL Injection.

¿Por qué o cómo pasa esto?
Cuando un usuario introduce información en los formularios que hemos creado en nuestra página, éste texto es concatenado de algún modo en sentencias SQL para realizar queries. Por ejemplo, cuando un usuario escribe su UserName y su Password formamos una sentencia como esta:
SELECT * FROM Usuarios WHERE UserName='usr1' AND Password='pwd1'
Como vemos, las comillas simples delimitan cadenas en la sentencia.

¿Qué pasaría si el usuario en lugar de escribir [usr1] escribiera ['; DROP--]
La sentencia sería:
SELECT * FROM Usuarios WHERE UserName=''; DROP--' AND Password='pwd1'

Seguramente el usuario verá un error en la aplicación. Pero observemos:
1. El punto y coma provocó finalizar una sentencia
2. Los dos guiones provocan que el texto siguiente sea un simple comentario
3. Drop podría ser utilizado para borrar completamente una tabla.

En fin, no queremos ahondar en este tema, pero sí prevenir este tipo de ataques, así que en el caso de nuestras aplicaciones que corren en Web podemos utilizar dos rutinas. Una de ellas que convierta cualquier texto en código HTML, incluyendo la comilla simple, y sólo así guardar la información en la base de datos. La otra tomará texto de la base de datos, que viene en formato HTML y de ser necesario la decodificará para mostrarla correctamente (en controles textbox principalmente).

Function TextFromBD(ByVal StrText As String, ByVal BlnType As Boolean) As String
'BlnType: (0 - Para mostrar en HTML) (1 - Para mostrar en TextBox)
If BlnType = True Then
StrText = Server.HtmlDecode(StrText)
StrText = Replace(StrText, "&#39", "")
StrText = Replace(StrText, "&#3", "")
StrText = Replace(StrText, "&#lt", "")
StrText = Replace(StrText, "&#l", "")
StrText = Replace(StrText, "&#gt", "")
StrText = Replace(StrText, "&#g", "")
StrText = Replace(StrText, "&#", "")
Else
StrText = Replace(StrText, ControlChars.CrLf, "<br>")
StrText = Replace(StrText, ControlChars.Tab, "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;")
End If
Return StrText
End Function

Function TextToBD(ByVal StrText As String, ByVal IntLeft As String) As String
StrText = Trim(StrText)
StrText = Server.HtmlEncode(StrText)
StrText = Replace(StrText, "'", "&#39;")
StrText = Replace(Replace(StrText, "<", "&lt;"), ">", "&gt;")
If IntLeft > 0 Then StrText = Left(StrText, IntLeft)
Return StrText
End Function

Expresiones regulares

Para validar URLs:
http(s)?://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?

Para validar correo:
^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$

Para validar cadenas sin caracteres especiales:
^[a-zA-Z0-9ñÑáéíóúÁÉÍÓÚ]+$

Para validar RFC
^[a-zA-Z]{3,4}(\d{6})((\D|\d){3})?$

Función general para utilizar las expresiones:

Ejemplifiquemos con la expresión regular que valida el correo. Esta función regresará False cuando strIn sea un correo no válido.

Function IsValidEmail(ByVal strIn As String) As Boolean
  Return Regex.IsMatch(strIn, ("^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$"))
End Function

¿Cómo crear un DataSet que contenga llave primaria?

Supongamos que requerimos una tabla que tenga dos columnas: ID y Nombre. La primera columna (ID) deberá ser llave primaria y además será de tipo "UniqueIdentifier" de modo que nos permita almacenar valores alfanuméricos y que no se repitan.

Dim dsProcesadas As New DataSet("MiDataSet")
Dim newTable1 As New DataTable("MiTabla1")
dsProcesadas.Tables.Add(newTable1)

newTable1.Columns.Add("ID", Type.GetType("System.Guid"), "")
newTable1.Columns.Add("Nombre", Type.GetType("System.String"), "")

Dim key(0) As DataColumn
key(0) = newTable1.Columns("ID")
newTable1.PrimaryKey = key


¿Cómo añado registros?

Es muy fácil, podemos crear una rutina muy aparte que lo haga y que reciba como parámetros los valores de las columnas. No nos confundamos, veamos el ejemplo:

Sub CreaRegistro(ByVal GuidID As Guid,ByVal StrNombre As String, ByRef ds As DataSet)
   Dim row As DataRow
   row = ds.Tables("MiTabla1").NewRow
   ds.Tables("MiTabla1").Rows.Add(row)
   row("ID") = GuidID
   row("Nombre") = StrNombre
End Sub


Juntemos todo el código en la siguiente función:

<script runat="server">

Sub Page_Load()
   Dim ds As new DataSet
   ds = GetDataSetPrincipal()
   '# A PARTIR DE AQUI PODEMOS HACER Y DESHACER
   '# EN EL DATASET
End Sub

Function GetDataSetPrincipal() As DataSet
   Dim ds As New DataSet("MiDataSet")
   Dim newTable1 As New DataTable("MiTabla1")
   ds.Tables.Add(newTable1)

   newTable1.Columns.Add("ID", Type.GetType("System.Guid"), "")
   newTable1.Columns.Add("Nombre", Type.GetType("System.String"), "")

   Dim key(0) As DataColumn
   key(0) = newTable1.Columns("ID")
   newTable1.PrimaryKey = key

   Dim GuidJuan As Guid = New Guid("9CD8769C-7DEB-40A0-828E-DBB03556B451")
   Dim GuidPedro As Guid = New Guid("9CD8769C-7DEB-40A0-828E-DBB03556B452")
   Dim GuidAna As Guid = New Guid("9CD8769C-7DEB-40A0-828E-DBB03556B453")
   CreaRegistro(GuidJuan, "Juan" , ds)
   CreaRegistro(GuidPedro, "Pedro" , ds)
   CreaRegistro(GuidAna, "Ana" , ds)

   Return ds
End Function

Sub CreaRegistro(ByVal GuidID As Guid,ByVal StrNombre As String, ByRef ds As DataSet)
   Dim row As DataRow
   row = ds.Tables("MiTabla1").NewRow
   ds.Tables("MiTabla1").Rows.Add(row)
   row("ID") = GuidID
   row("Nombre") = StrNombre
End Sub

</script>