Y tú, ¿dominas tus aplicaciones?

sábado 28 de octubre de 2006 | categorías: , , | 2 comentarios -- da clic aquí para dejar el tuyo

Hace unos días, Eber Irigoyen escribió un post con un ejemplo muy padre de cómo invocar un método privado de una clase desde otra y otro de cómo instanciar una clase que tenga un constructor privado utilizando reflection (reflexión, pues).

En realidad es muy sencillo hacerlo, así que si eres tan neurótico como yo, lo primero que se te viene a la mente es "¡Ah jijos! Pero debe haber alguna manera de evitar eso, ¿no? Digo, ¿apoco cualquiera puede agarrar mi código y 'hackearlo' así tan pelada?" La respuesta es "sí hay manera de evitarlo, pero no es tan sencillo", debes tener una buena idea de cómo el CLR carga y ejecuta Assemblies, cómo funcionan los mecanismos de Code Access Security (CAS) que trae el .NET Framework, cómo se relacionan con los Application Domains, Reflection, etcétera.

Sería bastante material para un humilde post, así que para que no te me aburras voy a seguir la filosofía de "¿Cómo te comes un elefante?" y espero poder escribir varios artículos al respecto en los próximos días (bueno, semanas)--sí ya sé que todavía tengo pendientes terminar los de ADO.NET, no creas que se me ha olvidado.

Parte de este artículo está adaptado y (MUY) sintetizado del capítulo 8 del libro para la certificación MCTS, de Tony Nurthup [et.al.], que fue de donde yo lo aprendí. No me estoy pirateando su texto, pero me gustó mucho la manera en que explicó la "teoría", así que me basé en el, lo resumí y le agregué de lo mío. Sin embargo, lo menciono porque quizá te interese echarle un ojo a ese libro.

Assemblies y Application Domains

Cuando compilas código de C# o VB.NET--o cualquier otro lenguaje que cumpla con el CLS--el resultado es un Assembly (¿ensamblaje?), o como decimos los mortales: un .EXE o .DLL. Sin embargo, ese ejecutable o DLL no está en código máquina, sino en código intermedio o MSIL (se pronuncia "misil").

Cuando quieres ejecutar o invocar el código en ese assembly, el Common Language Runtime (CLR) hace varias cosas, entre ellas:

  • Carga el assembly y, de ser necesario, crea un Application Domain (dominio de aplicación) para ejecutarlo.
  • Intenta "adivinar" los permisos con los que debe correr ese assembly (el nivel de seguridad) mediante evidencia y de acuerdo a la póliza de seguridad de la máquina.
  • Hace una compilación Justo A Tiempo (JIT) del assembly a código nativo de acuerdo a la plataforma donde esté corriendo (x86, x64, ARM, etc.)
  • Invoca el Entry Point (punto de entrada) del assembly para iniciar la ejecución.

Bueno, ¿pero qué carajos es un Application Domain? Es el análogo a un proceso del sistema operativo, pero para el .NET Runtime. Es decir, es un contenedor lógico que te permite correr varios assemblies bajo un mismo proceso (de S.O.), pero conservando muchos de los beneficios (p.ej., separación de memoria y de acceso a recursos).

Normalmente, el .NET Framework se encarga de crear el AppDomain default para tu assembly usando uno de los anfitriones que trae de cajón: ASP.NET Worker Process, Internet Explorer o Windows. Sin embargo, lo que muchos no saben es que puedes crear AppDomains a partir de tus propios assemblies que correrán contenidos dentro del AppDomain default.

Un buen ejemplo de esto son las aplicaciones web. Si tienes una aplicación web de ASP.NET y es accedida por N personas, el aspnet_wp.exe creará N instancias del assembly de tu aplicación, cada una dentro de un AppDomain separado.

Tú puedes hacer lo mismo en tus aplicaciones de una manera bastante sencilla. ¿Para qué? Se me ocurren 3 razones muy buenas:

  • Seguridad: Puedes especificar evidencia (que determina el nivel de seguridad) al crear un AppDomain o al cargar un assembly en el AppDomain. Si estás usando, por ejemplo, un componente de terceros, es buena práctica no darle permisos FullTrust nomás porque sí, y limitarlo ya sea a nivel AppDomain o a nivel Assembly.
  • Eficiencia: Si el assembly fue cargado en el AppDomain default, no podrás liberar su memoria hasta que termine el proceso anfitrión. Pero si lo cargas en un AppDomain separado, sí podrás hacerlo. Esto se puede ofrecer, por ejemplo, si tienes un servicio de Windows que hace uso de assemblies externos pero por un periodo corto de tiempo; te puede convenir liberar esa memoria cuando el servicio no esté chambeando.
  • Confiabilidad: Puedes aislar código inestable que pudiera tronar tu aplicación (Crystal Reports anyone?).
Usando AppDomain

Como podrás haber adivinado, dado que los AppDomains son importantes, el .NET Framework trae una clase especial para manejarlos: System.AppDomain

Estas son algunas de sus propiedades más interesantes (en mi humilde opinión):

  • Evidence: Expone la evidencia asociada al AppDomain y que será verificada contra la póliza de seguridad de la máquina. Más sobre esto en el siguiente post.
  • SetupInformation: Expone la configuración que se utilizó al crear el AppDomain.
  • CurrentDomain: Devuelve una referencia al AppDomain del hilo actual de ejecución (current Thread).
  • FriendlyName: Como su nombre lo dice, expone un nombre amigable que le puede asignar al crear el AppDomain. Si no lo especifican utiliza uno por omisión que quizá hayan visto en los mensajes del debugger(miassembly.vshost.exe)

Y de sus métodos, estos son los que me parecen más relevantes:

  • CreateDomain: Sirve para, duh, crear un AppDomain. AppDomain usa el patrón Factory, así que en lugar de utilizar su constructor, utilizas este método.
  • ExecuteAssembly y ExecuteAssemblyByName: Ejecutan un assembly dentro del AppDomain (otro duh). La única diferencia entre estos dos es que uno acepta la ruta al archivo del assembly y el otro solo el nombre (lo cual requiere que tengas una referencia a él en tu proyecto).
  • Load: Carga un assembly dentro del AppDomain.
  • Unload: Descarga el AppDomain completito. OJO: No puedes descargar assemblies o tipos individualmente.
  • CreateInstance: Crea una instancia de algún tipo (clase) definida en un assembly.
  • GetAssemblies: Expone los assemblies que han sido cargados en el contexto de ejecución actual.

Ahora sí, después del rollote, vamos aponerlo en práctica.

Hice una solución en en Visual Studio con dos proyectos de tipo Windows Console Application, uno llamado Anfitrion y otro llamado OtraAplicacion. Anfitrion tiene una referencia a OtraAplicacion, lo cual nos permite ejecutarlo por nombre. OtraAplicacion solo escribe un mensaje a la consola de "Hola, soy la Otra Aplicación".

// Crear el nuevo dominio. AppDomain usa el patron factory, así que se necesita
// utilizar CreateDomain en lugar de su constructor.
AppDomain d = AppDomain.CreateDomain("OtroDominio");
 
// Mostremos el nombre del dominio anfitrión y el del dominio que fue creado
Console.WriteLine("Dominio anfitrion: {0}", AppDomain.CurrentDomain.FriendlyName);
Console.WriteLine("Dominio creado: {0}", d.FriendlyName);
 
// Cargar y ejecutar un assembly, sin especificar evidencia, en el nuevo dominio.
d.ExecuteAssemblyByName("OtraAplicacion");
 
// Descargar el dominio
AppDomain.Unload(d);
Cómo restringir un AppDomain

Ahora sí, veamos qué tiene que ver todo esto con seguridad de código. Para correr un dominio o un assembly con privilegios limitados, necesitamos especificar evidencia en el momento de crear el AppDomain o de invocar los métodos Load, ExecuteAssembly o ExecuteAssemblyByName.

Para no desviar mucho del tema, solo te diré por ahora que evidencia se refiere a "pistas" que le puedes dar al .NET Framework acerca de la identidad del assembly y su procedencia. Basado en estas pistas, el runtime determinará a qué grupo de código pertenece y por lo tanto con qué permisos correrá. Si este párrafo solo te hizo pelotas, no te preocupes, intentaré explicarlo más a detalle en otro post.

Ahora, cambiemos OtraAplicacion para que haga algo más travieso que simplemente escribir un mensaje:

using System;
using System.IO;
 
namespace OtraAplicacion
{
    class Program
    {
        static void Main(string[] args)
        {
            //Console.WriteLine("Hola, soy la OtraAplicacion");
            File.Delete(@"C:\boot.ini");
        }
    }
}

Podemos protegernos de él si cambiamos el código que lo invoca de la siguiente manera:
// asumiendo que se tienes
// using System.Security.Policy
 
// crear un objeto de evidencia para limitar permisos.
object[] pistas = { new Zone(System.Security.SecurityZone.Internet) };
Evidence evidencia = new Evidence(pistas, null);
 
// crear dominio con permisos restringidos
AppDomain d = AppDomain.CreateDomain("OtroDominio", evidencia);
 
try
{
    // también se puede especificar la evidencia al 
    // cargar o ejectuar el assembly.  Por ejemplo
    // d.ExecuteAssemblyByName("OtraAplicacion", evidencia, null);
    d.ExecuteAssemblyByName("OtraAplicacion");
}
catch (System.Security.SecurityException ex)
{
    Console.WriteLine(ex.Message);
}
finally
{
    AppDomain.Unload(d);
}
Aunque este error no es el que esperaba (UIPermission se debe a que una aplicación corrida desde la zona de Internet no puede ejecutar aplicaciones con interfaz, ni siquiera de consola), sirve para demostrar que nuestro assembly está corriendo ahora en un AppDomain restringido.

Habrás notado que para crear la evidencia tuve que utilizar un arreglo de object. Esto es porque puedes especificar varios tipos de objetos como "pistas" y estas pistas pueden ser cualquier cosa, strings, int's o tipos. Los más sencillos de usar son los tipos que vienen en el espacio de nombres System.Security.Policy, como Zone, que fué el que utilicé en el ejemplo.

Otra cosa importante que quizá notaste es que esta misma técnica podría utilizarse para correr una aplicación con permisos MENOS restrictivos ya que en realidad estamos proveyendo evidencia falsa sobre nuestro assembly. Después veremos cómo impedir esto.

Por ahora, espero haberte dado al menos una idea de cómo cargar y administrar tu código utilizando dominios de aplicación y su relación con la seguridad de tu código. En la próxima nos clavamos ya un poco más con lo que son los permisos, permission sets, códigos de grupo, etcétera.

Enjoy.

Fotorecuento del MDCD Cd. Juárez

domingo 22 de octubre de 2006 | categorías: , | 1 comentarios -- da clic aquí para dejar el tuyo

(Espero tomen este post por el lado amable y no salir yo golpeado en la próxima reunión de la Comunidad .NET. Solo recuerden: grito como niña y sangro fácilmente.)

Disclaimer: Las fotos las tomó el Pelos (Alex) con la cámara del Pepe. Así que si no les gusta cómo salieron ya saben a quién reclamarle ;)

Humberto: "Ojalá el Vista se termine de instalar antes que Pepe termine su plática..."

Foto-Colado (enseguida del chavo del folder verde): "¿Verdad que hago caras chistosas?"

Chavo de camiseta amarilla: "Oremos hermanos...."

El Aplicado: "Ojalá venga esto en el examen, pa' que el profe se impresione con mis apuntes..."

Humberto: "Ya casi termina de instalarse Vista..."

Los Programadores de-a Neta: "A ver si es cierto que jala ese código..."

(¡Había gente tirándo código durante las presentaciones, yo los vi!)

Chavas(avos) del registro: (en voz semi-verdulera) "Pásele marchanta, lleve su paque-Microsoft con Visual Studio Tools for Office y Office 2007 Beta 2... Bara... Bara... llévelo, llévelo..."

Pepe: "Por favor Diosito, que no noten que estoy sudando..."

Chavo de camisa de cuadros: "Zzzzzzzz..." (Título alterno de la foto: El suspenso era tanto que parecía película de Hitchcock)

Humberto: "Era de este tamaño..." (con o sin albur, depende de ustedes)

(Nótese que hicimos el evento en el Tec de Monterrey)

Humberto: "Me hace falta mi porta-micrófono humano... ¡Aleeeeex!"

Humberto: "¿Ya ven qué bonito se ve el Güindous Vista?"

Pepe: "Quiero mucho a Meny" (noten el abracito cariñoso por la cintura... not that there's anything wrong with that...)

(Título alterno de la foto: Los chalanes compas del Pepe... ¡Gracias por toda la ayuda!)

Gorrones: "¿Qué, no hay pizza? Hmmm... en el Grupo de Usuarios El Paso sí ponen..."

(Fueron tantos asistentes que no cabían ni en la foto)

Pepe: "Inche Charlie, ¿pos de cuál andas fumando?"

Carlos: "Pura de la buena loco..."

Carlos: "Ay tula, Pepe, ya no me hagas cosquillas..." (qué puñal salí en esta foto, neta)

(Gonzo-- digo, el narizón de yo presumiendo mi wallpaper de Flock)

(Título alterno de la foto: Más publicidad para el Tec... y ¡arriba México!)

Edgar: "Qué bonito soy, qué bueno que me tomaste una foto..."

Foto-Colado: "¿Vieron? Otra de mis caras chistosas..."

Chava con la pluma: "¿TODO eso va a venir en el examen?"

Chava fotofóbica: (cubriéndose con un vaso) "¡Nooooo! ¡A mi no me gusta salir en las fotos!"

Foto-Colado: (a la izquierda) "Una más de mis caras sonrientes, para los que se las perdieron..."

Chava foto-fóbica: "¡Ya te dije que no me gustan las fotooooos!"

El Aplicado: "¿De qué $#¡ngaos está hablando este loco?"

Carlos: (con voz de homie-cholo-loco-matón) ".NET 3.0 ta chido ese..."

Chavo de camisa de cuadros: "Zzzzzzzz..."

Carlos: (como cantando rolita de Emanuel) "Al finaaaaaal..."

(primer ganador de la noche)

Foto-Colado: "Me cuelo en una foto más..."

Edgar: "Live long and prosper..."

Abraham: "Dejen les modelo el libro que me gané..."

(neta que el Abe sabe "vender", si no me creen, chequen la foto de lo que se llevó esa noche)

(el último ganador de la noche)

Cursos gratis de .NET Framework 3.0

miércoles 18 de octubre de 2006 | categorías: , , , , , | 3 comentarios -- da clic aquí para dejar el tuyo

No sé si te enteraste, pero de aquí al lanzamiento al público de Windows Vista (en enero), Microsoft está ofreciendo gratis 3 cursillos sobre las tecnologías principales del .NET Framework 3.0 (en inglés). Cada uno de ellos dura como 2 horas. Hay uno para Windows Presentation Foundation, otro para Windows Workflow Foundation y otro para Windows Communication Foundation.

Así que si después de la plática de ayer en el Developer Community Day te quedaste con las ganas de aprender un poco más, pues inviértele unas cuantas horas, que al fin y no pagas nada ;)

PD. ¡Gracias a Abe por su reseña del evento! (casi me chiveo con sus palabras jejeje)

¿Y dónde está el Kamikaze? 2 1/2

| categorías: | 1 comentarios -- da clic aquí para dejar el tuyo

(Ya sé, sorry por el mal chiste con el título, pero ya ven cómo me caen en gracia las maltraducciones)

Como dice la rolita: No estaba muerto, andaba de parranda.

La semana pasada y antepasada me la pasé en la Gran Manzana, visitando a mi dizque-morra y desconectándome un poco. No cargué con mi laptop, por que tenía el firme propósito de no geekear en el viaje, pero pues ya ven cómo es la vida.

Después de ver a Freddy Cole tocar como parte de Jazz at Lincoln Center (y echarme unos martini's de durazno ultra-poca-madre ahí), de ver en el Met la exhibición de Vollard con los Cezanne-s, Van Goh-s y Picasso-s (pre-cubismo) y la exhibición de las esculturas de Rodin, de visitar el planetario y los dinosaurios en el American Museum of Natural History y de cagarme de risa viendo Spamalot, pues quedó algo de tiempo libre. (La neta que ni cuando estuve viviendo allá turisteé tanto en tan poco tiempo, me cae)

Fue así que un día, merodeando por el TimeWarner Center, mientras esperaba a que la fierce saliera de su chamba en ese edificio, me topé con The Samsung Experience. Ni modo, no pude contener mi geekyness. Después de haber disfrutado de mi monitor LCD modelo 204B de 20.1" le agarré cariño a los productos de Samsung y pues este mostrador está chida. Básicamente es un localote en uno de los centros comerciales más caros de Manhattan dedicado a que llegues y juegues con todos los productos, desde celulares y monitores, hasta laptops, sistemas de audio. No te venden nada ahí, es nomás pa' que te quedes picado (sin albur).

Luego, resultó que la iPod Shuffle de la ley ya pedía reemplazo a gritos, lo cual fue la excusa perfecta para darnos una vuelta al Apple Store que está en 5th Ave. y E 58th St. para comprarle una iPod nueva. Antes de entrar nos tomamos fotos enfrente del mega-cubo de vidrio (bueno me tomaron fotos, ¿ya ven qué pinche geek soy?), aunque fue con una cámara convencional porque mi morra decidió cambiar de bolsa justo antes de salir del depa y ahí dejó la digital (¡mujeres!). Así que esas fotos no las puedo compartir. El logotipo del cubo de Apple no estaba cristalino, sino rojo, debido a la campaña de (RED) que traen varias tiendas para ayudar a combatir el SIDA en África.

Y sí, para poder entrar nos paseamos en el elevador cilíndrico transparente, el cual afortunadamente no nos dejó atrapados. Fuimos en un jueves como a las 8:30PM y la tienda estaba has-ta el cuuu-li-to. Pero había tantas iPods (shuffles, nanos, y normales) para jugar que eso no fue problema (imaginen 3 o 4 mesas grandes con como 10 o 12 iPods cada una para que los clientes pendejeen con ellas. Así que después de que la nena se decidió por una iPod video de 30Gb (negra por supuesto por que según ella es más sexy) pues yo me puse a jugar con la razón por la que vendí mi PC (la de 20", sin albur). Después me aviento otro post respecto a mis otras razones...

En fin, regresé el domingo en la noche. Lo cual significó que solo tuve un día para prepararme a dar la plática sobre .NET Framework 3.0 en el Community Developer Day, que fue ayer. Espero hayan asistido, si no ¡se la perdieron! porque estuvo bastante bueno el evento (luego les platico más, si es que no me ganan el Pelos o el Pepe).

[EOT]