You are on page 1of 18

Plataforma

Microsoft .NET

Juan Francisco Adame Lorite


Ingeniería de servicios de
Internet (Julio 2003)
Juan Francisco Adame Lorite

Presentación
La plataforma .NET de Microsoft es la última apuesta de esta compañía para
la integración de servicios y aplicaciones de Internet. Es una plataforma hecha a la
semejanza de la plataforma J2EE de Sun (no es un delito admitirlo, ni hace de
menos al software de Microsoft). La plataforma de Sun ha sentado una buena base
no sólo comercial sino de filosofía moderna de sistema de información, que
Microsoft ha reutilizado para adecuar sus productos de desarrollo a un nuevo
entorno. Microsoft ha intentado recuperar el tiempo perdido con este software.
La plataforma está orientada a Internet y los entornos distribuidos. Por eso
hace especial hincapié en la distribución de código en diferentes ubicaciones y a la
comunicación de estas partes de código mediante objetos remotos o servicios Web
entre otras tecnologías.
La naturaleza distribuida de la plataforma obliga a hacer un especial
esfuerzo en lo que a seguridad y confianza se refiere. Todo el código y servicios se
desarrollan bajo unas características apropiadas de seguridad y confiabilidad.
La plataforma se ha orientado mucho a nuevas tecnologías como XML
ampliamente aceptadas por una gran parte del sector de las tecnologías de la
información. Esto permite que las aplicaciones y servicios desarrollados en la
plataforma sean fácilmente integrables con otros servicios y aplicaciones, incluso de
otras plataformas.
El ámbito de aplicación de la plataforma es muy extenso, desde servicios
Web, aplicaciones Windows y aplicaciones Web hasta componentes y bibliotecas de
todo tipo.

Estructura de la plataforma
La plataforma se compone principalmente de dos partes:
„ Common Language Runtime
„ .NET Framework Class library
El primero es el entorno de ejecución, es el cliente de la plataforma que
analiza y ejecuta el código. Es el elemento análogo al JVM de Java (Java Virtual
Machina), salvo con la diferencia que el código ejecutado si es binario compilado en
este caso.
El segundo es el conjunto de bibliotecas de la plataforma integradas en ella
que permiten al desarrollador hacer uso de las principales funciones y
características de la plataforma. Es el elemento análogo a las JFC de Java (Java
Foundation Classes).
A diferencia de la plataforma Java no existe un lenguaje definido para el
desarrollo. Si bien todo código es traducido a una especie de metacódigo llamado
MSIL, similar al Bytecode de Java; éste como en el caso de Java no es apto para el
desarrollo. La plataforma sólo exige una serie de tipos, estructuras y formas
comunes que todo lenguaje debe implementar y modelar de alguna manera en su
sintaxis, que le permita compilar después su código a MSIL. Microsoft distribuye la
plataforma con cuatro lenguajes de desarrollo: Visual Basic, Manager C++, C# y
J#. Aunque actualmente muchos fabricantes han anunciado la salida al mercado de
sus lenguajes de desarrollo para la plataforma .NET, como es el caso de Borland y
Delphi.
El Common Type System (CTS) define como son declarados, usados y
administrados los diferentes tipos en tiempo de ejecución. Esto es muy útil porque
define los tipos posibles y su forma lo que facilita la implementación de estos tipos
en los diferentes lenguajes de la plataforma .NET. El CTS define los tipos nativos o
de valor y los tipos referenciados (tanto a datos, como los delegados y eventos),
los tipos miembro (métodos, funciones, constructores, atributos…) y sus
Juan Francisco Adame Lorite

modificadores, así como los delegados y eventos, arrays, interfaces, punteros…


Todo lenguaje compatible o integrable en la plataforma debe ser concordante y
coherente con estas especificaciones. Un resumen del CTS se puede encontrar en
http://msdn.microsoft.com/library/default.asp?url=/library/en-
us/cpguide/html/cpconthecommontypesystem.asp
La siguiente figura muestra el esquema de tipos que define el CTS:

Para permitir interactuar entre los elementos sin importar el lenguaje en que
se implementan, estos elementos deben mostrar sólo aquellas características que
son comunes a todos los lenguajes. Por este motivo el Common Language
Specification (CLS) se define como requisito de interfaz (hacia dentro se puede
utilizar el CTS completo) de todos los elementos de la plataforma. Para que dos
elementos implementados en lenguajes distintos puedan interactuar entre sí, sus
interfaces públicos deben cumplir los requisitos de tipos especificados en el CLS. El
CLS es un subconjunto de especificaciones reducidas del CTS. El CLS permite a los
desarrolladores de diferentes lenguajes compartir código y componentes. Un
resumen del CLS se encuentra en
http://msdn.microsoft.com/library/default.asp?url=/library/en-
us/cpguide/html/cpconwhatiscommonlanguagespecification.asp

Common Language Runtime (CLR)


El Common Language Runtime (CLR) es un agente o cliente de la plataforma
que gestiona los procesos de ejecución y los servicios de estos procesos. Es análogo
al JVM de Java con la salvedad que se ejecuta código binario compilado específico y
no código interpretado. La misión del CLR es efectuar la carga de este código,
gestionar sus necesidades de memoria y recursos, comprobar el acceso y privilegios
disponibles y requeridos para el código, comprobar la robustez y la seguridad de
tipos concordantes con el CTS.
El código es compilado haciendo referencia y uso del agente CLR, por lo que
se denomina managed code (código administrado). El CLR se encarga de la gestión
de memoria: reserva y liberación de recursos, referencias nulas, erróneas o zonas
de tipo privado; tiempo de vida de los objetos y liberación de recursos automático,
control y gestión de la seguridad.
El CLR permite también la ejecución de código o partes del código de tipo no
administrado (unmanaged code), cuando el código tiene los privilegios de seguridad
necesarios para la ejecución de código no administrado (mucho más restrictivos
que el código administrado). De esta manera es posible interactuar con antiguas
bibliotecas como las del sistema (WIN32) o con tipos COM, que son código no
administrado.
Juan Francisco Adame Lorite

La figura muestra el esquema de la estructura de la plataforma. El agente de


ejecución (CLR) se ejecuta sobre el sistema operativo y es el único intérprete entre
las aplicaciones de código administrado y el sistema operativo. El código
administrado hace uso de las clases de la biblioteca .NET Framework y de las
propias bibliotecas o externas del desarrollador. El código no administrado hace sin
embargo uso directo del sistema operativo, sin pasar por la supervisión del CLR.
Existe un segundo CLR que el es que ejecuta los servicios Web y aplicaciones
ASP.NET; este agente CLR es específico para funcionar sobre Internet Information
Server (IIS) y hace uso de las funcionalidades adicionales y restricciones de este
entorno. En este caso el agente no se comunica con el sistema operativo si no que
lo hace con éste último mediante el IIS.
Puede encontrarse más información sobre el CLR en:
http://msdn.microsoft.com/library/default.asp?url=/library/en-
us/cpguide/html/cpconcommonlanguageruntimeoverview.asp.

.NET Framework Class Library


La .NET Framework Class Library es la biblioteca de la plataforma. La
Framework ofrece un conjunto de clases, interfaces y tipos reusables con las
funcionalidades más básicas y comunes de la plataforma. Contiene los tipos
utilizados en el desarrollo de la plataforma.
Permiten implementar:
„ Aplicaciones de consola. (System.Console) Este espacio de nombres
permite utilizar y hacer uso de los flujos de entrada, salida y error
básicos de la aplicación.
„ Aplicaciones basadas en formularios Windows.
(System.Windows.Forms) Este espacio de nombres nos permite hacer
uso de la GUI de Windows: ventanas, botones,…
„ Aplicaciones Web ASP.NET y servicios Web (System.Web) Este
espacio de nombres nos permite implementar aplicaciones Web
basadas en formularios ASP y desplegar servicios Web.
„ Acceso a fuentes de datos (System.Data)
„ Acceso de ficheros y flujos (System.IO)
„ …
Juan Francisco Adame Lorite

Además define interfaces de funcionalidades básicas como el IComparable


para establecer los operadores de comparación de elementos, el IEnumerable para
hacer uso de la colección en un bucle foreach, ICloneable para soportar el clonado
de objetos,… y clases base como BaseCollection para implementar colecciones
específicas de elementos mediante herencia.
Puede encontrarse más información en:
http://msdn.microsoft.com/library/default.asp?url=/library/en-
us/cpref/html/cpref_start.asp.

El proceso de ejecución administrado


El proceso de ejecución de un proceso de la plataforma .NET es el siguiente:
El compilador del lenguaje específico elegido para el desarrollo compila el
código fuente al lenguaje intermedio MSIL. Este código MSIL junto con los recursos
de otros tipos necesarios para la ejecución y los metadatos del código son
encapsulados en un archivo Portable Executable (PE).
El siguiente cuadro muestra un ejemplo de código MSIL:
.method public hidebysig instance class System.Object Pop() il managed {
// Code size 43 (0x2b)
.maxstack 4
.locals ([0] class System.Object V_0, [1] int32 V_1)
IL_0000: ldarg.0
IL_0001: ldfld int32 Stack::m_size
IL_0006: brtrue.s IL_000e
IL_0008: newobj instance void ['mscorlib']System.NullReferenceException::.ctor()
IL_000d: throw
IL_000e: ldarg.0
IL_000f: ldfld class System.Object[] Stack::m_stack
IL_0014: ldarg.0
IL_0015: dup
IL_0016: ldfld int32 Stack::m_size
IL_001b: ldc.i4.1
IL_001c: sub
IL_001d: dup
IL_001e: stloc.1
IL_001f: stfld int32 Stack::m_size
IL_0024: ldloc.1
IL_0025: ldelem.ref
IL_0026: stloc.0
IL_0027: br.s IL_0029
IL_0029: ldloc.0
IL_002a: ret
} // end of method 'Stack::Pop'
En el momento en que se solicita la ejecución del fichero PE el compilador
Just In Time (JIT) extrae el código MSIL y con ayuda de los metadatos compila a
código binario dependiente de la máquina. Ese código binario se almacena en un
caché de binarios para futuras ejecuciones.
El agente CLR toma ahora el control sobre la ejecución de la aplicación.
Primero comprueba que recursos y privilegios requiere la aplicación (de acceso a
memoria o disco, de código no administrado, de seguridad y concordancia de
tipos,…), estos se obtienen de los metadatos del código. Si el usuario que ejecuta y
el código ejecutado tienen los suficientes permisos y privilegios exigidos se procede
a la ejecución, si no se produce una excepción y no se ejecuta el código.
Durante la ejecución el CLR proporciona y administra los recursos de la
aplicación, gestiona el tiempo de vida de sus objetos, comprueba la seguridad y
concordancia de los tipos, dispara excepciones,…
Existe más información sobre los ficheros PE en:
http://www.windowsitlibrary.com/Content/356/11/1.html.
Juan Francisco Adame Lorite

El recolector de basura
En los lenguajes orientados a objetos el tiempo de vida de los mismos ya era
controlado por el compilador, pero aún así había ocasiones en que esto no era
suficiente y parte de la memoria podía quedar desreferenciada y no era liberada.
Java resolvió este problema con el recolector de basura (Garbage Collector,
GC) y la plataforma .NET hace uso del mismo concepto.
El tiempo de vida de toda instancia de una clase (objeto) es el tiempo
transcurrido entre la llamada a su constructor y la llamada a su destructor y la
liberación de los recursos de los que hacía uso. El momento de creación es
controlado en el código por el usuario. Sin embargo, la destrucción del objeto no la
lleva a cabo el usuario, el CLR ejecuta cada cierto tiempo un agente llamado
recolector de basura que comprueba que elementos no están ya referenciados para
liberar los recursos que consumen (principalmente de memoria). La afirmación de
que la destrucción de recursos no está controlada por el usuario no es del todo
cierta, aquellos recursos que implementen el interfaz IDisposable poseen el método
Dispose que libera los recursos que posea la instancia sin necesidad de llamar al
recolector (sólo los recursos asociados, la propia instancia es eliminada por el
recolector de basura).
Los objetos de tipo no nativo o de valor, son llamados objetos referenciados,
son instancias de clases. El elemento de código es una referencia al heap del
proceso donde se almacena realmente la instancia. Cada cierto tiempo el GC inicia
el proceso de recolección de basura, primero comprueba que elementos del heap
no están apuntados por ninguna referencia del código o que referencias están fuera
ya del ámbito de ejecución actual. Todos esos elementos son eliminados del heap.
Si el número de elementos eliminado es muy alto, la memoria se compacta para
aprovechar el espacio y se actualizan las referencias en el código. Es por este
motivo muy importante hacer uso del operador fixed cuando trabajemos con
punteros en código no administrado, para informar al GC que el elemento
referenciado apuntado no debe moverse en el proceso de compactación a fin de
que el puntero no referencie de forma errónea. Puede verse un ejemplo de
programación no administrada donde se comprueba este efecto en:
http://www.codeproject.com/csharp/unsafe_prog.asp.
También es posible que existan elementos muy grandes en el heap, cuando
esto es así la compactación del heap se hace muy lenta y costosa y repercute en el
rendimiento de la aplicación. Estos elementos muy grandes son almacenados en un
heap especial que no es compactado nunca.
Para mejorar la eficiencia del recolector de basura, existen tres niveles en el
heap en los que se distribuyen los objetos según su tiempo de vida, de más jóvenes
a más antiguos. Cuando no hay espacio en el heap de nivel 0 para almacenar un
nuevo elemento, se llama al GC y todos los objetos que sobrevivan al proceso de
recolección y/o compactación se pasan al nivel 1. Cuando el nivel 1 se colapse se
repite el mismo proceso y se pasarían al nivel 2. El nivel 2 es el de mayor nivel.
Esto es muy eficiente porque los elementos tienen tiempos de vida parecidos
según el ámbito de código al que pertenecen (por ejemplo todas las variables
locales de un método) y de esta manera se eliminan a la vez afectando a un solo
nivel del heap.
Más información sobre el recolector de basura en:
http://msdn.microsoft.com/msdnmag/issues/1100/GCI/default.aspx.
http://www.yasd.com/tutorials/c_sharp/chap17_1.htm.

Assemblies
Los assemblies (ensamblados) son los bloques básicos de las aplicaciones,
ellos son la unidad fundamental de despliegue, control de versiones, reutilización,
ámbito y permisos de seguridad. Un assembly es una colección de tipos y de
recursos integrados de manera y forma que son la unidad lógica de funcionalidad.
Juan Francisco Adame Lorite

El assembly provee al CLR de la información necesaria en forma de metadatos de


los tipos implementados y su interpretación, por lo que un tipo no puede existir
fuera del contexto de un assembly.
El assembly es el elemento básico de salida del compilador. Es el elemento
ejecutado por el CLR.
Todo assembly contiene una versión, assemblies con versiones distintas son
distintos para el CLR. El origen, el autor y la versión del assembly se pueden
garantizar mediante firmado.
El assembly es la unidad de seguridad de código básica, los privilegios se le
conceden al código en función del origen, autor, versión,… del assembly.
El assembly es la entidad de ámbito básica, dos tipos iguales en assemblies
distintos son tipos distintos, un tipo no tiene sentido fuera del contexto de un
assembly.
Un assembly se compone de:
„ Por un manifiesto en forma de metadatos del assembly: nombre,
versión, cultura, firma,…
„ Metadatos del código, donde se definen los tipos de forma
concordante con el CTS.
„ Código MSIL.
„ Un conjunto de recursos, aunque éstos pueden ser separados del
assembly en módulos para facilitar la descarga del assembly.

Los assemblies compartidos se despliegan en el Global Assembly Cache


(GAC). Estos assemblies deben estar firmados. Dos versiones de un mismo
assembly pueden desplegarse en el GAC y la adecuada es escogida por el CLR. Las
assemblies declaran con que versiones anteriores son compatibles para poder ser
escogidas por el CLR cuando la versión exacta no exista en el GAC.
Se puede encontrar más información sobre assemblies en:
http://msdn.microsoft.com/library/default.asp?url=/library/en-
us/cpguide/html/cpconassemblies.asp.

Metadatos
Los metadatos son información declarativa que define y especifica el código
del assembly. Los metadatos añaden información adicional a la deducible del
código, o definen esta información para que evitar que tenga que ser deducida del
código (por un elemento o agente que no entienda ese lenguaje, por ejemplo).
Los metadatos facilitan la interacción entre diferentes lenguajes. Estos
metadatos definen los tipos del assembly para que puedan ser utilizados por otros
lenguajes. Así al leer el interfaz de los tipos desde los metadatos el lenguaje no
debe saber en que fue realizado pues sólo se limita a lo que los metadatos le
indican.
Los metadatos definen cada tipo y miembro del código de una manera
neutral. Los metadatos almacenan la siguiente información:
„ Descripción del assembly:
• Identidad (nombre, versión, cultura, llave pública de firmado)
Juan Francisco Adame Lorite

• Los tipos exportados


• Otros assemblies de los que este depende y sus versiones
• Permisos y privilegios necesarios para ejecutar
„ Descripción de tipos:
• Nombre, visibilidad, clases base e interfaces implementados
• Miembros: atributos, propiedades, campos, eventos, tipos
anidados
„ Atributos:
• Información descriptiva adicional que modifica la definición,
interpretación o modelado de tipos y miembros
Los metadatos de este último tipo se introducen en el código mediante los
atributos:
[WebMethod(Description="Put in your search string then press Invoke.")]
public DataSet Search(string searchParam)
{ … }

[Serializable]
public class Searcher
{ … }

Seguridad en la plataforma .NET


Existen 3 mecanismos de seguridad en la plataforma .NET. Cada uno de
ellos es definido en función de unos elementos y es gestionado de distinta manera:
„ Identity. Los privilegios se asignan en función de los metadatos de
identidad (nombre, versión, cultura, autor, clave pública de
firmado,…) del assembly a ejecutar.
„ Code Access Security. Dentro de la descripción en metadatos del
assembly entre los metadatos descriptivos y los atributos se indican
que privilegios y permisos requiere el assembly para ejecutar y
cuales, aún teniéndolos, no desea que se le asignen.
„ Role-based security. La aplicación corre sobre un sistema en que
cada usuario posee unos privilegios y permisos. Estos privilegios y
permisos se definen por el administrador.
La ejecución final de la aplicación o servicio, y los permisos y privilegios con
que ésta corra dependerán de estos tres elementos (de la intersección de ellos).
Si un elemento de código necesita un permiso para ejecutar, ese permiso
debe de estar asignado tanto a ese elemento como a todos los que le llaman. Es
decir los privilegios deben estar otorgados en todos los assemblies que se llaman.
Por ejemplo, si el assembly A llama o hace uso del assembly B y este último
requiere del permiso P, sólo ejecutará si A también tiene asignado este permiso.
Se puede encontrar más información sobre seguridad en la plataforma .NET
en:
http://msdn.microsoft.com/library/default.asp?url=/library/en-
us/cpguide/html/cpconnetframeworksecurity.asp.

Identity security
Es el mecanismo encargado de otorgar permisos y privilegios en función de
los metadatos de identidad del assembly. El ámbito, el conjunto de código y la
unidad básica de granulado es el assembly.
El equipo tiene asignadas unas políticas de seguridad. En estas políticas se
definen que privilegios se asignan a cada assembly en función de algunos o algún
metadato de identidad. Por ejemplo, los assemblies cuya zona de origen (lugar
donde se ubica el assembly) sea Internet no perteneciente a los sitios seguros de
Internet Explorer, no tendrá privilegios para escribir en disco, ver propiedades del
sistema,… Estos metadatos de identidad pueden ser el nombre del assembly, la
Juan Francisco Adame Lorite

versión, el autor del assembly (se comprueba por la clave pública de firmado), la
zona de ubicación del assembly, la URL de ubicación del assembly,…
Puede que un assembly esté afectado por más de una de estas reglas de
seguridad, si es así el assembly recibe los permisos de ejecución unión de todos los
otorgados por cada regla.
Además se definen tres diferentes políticas y una cuarta opcional. Se
denominan de empresa, de equipo, de usuario y de dominio de la aplicación. La
primera es común para todo el dominio, la segunda es común para todo el equipo,
la tercera es propia de cada usuario y la cuarta de cada dominio de aplicación (de
cada aplicación, ésta es opcional). Los privilegios resultantes para cada assembly
son la intersección de los otorgados por cada política.
En el siguiente ejemplo podemos observar que el código con clave pública de
firmado dada, cuyo nombre de assembly sea Microsoft.App y que el autor sea
Microsoft recibirá por un lado permisos de lectura en el directorio c:\Microsoft y por
el otro de escritura en dicho directorio. La aplicación tendrá privilegios de lectura y
escritura en el directorio a no ser que alguna de las otras dos políticas (empresa o
usuario) no los tenga:

Code access security


Los privilegios y permisos de acceso al código se definen específicamente en
el código, en los metadatos del propio assembly. Lo que se definen van a ser dos
cosas, los privilegios que se exigirán estar otorgados para la ejecución de la
aplicación y en segundo lugar los que se denegarán en la ejecución si ya estuviesen
otorgados. Por ejemplo, mi aplicación puede requerir para ejecutarse
correctamente permisos de escritura en el directorio C:\MyApp, luego no se
ejecutará si la seguridad de tipo Identity no le ha otorgado este permiso. De la
misma manera mi aplicación no va a hacer uso de otro directorio que no sea ese,
luego puedo denegar el acceso de cualquier tipo a cualquier otra parte del disco, y
aunque la seguridad de tipo Identity le haya otorgado este permiso la aplicación no
lo poseerá y será más segura (frente a bugs que pueda alguien aprovechar de
forma maliciosa, por ejemplo).
Estos permisos se establecen en los metadatos del assembly en dos puntos:
en el código (imperativos), o en los metadatos de descripción del assembly
(declarativos).
Los permisos declarativos se declaran como atributos en el código también,
pero en el assembly los almacenan en los metadatos de descripción del mismo.
Hacen referencia a todo el assembly, no a una parte del código. Indican que
Juan Francisco Adame Lorite

permisos son necesarios para ejecutar el assembly (si no, el CLR no lo ejecuta) y
cuales se deniegan (aunque la seguridad de tipo Identity los haya otorgado la
aplicación no los poseerá). Se comprueban en tiempo de carga antes de ejecutar la
aplicación. También es posible solicitar permisos de forma optativa, si no se
otorgan se procederá a ejecutar la aplicación en este caso y deberemos comprobar
si han sido otorgados de forma imperativa
//If it is not granted the application will fail to start
[assembly : UIPermissionAttribute (SecurityAction.RequestMinimum)]
//If it is not granted the application will still run
[assembly : SecurityPermissionAttribute (SecurityAction.RequestOptional
,Flags=SecurityPermissionFlag.UnmanagedCode)]
// The entire assembly will be blocked from accessing this drive.
[assembly : FileIOPermissionAttribute (SecurityAction.RequestRefuse
,Read=“C:\\”)]
Los permisos imperativos o solicitados de forma imperativa se solicitan en el
propio código y se comprueba si se han otorgado mediante el código. Son por lo
tanto específicos a una parte del código y al desarrollo particular de la ejecución de
la aplicación. Se comprueban en tiempo de ejecución.
try {
FileIOPermission myPermission = new FileIOPermission
(FileIOPermissionAccess.AllAccess,@"c:\\");
myPermission.Demand();
}
catch (SecurityException ex) {
MessageBox.Show(“Security Exception: “+ex.Message);
}

Role-based security
Hasta ahora solo hemos comprobado los privilegios de las entidades de
código. Pero además de estos permisos y privilegios existe un elemento más que
influye en estos: el usuario de la aplicación.
Aparecen entonces dos nuevos elementos en la arquitectura el autentificador
y el autorizador.
El autentificador es el elemento que indica que usuario es el que está
accediendo a la aplicación o servicio. En el caso de aplicaciones de formularios
Windows es el propio sistema operativo Windows, en el caso de servicios Web y
aplicaciones Web es el Internet Information Server. Aunque en ambos se casos se
puede buscar una vía alternativa de autentificación propia.
El autorizador es el elemento que se encarga de otorgar permisos y
privilegios en función del usuario autentificado. La autorización se realiza de forma
imperativa en el código haciendo uso de las clases Identity que define la identidad
del usuario y Principal que define su pertenencia a grupos. Cada autentificador
declara subtipos (el sistema operativo Windows define WindowsPrincipal y
WindowsIdentity) de estos que se pueden instanciar en la ejecución del código para
saber que usuario está ejecutando ese código y autorizarle o no.
WindowsIdentity MyIdentity = WindowsIdentity.GetCurrent();
If (MyIdentity.IsGuest) {…}
If (MyIdentity.IsAnonymous) {…}
If (MyIdentity.IsSystem) {…}
String Str=MyIdentity.AuthenticationType;
Str=MyIdentity.Name;
WindowsPrincipal MyPrincipal = new WindowsPrincipal(MyIdentity);
If (MyPrincipal.IsInRole(“Administradores”)) {…}
Juan Francisco Adame Lorite

Seguridad en ASP.NET

Esta figura muestra el proceso de autentificación y autorización en


aplicaciones ASP.NET y servicios Web. Toda petición pasa por un proceso doble de
autentificación y autorización, el del Internet Information Server y el del agente
CLR de ASP.NET.
En los puntos 2 y 3 se autentifica y autoriza al usuario para acceder a un
recurso que a continuación se comprueba es una aplicación ASP.NET o servicio Web
por lo que se pasa la ejecución de la aplicación al agente CLR de ASP.NET.
Este agente provee de nuevos mecanismos de autentificación y autorización
específicos, 5 y 6, que son controlados por el propio código de la aplicación o
servicio.
Finalmente es posible que se intente acceder a un nuevo recurso que
requiera autentificación y autorización, punto 7, en ese caso se hace uso de la
propia del agente CLR ASP.NET, se utiliza la propia identidad obtenida en 5 o se
impersonaliza con una identidad específica.
La arquitectura habitual de una aplicación ASP.NET o servicio Web, es la de
autentificarse en 2 como usuario anónimo, y que el IIS permita en 3 el acceso
anónimo al recurso ASP.NET. En 4 observamos que la identidad que se pasa al
agente CLR ASP.NET es la definida como usuario anónimo de IIS (IUSR_MACHINE).
Es en 5 donde se realiza la autentificación real por diferentes medios como el
servicio Passport de Microsoft, haciendo uso de la de Windows (siempre será el
usuario anónimo de acceso por IIS que es la pasada al agente CLR ASP.NET) o
mediante formularios Web, en la que el código define la propia identidad y principal
del usuario. En 6 el código autoriza a la identidad obtenida del punto 5. Y el acceso
a recursos externos, punto 7, se realiza mediante autentificación Windows (usuario
anónimo) o impersonalizando la petición a un usuario que sabemos tiene acceso al
recurso.

Nuevas aplicaciones y tecnologías


Aplicaciones de formularios Windows
Conserva la GUI habitual de coger y arrastrar elementos para diseñar el
aspecto de los formularios. No hay cambios significativos salvo que el sistema de
Juan Francisco Adame Lorite

mensajes de las aplicaciones MFC y Windows API 32 se sustituye por el concepto de


evento y delegado.
public class EventIssuer {
public delegate void EventDelegate(object from, EventArgs args);
public event EventDelegate myEvent;

public void issueEvent(EventArgs args) {


myEvent(this, args);
}
}

EventIssuer ei;
ei.myEvent += new EventIssuer.EventDelegate(handleEvents);

Public void handleEvents(object sender, System.EventArgs e){
…//Acción a realizar cuando se lance el evento
}

this.button1.Click += new System.EventHandler(this.button1_Click);



private void button1_Click(object sender, System.EventArgs e)
{
net.xmethods.www.CurrencyExchangeService Servicio = new
net.xmethods.www.CurrencyExchangeService();
float num = (float) Servicio.getRate("euro","us");
label1.Text=num.ToString();
}
Más información en la página:
http://msdn.microsoft.com/library/default.asp?url=/library/en-
us/vbcon/html/vboricreatingstandaloneappsvb.asp.

Servicios Web
Es el nuevo tipo de aplicación soportado por la plataforma. Microsoft se ha
orientado claramente a esta tecnología con la plataforma .NET y es la principal
innovación.
Definido bajo los estándares de SOAP para el intercambio de objetos
mediante mensajería XML, de WSDL para la definición de interfaces de servicios
Web y de UDDI para la publicación de servicios. Al acogerse a estándares no
propietarios y adoptados por las otras plataformas (J2EE en especial) esta
plataforma se puede integrar con otras mediante esta tecnología.
El servicio Web es un subtipo de la clase System.Web.Services.WebService y
que indica que métodos exporta mediante el atributo WebMethod. Esto permite
crear automáticamente el archivo WSDL, mediante la firma de cada método
definido como servicio, y la publicación en el directorio UDDI.
namespace MyWebService {
using System;
using System.Web.Services;

public class MyStringReverse: WebService {

[WebMethod(Description="Reverse String")]
public String ReverseString ( String InString ) {
// Check null String
if ( InString == null ) return null;
Int32 intSize = InString.Length;
char[] arrayInString = InString.ToCharArray();
char[] arrayOutString = new char[intSize];
for (Int32 i = 0 ; i < intSize ; ++i) arrayOutString[i] =
arrayInString[intSize-i-1];
return new String(arrayOutString);
}
}
}
La aplicación cliente, es decir la que hace uso del servicio Web, hace
peticiones a través de una clase proxy. Es una clase que tiene el mismo interfaz
Juan Francisco Adame Lorite

que el servicio Web pero cuya implementación de cada método son las llamadas al
servicio Web. Esta clase se genera automáticamente desde el archivo WSDL.
//------------------------------------------------------------------------------
// <autogenerated>
// This code was generated by a tool.
// Runtime Version: 1.0.2914.16
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </autogenerated>
//------------------------------------------------------------------------------

//
// This source code was auto-generated by wsdl, Version=1.0.2914.16.
//
using System.Diagnostics;
using System.Xml.Serialization;
using System;
using System.Web.Services.Protocols;
using System.Web.Services;

[System.Web.Services.WebServiceBindingAttribute(Name="MyClassSoap",
Namespace="http://tempuri.org/")]
public class MyClass : System.Web.Services.Protocols.SoapHttpClientProtocol {

[System.Diagnostics.DebuggerStepThroughAttribute()]
public MyClass() {
this.Url = "http://localhost/ASP.NET/MyWebService.asmx";
}
[System.Diagnostics.DebuggerStepThroughAttribute()]

[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/Add
",
Use=System.Web.Services.Description.SoapBindingUse.Literal,
ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
public int Add(int a, int b) {
object[] results = this.Invoke("Add", new object[] {
a,
b});
return ((int)(results[0]));
}

[System.Diagnostics.DebuggerStepThroughAttribute()]
public System.IAsyncResult BeginAdd(int a, int b, System.AsyncCallback
callback, object asyncState) {
return this.BeginInvoke("Add", new object[] {
a,
b}, callback, asyncState);
}

[System.Diagnostics.DebuggerStepThroughAttribute()]
public int EndAdd(System.IAsyncResult asyncResult) {
object[] results = this.EndInvoke(asyncResult);
return ((int)(results[0]));
}
}
La aplicación cliente sólo debe instanciar la clase proxy y llamar al método
que se precise. De forma síncrona:
MyClass mycls = new MyClass();
int x = Int32.Parse(a.Text);
int y = Int32.Parse(b.Text);
Message.Text = mycls.Add( x, y).ToString() ;
O asíncrona:
class TestCallback
{
public static void Main()
{
//Create AsyncCallback delegate for the BeginAdd method.
AsyncCallback objCallBack = new
AsyncCallback(TestCallback.FactorizeCallback1);
// Begin the Asynchronous call to the Web Service
Calc1 objCalcService = new Calc1();
Juan Francisco Adame Lorite

IAsyncResult objAsyncResult = objCalcService.BeginAdd(5, 5, objCallBack,


objCalcService);
... // Other tasks
// Keep track how long it takes to complete the async call
while (objAsyncResult.IsCompleted == false)
{
... // Task when finalized
}
}
// Callback function invoked by the proxy class when the asynchronous
operation completes
public static void FactorizeCallback1(IAsyncResult objAsyncResult)
{
// Use the AsyncState property to get the Web Service proxy object
Calc1 objCalcService = (Calc1) objAsyncResult.AsyncState;
// Get the completed results.
int results = objCalcService.EndAdd(objAsyncResult);
}
}
Se comprueba que la plataforma no sólo está orientada a los servicios Web,
sino que además el entorno de desarrollo permite un despliegue muy rápido de
estos servicios incrementando la productividad en estas tareas.
Más información en la página:
http://msdn.microsoft.com/library/default.asp?url=/library/en-
us/cpguide/html/cpconwebservicesoverview.asp.

Aplicaciones ASP.NET
Las aplicaciones Web también han sufrido un gran cambio. Hay muchas
diferencias entre el lenguaje de scripting ASP antiguo y el moderno ASP.NET.
Las aplicaciones ASP.NET se pueden implementar en cualquier lenguaje de la
plataforma .NET y hacer uso de toda la biblioteca .NET FrameWork Class Library.
El nivel de presentación se separa del funcional, cada uno se implementa en
un archivo distinto. Se puede trabajar diseño y funcionalidad de forma separada. El
modelo de interacción de la GUI es idéntico al modelo de eventos y delegados de
los formularios Windows, lo que da mucha más flexibilidad y funcionalidad a las
aplicaciones Web. El código client-side y server-side se desarrolla en el mismo
entorno.
El código no es un script interpretado es código binario compilado de la
misma manera que se ejecuta el resto de código en la plataforma .NET como se
explicó al comienzo del trabajo. Esto da mucha más eficiencia y rapidez a servicios
Web y aplicaciones Web.
Más información en la página:
http://msdn.microsoft.com/library/default.asp?url=/library/en-
us/cpguide/html/cpconcreatingaspwebapplications.asp.

ADO.NET
Es el nuevo interfaz de acceso a fuentes de datos, posee cuatro
implementaciones del tipo abstracto de base:
„ OLEDB: para ficheros CSV, Excel, Access,…
„ ODBC: para bases de datos con conectividad ODBC
„ SQL: para SQL Server versión 7 o mayor
„ Oracle: para Oracle Database versión 8 o mayor
Así mismo, se conserva el escenario clásico conectado y se añade uno
nuevo, el escenario no conectado.
Más información sobre ADO.NET en:
http://msdn.microsoft.com/library/default.asp?url=/library/en-
us/cpguide/html/cpconaccessingdatawithadonet.asp.
Juan Francisco Adame Lorite

ADO.NET: Escenario conectado


Es el escenario clásico de acceso a las fuentes de datos. Primero se
establece una conexión, se ejecuta un comando SQL y se leen los datos devueltos
con un reader.
En este escenario las relaciones entre elementos y las restricciones e
integridad se comprueban en la fuente de datos. Cuando se produce un error, éste
se propaga hasta la aplicación cliente, siendo este proceso más lento.
El interfaz es el interfaz de la fuente de datos, hacemos peticiones en el
lenguaje de la fuente de datos. Un cambio de fuente de datos podría provocar un
cambio en todas las consultas de la aplicación cliente.
Se requiere una conexión continúa con la fuente de datos, situación que no
es posible en muchos casos como en los dispositivos portátiles.

El siguiente es un ejemplo de código:


public void ReadMyData(string myConnString) {
string mySelectQuery = "SELECT OrderID, CustomerID FROM Orders";
SqlConnection myConnection = new SqlConnection(myConnString);
SqlCommand myCommand = new SqlCommand(mySelectQuery,myConnection);
myConnection.Open();
SqlDataReader myReader;
myReader = myCommand.ExecuteReader();
// Always call Read before accessing data.
while (myReader.Read()) {
Console.WriteLine(myReader.GetInt32(0)+myReader.GetString(1));
}
// Always call Close when done reading.
myReader.Close();
// Close the connection when done with it.
myConnection.Close();
}

ADO.NET: Escenario no conectado


El escenario no conectado es apropiado para las situaciones en las que el
cliente no está conectado directamente, o las solicitudes son esporádicas y no
podemos copar el recurso de la conexión continuamente.
La idea de este escenario es modelar en la aplicación parte de la base de
datos, trabajar sobre este modelo y actualizar la base de datos con los cambios al
finalizar.
El objeto que modela la base de datos, sus tablas, sus relaciones entre
tablas y restricciones de las columnas es el DataSet. Su estructura se define con un
documento XML que define todos estos elementos.
El elemento que rellena el DataSet y actualiza los cambios sufridos en él es
el DataAdapter. El DataAdapter posee los métodos Select para rellenar el DataSet
consultando datos a la fuente de datos y los métodos Update, Insert y Delete para
reflejar los cambios sufridos en el DataSet en la fuente de datos.
Inicialmente deberemos rellenar el DataSet con las filas y tablas que
deseemos, el método Select del DataAdapter elige que filas y tablas se cargan. A
continuación podemos trabajar con las filas y tablas del DataSet sin necesidad de
que haya conexión con la fuente de datos. El DataSet comprueba que las
restricciones de tablas (relaciones) y columnas (constraints) definidas en su
esquema se conserven. Cuando finalicemos, las filas creadas estarán marcadas
como tales y se actualizarán en la fuente de datos mediante el método Insert, las
Juan Francisco Adame Lorite

modificadas con el método Update y las borradas con el método Delete del
DataAdapter.
Existe un problema añadido en este escenario no existente en el anterior,
durante el tiempo que no hay conexión se producen actualizaciones en la fuente de
datos que pueden provocar incoherencias al actualizar el DataSet. Esas
incoherencias se detectan y pueden ser subsanadas.

El siguiente es un ejemplo de código:


string cString = "user id=sa;password=;initial catalog=northwind;data
source=MyComputerName\\NetSDK;Connect Timeout=5";
SqlConnection myConnection = new SqlConnection(cString);
// Create a SqlDataAdapter.
SqlDataAdapter myAdapter = new SqlDataAdapter();
myAdapter.TableMappings.Add(“TSuppliers", "Suppliers");
myConnection.Open();
SqlCommand myCommand = new SqlCommand("SELECT * FROM TSuppliers",myConnection);
myCommand.CommandType = CommandType.Text;
myAdapter.SelectCommand = myCommand;
ds = new DataSet("Customers");
myAdapter.Fill(ds);
// Create a second Adapter and Command.
SqlDataAdapter adpProducts = new SqlDataAdapter();
adpProducts.TableMappings.Add(“TProducts", "Products");
SqlCommand cmdProducts = new SqlCommand("SELECT * FROM TProducts", myConnection);
adpProducts.SelectCommand = cmdProducts;
adpProducts.Fill(ds);
myConnection.Close();
// Create a FK relation between both tables
System.Data.DataRelation dr;
System.Data.DataColumn dc1;
System.Data.DataColumn dc2;
// Get the parent and child columns of the two tables.
dc1 = ds.Tables["Suppliers"].Columns["SupplierID"];
dc2 = ds.Tables["Products"].Columns["SupplierID"];
dr = new System.Data.DataRelation("suppliers2products", dc1, dc2);
ds.Relations.Add(dr);
// Get supplier from suppliers' table
DataView suppliers = new DataView();
suppliers.Table = ds.Tables["Suppliers"];
suppliers.RowFilter = "Name = 'The supplier'";
int ID = suppliers[0]["SupplierID"];
// Create a new row in products' table
DataRow fila = ds.Tables["Products"].NewRow();
fila["SupplierID"]=ID;
...
fila["Name"]=@"products' name";
ds.Tables["Products"].Rows.Add(fila);
// Update Changes
DataSet changes = ds.GetChanges();
myAdapter.Update(changes);
adpProducts.Update(changes);
// Check conflicts and errors
if (ds.HasErrors){
DataRow[] errores = ds.Tables["Products"].GetErrors();
... // Fixing conflicts
} else ds.AcceptChanges();

Referencias
„ Programming C#, 3ª edición; Jessy Liberty; O’Reily
„ C# in a Nutshell, marzo 2002; Peter Drayton, Ben Albahari
& Ted Neward; O’Reily
Juan Francisco Adame Lorite

„ .NET Framework Essentials; junio 2001, Thuan Thai & Hoang Lam,
O’Reily
„ Plataforma .NET
• http://msdn.microsoft.com/library/default.asp?url=/library/en
-us/cpguide/html/cpconinsidenetframework.asp
„ C#
• http://www.codeproject.com
• http://msdn.microsoft.com/library/default.asp?url=/library/en
-us/csref/html/vcoriCSharpTutorials.asp
„ ASP.NET
• http://www.asp.net
• http://www.4guysfromrolla.com/
• http://411asp.net/
„ Servidores gratuitos ASP.NET, para probar:
• http://europe.webmatrixhosting.net/
• http://dotnetplayground.com/
„ Y las específicas de cada capítulo
Juan Francisco Adame Lorite

You might also like