Vous êtes sur la page 1sur 14

SEGURIDAD EN ASP.

NET: AUTENTICACIÓN Y AUTORIZACIÓN

Milián, V

Universidad de las Ciencias Informáticas

Resumen
La seguridad es un elemento importante en el desarrollo de aplicaciones web. Posiblemente
garantizar la seguridad en aplicaciones Web es la cuestión más importante. En la actualidad más
aplicaciones Web en tiempo real ofrecen su información a través de Internet y redes privadas. A
pesar de la amplia posibilidad y ventajas que esto ofrece, también aumenta los riesgos de
seguridad. Las aplicaciones Web que requieran información sensible deben ser protegidas de
ataques maliciosos.
ASP.NET en conjunto con IIS proporciona un servicio de autenticación y autorización a las
aplicaciones Web. Con Microsoft. NET Framework e IIS, ASP.NET ofrece una mejor seguridad
a dichas aplicaciones Web. La autenticación en ASP.NET se lleva a la práctica con la ayuda de
proveedores de autenticación, tales como las formas y la autenticación sobre Windows.
Esperamos demostrar con algunos ejemplos cómo utilizar estas técnicas en aplicaciones
ASP.NET.

Abstract
Security is a significant element in any Web development. Positively ensuring security in Web
applications is a major issue. In the present Internet world more real-time Web applications offer
their information across Internet and private networks. Even though this widespread connectivity
offers better advantages, it also increases the security risks. Web applications that entail sensitive
information have to be protected from malicious attacks.
ASP.NET works in concurrence with IIS to provide authentication and authorization services to
Web applications. With Microsoft .NET Framework and IIS, ASP.NET offers better Web
application security. ASP.NET authentication is put into practice with the assistance of
authentication providers, such as Forms and Windows authentication. We hope whit some
programming examples, demonstrate how to use these techniques in ASP.NET applications.

Palabras clave: ASP.NET, autenticación, autorización

Keywords: ASP.NET, Authentication, Authorization

277
1. Introducción
En el desarrollo de aplicaciones ASP.NET seguras, se debe considerar los siguientes mecanismos
fundamentales:
Autenticación: ¿Quién eres?
La autenticación es el proceso de verificación de identidad antes de permitir que el
usuario/aplicación acceda a un recurso. Por ejemplo, el usuario/aplicación tiene que identificarse
mediante la presentación de algún tipo de credenciales, como un par de nombre y contraseña.
Autorización: ¿Se le permite acceder a este recurso?
Después que el usuario/aplicación es autenticado, la autorización es el proceso de concesión de
privilegios basada en la identidad. Es el paso siguiente a la autenticación, que valida a que
recursos el usuario/aplicación autenticado tiene permitido el acceso (por ejemplo, verifica si tiene
acceso total o limitado a la aplicación).

2. Autenticación ASP.NET
2.1 Aspectos Generales
La autenticación es una de las principales características de la seguridad en aplicaciones Web.
Existen tres formas de implementarla con la ayuda de los proveedores de autenticación de
ASP.NET: formularios, Passport y la autenticación de Windows. Para usar un proveedor de
autenticación, se debe configurar el atributo mode del elemento <authentication> en el archivo de
configuración de la aplicación de la siguiente manera:
//Web.config:
<authentication mode = "[Windows/Forms/Passport/None]"> </authentication>
El atributo mode se puede establecer en uno de estos métodos: Windows, Forms, Passport, o
None. El valor por defecto es Windows.
 Forms: Las solicitudes no autenticadas se redirigen a una página de inicio de sesión,
donde el usuario tiene que proporcionar credenciales y envía el formulario. Si la
aplicación autentica la solicitud, a continuación, emite una cookie (o crea una sesión) que
contiene un símbolo o clave para el cliente. Luego, en cada solicitud posterior la "cookie"
se transmite en las cabeceras de la petición, para evitar nuevas autenticaciones. Este
método es adecuado para aplicaciones comerciales en Internet.
 Passport: En este mecanismo, las solicitudes no autenticadas son redirigidos a un sitio
alojado por Microsoft donde los usuarios pueden proveen un nombre y contraseña que
autentica su acceso a varios sitios. Este método es adecuado para aplicaciones
comerciales.
 Windows: En este mecanismo ASP.NET trabaja en conjunto al esquema de autenticación
de IIS. Primero, IIS implementa la autenticación mediante el empleo de alguna de estas
maneras: básica, implícita, autenticación integrada de Windows o NT LAN Manager
(NTLM), o certificados. Cuando IIS ha completado la autenticación, ASP.NET utiliza la
identidad autenticada para autorizar el acceso. Este método es el más adecuado en las
Intranet y de aplicaciones corporativas privadas.

278
 None: No se especifica método alguno. Aquí no se hacen comprobaciones de
autenticación y los dichos servicios están inactivos. No obstante los servicios de
autenticación de IIS todavía pueden estar presente. Se puede emplear cuando no se
autentican a los usuarios o se está creando un esquema de autenticación personalizado.
Veamos la autenticación mediante formularios y la de Windows.

2.1 Autenticación de formularios


La autenticación basada en formularios es un servicio de autenticación de ASP.NET, que facilita
a las aplicaciones Web hacer su propia verificación de credenciales y ofrecer a sus usuarios de un
mecanismo de inicio de sesión. Es ampliamente usado en los sitios Web para llevar a cabo la
autenticación de los usuarios de forma personalizada. Cuando un usuario se conecta por este
método, se crea una cookie, lo que permite realizar el seguimiento del usuario por todo el sitio.
En este mecanismo, los usuarios no autenticados se redirigen automáticamente a una página de
acceso donde han de proporcionar las credenciales adecuadas. Una vez que el usuario
proporciona las credenciales adecuadas y se autentica correctamente, ASP.NET crea la cookie
para el usuario y lo redirige a los recursos que anteriormente se solicitaban; de lo contrario, es
redirigido a la página de inicio de sesión e informado de que el nombre de usuario/contraseña no
es válido. La autenticación de formularios a menudo se utiliza para la personalización, donde el
contenido es personalizado los diferentes usuarios.
Inicialmente, el servidor emite un "cookie", un pequeño pedazo de datos, para el cliente. En las
siguientes peticiones HTTP, el cliente envía la cookie al servidor, lo que demuestra que el cliente
ha sido previamente autenticado. En el siguiente ejemplo se muestra cómo crear una aplicación
ASP.NET sencilla que implementa la autenticación de formularios. Hay tres archivos
involucrados: default.aspx, login.aspx y Web.config. Inicialmente, el usuario solicita la página
default.aspx. Si el usuario no está autenticado, él es redirigido a la página login.aspx, donde tiene
que presentar el nombre de usuario y la contraseña adecuada. Si el usuario es autenticado,
entonces se redirige a la página original. La autenticación por formularios utiliza las clases se
encuentran en System.Web.Security.
Para implementar la autenticación mediante formularios, se deben seguir los siguientes pasos:
 Ajustar el modo de autenticación en el archivo Web.config.
 Desarrollar un formulario para obtener las credenciales del usuario.
 Guardar las credenciales en un archive o base de datos.
 Autenticar al usuario contra el archivo o base de datos.
En la autenticación por formularios se puede almacenar las credenciales en:
 Web.config
 Archivo XML
 Base de datos

2.2.1 Almacenar credenciales en el archivo Web.config


En este método toda la información del usuario se almacena en la parte <credentials> del archivo
Web.config que se encuentra en el directorio raíz de la aplicación. Almacenar credenciales en el
archivo Web.config es adecuado y conveniente sólo para autenticación simple. No es adecuado si
279
se permite a los usuarios crear y mantener sus propias cuentas. En estos casos se debe almacenar
el nombre de usuario y contraseña en una base de datos o un archivo XML.
Se debe configurar el archivo de configuración Web.config de la siguiente manera y debe estar en
el directorio raíz de la aplicación (el directorio en el que reside default.aspx).
<configuration>
<system.web>
<authentication mode="Forms">
<forms name=".ASPXFormAuth" loginUrl="login.aspx" protection="All" timeout="15" path
="/">
<credentials passwordFormat="Clear">
<user name="Susam" password="Admin"/>
<user name="Michelle" password="User"/>
</credentials>
</forms>
</authentication>
<authorization>
<deny users="?" />
</authorization>
</system.web>
</configuration>
Si el usuario no está autenticado, se redirige al archivo login.aspx. Dicha página debe lucir como
se muestra en la Figura 1. El código de login.aspx es el siguiente.
private void Button1_Click(object sender, System.EventArgs e){
if (FormsAuthentication.Authenticate(Userid.Text, Passid.Text)){
FormsAuthentication.RedirectFromLoginPage(Userid.Text,false);
}
else{
Passid.Text = "";
Label3.Text = "Usuario o contraseña incorrecto!";
}
}

Figura 1. Login.aspx, el usuario envía un nombre y contraseña valido.

280
Aquí, FormsAuthentication.Authenticate(Userid.Text, Passid.Text) devuelve un valor booleano
true si las credenciales son válidas y false si las credenciales no son válidas. Si devuelve true, se
crea una cookie de autenticación, se añade a la respuesta de salida, y se redirige la solicitud a la
página solicitada inicialmente mediante
FormsAuthentication.RedirectFromLoginPage(Userid.Text,false). En este método el segundo
parámetro especifica si la autenticación debe ser una cookie de sesión (false) o una "cookie"
(true).
El archivo default.aspx es el solicitado originalmente. En dicha página simplemente mostraremos
un mensaje de bienvenida, como se muestra en la Figura 2. Al emplear
FormsAuthentication.SignOut(), se puede fácilmente eliminar o invalidar las cookies de
autenticación. El código de default.aspx es el siguiente:
private void Page_Load(object sender, System.EventArgs e){
Label1.Text = "Le damos la bienvenida " + User.Identity.Name;
}
private void SignOut_Click(object sender, System.EventArgs e){
FormsAuthentication.SignOut();
Response.Redirect("login.aspx");
}

Figura 2. Mensaje de bienvenida mostrado en default.aspx después de autenticado.

No se recomienda almacenar la contraseña en texto claro. A pesar de que un usuario no puede


acceder directamente a un archivo Web.config, si el servidor es accesible en una red local, existe
la posibilidad de acceder al Web.config. Por lo tanto, al almacenar nombres de usuario y
contraseñas usted debe cifrarlos, utilizando el método HashPasswordForStoringInConfigFile.
Este utiliza el SHA-1 o MD5 para cifrar los datos, como sigue:
Passid.Text = FormsAuthentication.HashPasswordForStoringInConfigFile(Passid.Text,"SHA1");
Por ejemplo, el valor hash de la contraseña "Divine" usando SHA-1 es
C1FF7FB589DDC7CECD412F515709D8DC2B2B2C22.
Usted también puede proteger la información confidencial en los archivos Web.config utilizando
la API de Protección de Datos (DPAPI).
2.2.2 Almacenar credenciales en archives XML
La información del usuario se almacena en un XML. No es práctico almacenar un gran número
de usuarios y contraseñas en el archivo Web.config. En este método, no hay parte de credenciales
en el archivo Web.config. El archivo Web.config es el siguiente:
<authentication mode="Forms">
<forms name=".ASPXFormAuthxml" loginUrl="login.aspx" protection="All" timeout="60" />
</authentication>
281
<authorization>
<deny users="?"/>
</authorization>
Como hemos comentado anteriormente, ASP.NET comprueba si se ha autenticado la petición. Si
la solicitud no está autenticada, se redirige a login.aspx. Allí, el cliente tiene que presentar las
credenciales adecuadas para la autenticación. La página login.aspx evalúa las credenciales
presentadas en el archivo Users.xml. El usuario es redirigido a la página solicitada si las
credenciales presentadas se encuentran en el archivo. Si no, la solicitud se redirige a otra página.
El archivo Users.xml, que incluye las credenciales del usuario, es el siguiente. El UserPassword
se cifra usando el método HashPasswordForStoringInConfigFile:
<?xml version="1.0" encoding="utf-8"?>
<Users>
<Users>
<UserID>Morgana</UserID>
<UserPassword> 44DD5C3AA9E4E693A9E394DAA5D3F3A449DC25CA</UserPassword>
</Users>
<Users>
<UserID>Michelle</UserID>
<UserPassword> FE71C5444F9327DDA2F1D69B7510ABF59B80672F</UserPassword>
</Users>
<Users>
<UserID>Susam</UserID>
<UserPassword> CF77B1B76919D5D2B8B79D63FCA5E70383A3D7E5</UserPassword>
</Users>
</Users>
El archivo login.aspx:
private void Button1_Click(object sender, System.EventArgs e) {
string Passidvalue =
FormsAuthentication.HashPasswordForStoringInConfigFile(Passid.Text,"SHA1");
String str = "UserID='" + Userid.Text+ "'";
DataSet ds = new DataSet();
FileStream fs = new
FileStream(Server.MapPath("Users.xml"),FileMode.Open,FileAccess.Read);
StreamReader reader = new StreamReader(fs);
ds.ReadXml(reader);
fs.Close();
DataTable clients = ds.Tables[0];
DataRow[] items = clients.Select(str);
if( items != null && items.Length > 0 ){
DataRow row = items[0];
String pass = (String)row["UserPassword"];
if (pass == Passidvalue)
FormsAuthentication.RedirectFromLoginPage(Userid.Text,false);
else
Label3.Text = "Por favor introdusca la contraseña correcta!";
}
282
else{
Label3.Text = " Usuario o contraseña incorrecto!";
Response.Redirect("adduser/adduser.aspx?UserID = "+Userid.Text);}
}
2.2.3 Almacenando credenciales en la base de datos
La información se almacena en la base de datos. Los archivos default.aspx y Web.config son
similares al método anterior. La única diferencia está en la página login.aspx. El código para el
método LoginBtn_Click es el siguiente:
private void LoginBtn_Click(object sender, System.EventArgs e){
SqlConnection conn = new SqlConnection ("Server=(local);" +
"Integrated Security=SSPI;" + "database=login");
try{
conn.Open();
String str = "select count (*) from login where UserID= '" +Userid.Text+ "' and Password= '" +
Passid.Text + "' ";
SqlCommand command = new SqlCommand(str, conn);
int count = (int)command.ExecuteScalar();
if (count!=0)
FormsAuthentication.RedirectFromLoginPage(Userid.Text, false);
else
Label3.Text = " Por favor introdusca la contraseña correcta!";
}
finally{
conn.Close();
}
}
Al validar las credenciales contra una base de datos, se deben tener en cuenta:

 Almacenar los valores hash de las contraseñas combinados con valores de saltos.
 Evitar las inyecciones SQL al validar las credenciales.
En aplicaciones reales, no se recomienda almacenar las contraseñas en la base de datos. El
problema con las contraseñas encriptadas es lo difícil de mantener segura la clave de cifrado. Por
otra parte, si un atacante tiene acceso a la clave, puede descifrar todas las contraseñas que se
almacenan en la base de datos. Por lo tanto, el mejor método es combinar el hash de la contraseña
con un valor de salto.
Se puede crear un valor de salto de la siguiente manera:
public static string GenerateSalt(int size){
RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider();
byte[] buff = new byte[size];
crypto.GetBytes(buff);
return Convert.ToBase64String(buff);
}

public static string GeneratePasswordHash(string passid, string salt){


283
string saltpassid = string.Concat(passid, salt);
string password = FormsAuthentication.HashPasswordForStoringInConfigFile( saltpassid,
"SHA1");
return password;
}
2.2.4 SQL Injection
Un usuario podría pasar de forma arbitraria, código SQL extra (malicioso), que normalmente se
añade al código SQL válido. Consideremos el siguiente código.
String str = "select count (*) from login where UserID= '" +Userid.Text+ "' and Password= '" +
Passid.Text + "' ";
Si el atacante entra para Passid.Text + " '"; cualquier cadena SQL maliciosa, la entrada anterior
ejecutará dicha cadena, porque el '(comilla simple) indica que la instrucción SQL se termina y el ;
(punto y coma) indica que se está abriendo una nueva declaración.
Para evitar las inyecciones SQL, considere lo siguiente:

 Utilizar validadores Fuertes y validar la entrada del usuario. Por ejemplo, limitar el
tamaño y el tipo de dato.
 Ejecutar las sentencias SQL con una cuenta con el mínimo de privilegios.
 Utilice parámetros a la hora de crear las sentencias SQL, como se muestra en el ejemplo.
SqlDataAdapter myCommand = new SqlDataAdapter( "SELECT * FROM login WHERE
UserID= @userid", myConn);
SqlParameter parm = myCommand.SelectCommand.Parameters.Add(
"@userid",SqlDbType.VarChar, 15);
parm.Value= Userid.Text;

2.3 Autenticación Windows


Los métodos de autenticación que ofrece IIS (aparte de la autenticación anónima), tales como
básica, implícita, autenticación integrada de Windows o sus otras formas (NTLM / Kerberos), o
certificados, son empleados en el mecanismo de autenticación de Windows. Es muy fácil de
implementar porque se puede aplicar con un mínimo de codificación, y la validación de las
credenciales las hace IIS. Este método es apropiado para aplicaciones de intranet, además,
funciona para todos los tipos de contenido, no sólo para los recursos ASP.NET.
Si un usuario solicita un recurso protegido, IIS lo autentica y le agrega una “ficha” de seguridad.
ASP.NET utiliza esta ficha para decidir si accede o no a la petición. Se puede suplantar la
identidad para restringir/permitir el acceso a los recursos. Si se habilita la suplantación, ASP.NET
suplanta al usuario por medio de la ficha de seguridad adjunta con la petición, comprueba que
está autorizado a acceder a los recursos y si se concede el acceso, envía los recursos solicitados a
través de IIS, de lo contrario, envía un mensaje de error.
Para habilitar este mecanismo, configuramos el Web.config estableciendo el modo de
autenticación a Windows y negando el acceso a los usuarios anónimos como sigue:
<configuration>
<system.web>

284
<authentication mode="Windows"/>
<authorization>
<allow users="Domainname\GroupName"/>
<deny users="*"/>
</authorization>
<identity impersonate="true" />
</system.web>
</configuration>
Las propiedades públicas definidas en la clase WindowsIdentity se muestran en la Tabla 1.
Tabla 1. Propiedades de instancia publica definidas en la clase WindowsIdentity

Propiedades Publicas Descripción


IsAnonymous Indica si la cuenta se identifica como anónima por el sistema.
IsAuthenticated Indica si el usuario ha sido autenticado.
IsGuest Indica si la cuenta de usuario se identifica como invitado.
IsSystem Indica si la cuenta de usuario se identifica como cuenta del sistema.
Name Indica el nombre del usuario autenticado en el SO
Token Obtiene la cuenta de Windows para dicho usuario.

Los métodos compartidos definidos en la clase WindowsIdentity se muestran en la Tabla 2.


Tabla 2.Métodos públicos estáticos (compartidos) definidos en la clase WindowsIdentity

Método Publico Descripción

GetAnonymous Devuelve un objeto WindowsIdentity que representa un usuario anónimo.

GetCurrent Devuelve un objeto WindowsIdentity que representa el usuario actual.

Impersonate Permite suplantar al usuario de Windows.

Para implementar la autenticación de Windows, establezca el modo de autenticación en el


Web.config como se muestra a continuación, y deshabilite el acceso anónimo. Por último,
configurar las cuentas de Windows en el servidor web si no están presentes.
<authentication mode="Windows" />
<authorization>
<deny users="?" />
</authorization>
En la autenticación de Windows, puede recuperarse la información directamente desde el objeto
User. Es decir, si un usuario está autenticado y autorizado, la aplicación puede obtener
información sobre el mismo mediante el uso de la propiedad Identity del objeto User. Por
ejemplo, para el siguiente código, la salida será como se muestra en la Figura 3.
285
private void Page_Load(object sender, System.EventArgs e){
UserLabel.Text = User.Identity.Name + "Bienvenido a Akademos";
}

Figura 3. Obteniendo información de la autenticación Windows.

Si se ejecuta el proyecto de forma remota, ASP.NET muestra un cuadro de diálogo en el


navegador para recoger el nombre de usuario y contraseña, como se muestra en la Figura 4. Si el
nombre de usuario y contraseña es valido para el dominio de red, ASP.NET autentica al usuario y
lo utiliza en la aplicación.

Figura 4. Cuadro de diálogo para nombre de usuario y contraseña

3. Autorización ASP.NET
La autorización es un proceso en el que se determina si un usuario autenticado tiene acceso a una
determinada página o recurso. En ASP.NET existen dos formas principales de autorizar el acceso
a un recurso determinado: la autorización de archivo y la autorización de URL. Vamos a discutir
estos dos tipos escrupulosamente.

3.1 Autorización de archivos


Es ejecutado por la FileAuthorizationModule, el que verifica la lista de control de acceso (ACL)
o los permisos en un recurso para determinar si el usuario tiene privilegio de acceso al recurso.
FileAuthorizationModule proporciona servicios de autorización contra la ACL del sistema de
archivos. Se puede configurar el ACL de un determinado archivo o directorio en la ficha
Seguridad de propiedades del Explorer. Tenga en cuenta que se llama a AccessCheck sólo si hay
286
una WindowsIdentity asociado a la solicitud, por lo que no es estrictamente útil para la
autenticación de formularios o Passport, donde se tiende a ser una cuenta de Windows (la cuenta
anónima).

3.2 Autorización de URL


Es ejecutado por UrlAuthorizationModule. El usuario anónimo es verificado con los datos de
configuración. Si el acceso está permitido a la URL solicitada, se autoriza la petición. Al emplear
UrlAuthorizationModule, se puede permitir o denegar el acceso a grupos de usuarios o roles. Para
aplicar la autorización de URL, se debe poner la lista de usuarios y / o roles en los elementos
<allow> o <deny> de la sección <authorization> del Web.config.
La sintaxis general para la sección <authorization> es el siguiente:
<[element] [users] [roles] [verbs] />
Aquí, los elementos <allow> y <deny>
 <allow> otorga al usuario acceso al recurso.
 <deny> deniega al usuario acceso al recurso.
Los atributos soportados por <allow> y <deny>se muestran en la Tabla 3.
Tabla 3. Atributos soportados por Allow y Deny.

Atributo Descripción
Roles Identifica el(los) rol(es) específico(s) para este elemento.
Users Identifica los usuarios específicos para este elemento.
Verbs Define a que método de petición HTTP se aplica (GET, POST y HEAD).

Por ejemplo, en el código siguiente se concede acceso a un usuario llamado Susan y al rol
Administrador. Se niegan todos los demás usuarios.

<configuration>
<system.web>
<authorization>
<allow users = "Susan" />
<allow roles = "Administrator"/>
<deny users= "*" />
</authorization>
</system.web>
</configuration>
Se puede especificar múltiples usuarios o roles mediante una lista separada por comas:
<allow users="Susan,Michelle" />

Existen 2 identidades especiales:

287
 * : Todos los usuarios.
 ? : No autenticados (anónimos).
También puede especificar el método HTTP utilizando el atributo VERB, como se muestra en el
siguiente código. Por ejemplo, este código permite a Susan y Michelle usar POST y el resto sólo
pueden utilizar GET.
<allow VERB="POST" users="Susam,Michelle" />
<deny VERB="POST" users="*" />
<allow VERB="GET" users="*" />
También podemos utilizar la etiqueta <location> para especificar un archivo o directorio en
particular.
<location path="Required path"/>

4. Conclusion
En este artículo se explica la seguridad de ASP.NET en detalle. Se muestran los mecanismos y
las principales clases involucradas en la programación de aplicaciones ASP.NET seguras.
Además se utilizan una serie de ejemplos que ilustran como implementar la autenticación y la
autorización en ASP.NET. Esperamos que este documento ayude a que desarrollemos mejores
aplicaciones.

Bibliografía
 Sworn, J. “Microelectronics”, 2nd ed. London: McGraw-Hill, 1998, pp. 3-10.
 Esposito, D. “Introducing Micosoft ASP.NET 2.0”. Washington: Microsoft Press, 2005.
 LeBlond, G. “ASP.NET 2.0 Cookbook”. O'Reilly, 2005.
 Goodyear, J. “ASP.NET 2.0 MVP Hacks”. Washington: Wrox Press.2006.
 Walther, S. “ASP.NET 2.0 Unleashed” . Sams, 2006.
 Baier, D. “Developing More-Secure Microsoft ASP.NET 2.0 Applications (Pro
Developer)”. Washington: Microsoft Press, 2006.
 Sarknas, P. “Pro ASP.NET 2.0 E-Commerce in C# 2005”. Apress, 2006.
 Meier, J.D. “Building Secure ASP.NET Applications: Authentication, Authorization, and
Secure Communication”. January 2006.
http://msdn.microsoft.com/architecture/application/default.aspx?pull=/library/en-
us/dnnetsec/html/SecNetHT08.asp.
 Meier, J.D. “Patterns & practices Security Guidance for Applications Index”. Agosto
2005. http://msdn.microsoft.com/en-us/library/ms998408.aspx

288
Correspondencia (Para más información contacte con):
Ing. Vladimir Milián Núñez
e-mail: vmilian@uci.cu
Facultad #2, Universidad de las Ciencias Informáticas
Web site: www.uci.cu
Carretera a San Antonio km 2 ½. Reparto Torrens
Ciudad de la Habana – Cuba Teléfonos: 0537.837 21 06

289
290