sábado, 4 de abril de 2015

El secreto de los dedos de Aignes [Leído]

Una historia que se desarrolle en la Europa de la segunda guerra mundial que combine acción y misterio siempre estará entre mis favoritas, tal vez por eso El secreto de los dedos de Aignes - escrita por Pablo Carnicero - es la segunda novela de este tipo que me leo en un poco más de un mes.

En esta novela su autor, desde la perspectiva del soldado James Villalobos, nos cuenta como un grupo de soldados de élite del ejercito norteamericano son reasignados de unidad y elegidos para desarrollar la importante misión de recuperar algunos tesoros en poder de los nazis, cuyo valor  le ayudará a los ejércitos aliados a financiar la guerra.

El Secreto de los dedos de Aignes
El Secreto de los dedos de Aignes
La historia se comienza a desarrollar en el famoso desembarco de Normandia, a partir del cual sus protagonistas comienzan a vivir una serie de situaciones que desafían el peligro mientras se infiltran en líneas enemigas. Como se explica en su sinopsis, la misión aparentemente sencilla, esconde una maraña de traición, codicia y asesinatos, que le sitúa en el núcleo estratégico de un terrible conflicto entre los dos bandos contendientes.

Durante el desarrollo de la historia se nota el trabajo de su autor por describir muy bien los escenarios de la Europa en guerra, principalmente en Francia, así como los detalles técnicos propios del conflicto que fue la Segunda Guerra Mundial que hacen que la historia aunque sea de ficción se encuentre muy bien sustentada.

Otro punto a favor del libro es que se encuentra escrito en un lenguaje que facilita su lectura, y aunque no ahonda en detalle sobre sus personajes no queda ningún cabo suelto de la historia a pesar de su corta extensión (unas 211 páginas).

Si se busca una historia de acción, con un poco de contenido bélico (contenido necesario para la época y situación que se desarrolla), un poco de historia e incluso un poco de misterio, este libro es una buena alternativa. Yo por mi parte dejo en mi lista de pendientes explorar otras obras del autor que se encuentran disponibles en su página web y que sin duda se ven atractivas.






miércoles, 1 de abril de 2015

Diferencia entre CHAR y VARCHAR en MySQL

Un aspecto importante a la hora de diseñar bases de datos es definir de forma correcta los tipos de datos que se almacenarán en cada campo, ya que esto a largo plazo y dependiendo del volumen de transacciones que maneje la base de datos impactará en su rendimiento.


MySQL provee muchos tipos de datos, los cuales muchas veces resultan ambiguos pero que de fondo difieren en la forma en que son tratadas por el motor. Un claro ejemplo son los tipos CHAR y VARCHAR que nos permiten almacenar cadenas alfanuméricas, los cuales ha simple vista parecen iguales pero que como veremos a continuación difieren en la longitud máxima permitida, en la manera en que son almacenados, y en como son recuperados.


Cuando se declara un valor tipo CHAR el campo se crea con la longitud fija indicada al crear la tabla, la cual debe ser entre 0 y 255. Dado que es un tipo de longitud fija, al momento de almacenar datos en una columna CHAR, se rellenará con espacios en blanco las posiciones que no son ocupadas por los caracteres de la cadena que se está almacenando, caracteres que se eliminan cuando el dato es recuperado.


En contra parte los campos tipo VARCHAR son de longitud variable, que deber ser entre 0 y 65.535. Cuando se declara un valor tipo VARCHAR el motor de MySQL reserva 1 o 2 Bytes para ser usados como un prefijo de longitud, que almacena el valor de la longitud en Bytes de la cadena que se está almacenando. Si la cadena tiene una longitud de 255 o menos reserva 1 Byte, si la longitud es de 256 hasta 65.535 reserva 2 Bytes.


Con base a lo anterior podemos concluir que VARCHAR es más adecuado para cadenas que superan los 255 caracteres de longitud; sin embargo por ser un tipo de datos estático, CHAR tiende a ser más rápido que VARCHAR, lo cual lo convierte en la mejor alternativa si lo que se busca es un mejor rendimiento.


Un ejemplo de uso correcto de estos tipos de datos sería por ejemplo: usar CHAR para almacenar los hashes de contraseñas encriptadas con SHA1 ya que este algoritmo siempre genera cadenas de 40 caracteres, y usar VARCHAR para almacenar datos como direcciones o nombres de personas ya que estos datos son de longitud variable.

Más información en https://dev.mysql.com/doc/refman/5.0/en/char.html

domingo, 8 de marzo de 2015

El Libro Negro del Programador [Leído]

Continuando con las opiniones de los libros que leo, hoy me gustaría compartir uno que terminé de leer, y que sin miedo a equivocarme recomiendo como lectura obligada si estamos vinculados a la industria del desarrollo de software desde cualquier cualquier rol (analista, desarrollador, arquitecto, manager del proyecto, etc.).


El libro en cuestión es El Libro Negro del Programador, escrito por Rafael Gómez Blanes, quien con una lectura agradable nos relata una serie de experiencias y recomendaciones de lo que se debe y no se debe hacer en proyectos de desarrollo de software.

Basándose en su experiencia profesional de muchos años, el autor reúne en varios capítulos una serie de situaciones que se presentan en un proyecto de desarrollo de software que pueden afectar su calidad y cumplimiento de metas.

Aunque su título parece sugerirlo, el libro no aborda aspectos técnicos como el uso de determinadas herramientas o tecnologías por ejemplo; sino que se centra en describir una serie de comportamientos y en describir las buenas practicas que pueden mejorarlos.

Durante todo el libro se destacan buenas practicas como el uso de los principios del software (DRY, KISS, y S.O.L.I.D por ejemplo), la importancia del refactoring, la importancia de que el software sea altamente depurable, el rol que juega el manager en un proyecto, la capacidad de resilencia de un profesional, y otros muchos aspectos que es mejor conocerlos con la lectura del libro que a través de esta entrada.

lunes, 2 de marzo de 2015

Otorgar permisos en carpeta /var/www/html (Apache + Linux)

Si tenemos un servidor web apache sobre Linux que está recién instalado, es probable que al intentar guardar archivos en la carpeta /var/www/html (que es donde se alojan las páginas y aplicaciones web) tengamos problemas porque nuestra cuenta de usuario no cuenta con permisos de escritura.

Una manera de solucionarlo es otorgar todos lo permisos sobre dicha carpeta con el comando chmod:
sudo chmod 777 /var/www/html 

Sin embargo esta solución no es la mejor en términos de seguridad, ya que le estamos dando permisos de lectura y escritura a cualquier usuario del sistema, dando la posibilidad de que cualquiera pueda modificar los archivos de nuestras aplicaciones con o sin autorización.

Una solución más segura es cambiar el propietario de la carpeta /var/www/html para que seamos nosotros mismos a través de nuestra cuenta de usuario. Suponiendo que nuestra cuenta es "webmaster", usando el comando chown podemos cambiar el propietario así:

sudo chown webmaster /var/www/html

Así podremos acceder de forma remota mediante FTP o SSH por ejemplo, haciendo uso de nuestra cuenta de usuario con la posibilidad de leer y escribir datos.

martes, 17 de febrero de 2015

La noche que Himmler conoció a Borges [Leído]

Hace tiempo que no compartía en este espacio una breve reseña (no profesional) de los libros que voy leyendo, por lo cual para no perder la costumbre en esta entrada comparto mis opiniones de un libro que tuve la oportunidad de leer recientemente. Se trata de la novela La noche que Himmler conoció a Borges, escrita por Javier Cosnava, que se puede clasificar como una novela histórica. 

La noche que Himmler conoció a Borges
La noche que Himmler conoció a Borges
Como se explica en su descripción, la novela se desarrolla cuando Himmler es capturado al finalizar la guerra, noche en la cual luego de ser sometido a revisiones médicas se da el encuentro con el escritor Jorge Luis Borges, quien se encuentra escribiendo un relato llamado Réquiem Alemán y espera conocer de primera mano la vida de Himmler para comprender mejor el nazismo. 

A lo largo de su encuentro, que dura hasta el amanecer, ambos personajes hablan de política, literatura, filosofía, religión y diversos temas; lo cual da pie para que a la par se vaya revelando la biografía de uno de los más grandes criminales de la historia.

En los diferentes pasajes se puede apreciar la vida de Himmler desde su niñez hasta su captura, mostrando detalles y vivencias que llevaron poco a poco a convertrilo en uno de los seres humanos más despiadados de la faz de la tierra.

Lo que me llevó a su lectura fue principalmente mi gusto por las novelas históricas, además del interés de conocer un poco más la vida de este personaje y de las ideas que fundamentan el nazismo. La novela no me defraudó, me pareció bien elaborada, bien compuesta por lps crudos y tristes que pueden ser los relatos de la Europa en guerra de comienzos del siglo XX.

Al final del libro hay una nota del autor que nos ayuda a comprender un poco mejor la historia, pero ojo, leerla antes de terminar podría dañar un poco el "encanto" del libro. 

lunes, 16 de febrero de 2015

Evitar que excel pregunte si se desean guardar los cambios cuando se cierra un archivo

Supongamos que tenemos un archivo de excel con una macro, la cual abre otro archivo para leer y procesar datos contenidos en el mismo. Si sobre ese archivo hacemos cambios y lo cerramos, nos aparecerá un recuadro preguntándonos si deseamos guardar los cambios realizados:

Guardar cambios al cerrar en excel
Guardar cambios al cerrar en excel

Mientras aparece este cuadro de dialogo la ejecución de la macro se pausará hasta que el usuario seleccione una opción. Si no necesitamos que se guarden los cambios en el archivo y queremos prescindir de esta funcionalidad, podemos omitir este recuadro cerrando el archivo con la siguiente línea:

Workbooks(NombreArchivo).Close savechanges:=False

Con el parámetro savechanges:=False le estamos diciendo a Excel que no pregunte por los cambios realizados; sin embargo, podrán aparecer otros mensajes como por ejemplo el que nos dice que el portapapeles tiene mucha información y que si deseamos tenerla disponible cuando cerremos el archivo; para evitar estos mensajes extras debemos añadir dos líneas más:

Application.DisplayAlerts = False ' Desactivo todo tipo de alertas
Workbooks(Exporte).Close savechanges:=False ' Cierro el archivo
Application.DisplayAlerts = True ' Activo de nuevo todas las alertas

Con lo anterior simplificamos la ejecución de la macro evitando al usuario tener que estar haciendo clic cada que se cierre un archivo, mucho más si la cantidad de archivos que se abren y cierra es considerable.

martes, 27 de enero de 2015

Uso de include() y require() en PHP

A la hora de necesitar incluir código que está contenido en otros archivos, PHP nos ofrece cuatro funciones: include(), require(), include_once(), y require_once(). A simple vista se podría decir que todas funcionan igual, sin embargo en realidad difieren entre sí por características específicas que se deben tener en cuenta a la hora de optar por alguna y que se describen a continuación:

  • include() como sugiere, incluye todo el código de un archivo que le especifiquemos para que dicho código sea evaluado por el intérprete de PHP. El archivo puede ser incluido tantas veces como deseemos y si por alguna razón  no existe o no es accesible, el script desde dónde se está llamando se continuará ejecutando y el intérprete nos arrojará una alerta.
  • include_once() hace lo mismo que include(), pero a diferencia de ésta sólo permite incluir una vez al archivo. Esto nos resulta últil para evitar conflictos con la declaración de variables y demás objetos, así como para no afectar el rendimiento de la aplicación.
  • require() hace también lo mismo que include(), pero a diferencia de la segunda si el archivo que se está llamando no existe la ejecución del script se detendrá.
  • require_once() se comporta como require(), pero como lo hace include_once() no permite que se incluya el archivo más de una vez.

Finalmente al utilizar alguna de estas sentencias es importante tener en cuenta que:

  • Las cuatro son sentencias, no son métodos; por lo cual debemos evitar colocar el nombre del archivo entre paréntesis, solo basta con colocarlo entre comillas dobles.
  • La ejecución de include_once y require_once tiende a ser más lenta que la de include y de require; por lo cual mientras el ámbito del proyecto no lo requiera es recomendable hacer uso de éstas dos últimas.
  • Como buena practica de seguridad, es recomendable que si los archivos que se incluyen manejan información sensible éstos estén  contenidos en directorios protegidos.

sábado, 24 de enero de 2015

Como optimizar la ejecución de una macro de excel y no morir en el intento

Las macros de excel son una buena alternativa cuando se requiere automatizar procesos que involucran cálculos y tratamiento de datos de forma repetitiva, gracias a que su programación resulta relativamente fácil y que es fácil contar con un equipo con el Excel instalado.

En los entornos productivos, con el paso del tiempo las macros que vamos escribiendo suelen crecer en tamaño y complejidad por cuenta de la dinámica de los procesos y del negocio, lo cual suele llevar a que el código se vuelva en lento y poco óptimo. 

Para evitar lo anterior, como en cualquier desarrollo de software, es importante adoptar buenas prácticas entre las cuales se pueden destacar los siguientes principios del desarrollo de software:

  • DRY (Don't repeat yourself - No te repitas): que básicamente consiste en que se debe eliminar al máximo la duplicidad de procesos, o en este caso de instrucciones, para lo cual es fundamental hacer uso de funciones, clases, módulos y demás elementos que proveen los lenguajes de programación (para el caso de este artículo vba de excel) y sus paradigmas.
  • KISS (Keep It Simple, Stupid - Mantenlo simple, estúpido): el cual establece que un sistema funciona mejor si se elimina al máximo la complejidad en su diseño.
  • YAGNI (You ain't gonna need it - No vas a necesitarlo): el cual consiste en que una funcionalidad que no va a ser utilizada no debe ser implementada.

Pero más allá de la metodología que se adopte para los procesos de desarrollo, también es importante desde la misma creación del código fuente contar con buenas practicas para que al momento de ejecutar nuestros programas el tiempo que estos se tarden ene ejecutarseb sea el mejor.

A continuación comparto algunas de las practicas que suelo realizar al escribir el código de las macros de excel, las cuales naturalmente no son todas las posibles, pero que en mi caso me han sido de gran utilidad para optimizar el rendimiento de las mismas.

Deshabilitar algunas funcionalidades propias de excel

Una de las cosas que más ralentizan la ejecución de una macro son el hecho de que todo el proceso que estas hacen se muestra en pantalla, por lo cual suelo deshabilitar esta característica mientras se ejecuta el código de la macro así:

Application.screenupdating=False

Con esto cada vez que se ejecute el código, no se verá en pantalla todo el proceso sino que la macro se ejcutará de una manera "más silenciosa". Una vez se termine la rutina o proceso que estamos codificando solo basta con cambiar de nuevo el valor a true:

Application.screenupdating=True

También es bueno deshabilitar otras características como los cálculos y eventos automáticos:

Application.calculation=xlCalculationManual
Application.EnableEvents=False

Con base a lo anterior así sería el ejemplo de una macro con las modificaciones mencionadas:

Private Sub Worksheet_Activate()
    ' Declaro e inicializco variables
    Dim NumeroPagos As Long
    NumeroPagos = 0
    
    Application.ScreenUpdating = False ' Deshabilito actualización en pantalla
    Application.Calculation = xlCalculationManual ' Deshabilito los cáculos automáticos
    Application.EnableEvents = False ' Deshabilito los eventos automáticos
    ActiveSheet.PivotTables("Resumen Pagos").PivotCache.Refresh 'Actualizo la tabla dinámica
    NumeroPagos = Range("A" & Rows.Count).End(xlUp).Row ' Obtengo la cantidad de registros en la hoja
    Application.DisplayStatusBar = True ' Activo la barra de estado
    Application.StatusBar = "Hay " & NumeroPagos & " registros." ' Cambio el contenido de la barra de estado
    Application.ScreenUpdating = False ' Habilito de nuevo la actualización en pantalla
    Application.Calculation = xlCalculationAutomatic ' Habilito de nuevo los cálculos automáticos
    Application.EnableEvents = False ' Habilito de nuevo los eventos automáticos
End Sub


Centralizar a la medida de lo posible el código fuente

Siendo consecuentes con los principios mencionados al comienzo de la entrada, una buena practica es centralizar el código fuente que contiene funciones y rutinas utilizando módulos, y hacer uso de estas a través de los diferentes eventos disponibles en cada hoja.

Utilizar la instrucción with para trabajar con los objetos

Si se necesita trabajar con un objeto como una hoja, un rango, o una gráfica por ejemplo; es más óptimo acceder a éste y manipularlo con la instrucción with ya que solo debo hacer referencia al objeto una vez:

' De la forma tradicional debo hacer referencia al objeto en cada línea
ActiveWorkbook.Sheets(1).Range("A1:A3").Font.Size = 12
ActiveWorkbook.Sheets(1).Range("A1:A3").Font.Name = "Calibri"
ActiveWorkbook.Sheets(1).Range("A1:A3").Font.Bold = True
    
' Usando With solo lo debo hacer una vez, lo cual optimiza el tiempo de ejecución
With ActiveWorkbook.Sheets(1).Range("A1:A3").Font
        .Size = 12
        .Name = "Calibri"
        .Bold = True
End With

Usar las formulas directamente desde visual basic

Haciendo uso del método WorksheetFunction  del objeto Application se pueden ejecutar las mismas formulas que se tienen disponibles en la hoja de cálculo, teniendo en cuenta que al usarlas desde excel éstas están con su nombre en inglés. Por ejemplo:

' Escribo la fecha y hora actuales usando la función AHORA()
Range("A").Value = Application.WorksheetFunction _
.now()

Conclusiones


Los puntos descritos en esta entrada no son los definitivos, existen muchos más "trucos" y buenas practicas que contribuyen a optimizar el tiempo de ejecución. En términos generales las buenas practicas que se aplican en otros lenguajes de programación se pueden aplicar con éxito a la hora de escribir macros.

El tiempo de ejecución de una macro es un factor importante para mejorar la experiencia del usuario final u optimizar el proceso, y más aún si estamos en un entorno corporativo donde el tiempo es valioso; por lo cual, desde la misma etapa de diseño de una solución se debe apuntar a hacer uso de las mejores practicas de programación.

jueves, 22 de enero de 2015

Nikto: alternativa Open Source para auditar nuestras aplicaciones web

Nikto es una herramienta Open Source escrita en Perl, cuyo objetivo es auditar la seguridad de servidores web buscando problemas y alertas relacionadas con errores de configuración, software desactualizado, configuraciones por defecto, programas y archivos inseguros, y demás posibles vectores de ataque.

Funciona bajo Linux, Windows, MAC OSX y múltiples otras variantes de UNIX. Es una herramienta diseñada para la evaluación de sistemas, por lo cual su funcionamiento no pasa desapercibido ante herramientas de defensa como los IDS por ejemplo. Al ser una herramienta de diagnóstico es importante saber que sólo nos arroja información y no provee ningún mecanismo de ataque.

Para su instalación sólo basta con cumplir ciertos requerimientos, descargarlo e instalarlo; de hecho en muchas distribuciones viene incluido en los repositorios por lo que solo basta instalarlo desde la línea de comandos usando el gestor de paquetes de nuestra distribución Linux. Para mi caso que uso Elementary (también funciona en Debian, Ubuntu y similares) sólo basta con teclear en la consola:

sudo apt-get install nikto

Una vez instalado, para auditar un servidor solo basta con ejecutar el programa con los siguientes parámetros:

nikto -host [direccion o hostname del servidor]

Por ejemplo:

nikto -host 192.168.0.1

Con esto el programa comenzará a auditar el servidor, proceso que dura varios minutos, y comenzará a arrojar información relacionada con el software que tiene instalado, servicios que presta, CGIs, módulos habilitados, aplicaciones instaladas, archivos, directorios, vulnerabilidades encontradas con su respectivo identificador y toda posible información.

Auditando la seguridad de un servidor con Nikto
Auditando la seguridad de un servidor con Nikto
Nikto ofrece diferentes opciones para parametrizar la auditoria, como por ejemplo especficar por cuales puertos se deben hacer las peticiones, si se debe usar un proxy, se se debe usar SSL a la fuerza, si se deben usar algunos de sus plugins, entre otras; esta es la lista de opciones se encuentra disponible ejecutando nikto -h.

Es importante resaltar que toda la información que muestra el programa no necesariamente representa una amenaza de seguridad, sin embargo nos permite tener una completa visión de como un posible atacante ve nuestro sistema. Un escenario que no respresenta un riesgo es que por ejemplo nos puede mostrar que en el servidor hay instaladas aplicaciones conocidas como wordpress, phpmyadmin, entre otras; las cuales en si no representan algún riesgo (si están bien configuradas claro está).

Todo esfuerzo para proteger la información e infraestructura que soporta nuestros sistemas de información no sobra, y más aún cuando estamos hablando de entornos productivos. Si bien en el mercado existen múltiples herramientas para probar y explotar la inseguridad de un servidor y/o aplicación, nikto hace muy bien su trabajo y de una forma simple.

Como desarrolladores no está demás que en los procesos de desarrollo incluyamos actividades enfocadas a la seguridad informática y a la seguridad de la información, para que desde su concepción la calidad de nuestros productos sea la mejor posible.

Para más información de la herramienta y su funcionamiento podemos consultar su documentación oficial que están en inglés.

lunes, 19 de enero de 2015

Protegiendo directorios en aplicaciones que corren sobre Apache

Uno de los errores más frecuentes al desarrollar aplicaciones web es dejar directorios críticos accesibles a cualquier persona, los cuales pueden contener archivos y scripts con información sensible que solo debería ser visible a usuarios autorizados o a la propia aplicación.

Ejemplo de acceso a un directorio web por cualquiera
Ejemplo de acceso a un directorio web por cualquiera

En el ejemplo anterior se ve como es posible acceder al contenido de un directorio y explorar sus archivos, e incluso descargar y visualizar su contenido dependiendo de su naturaleza. Lo anterior se da porque no hay un archivo "index" que es el primero que ejecuta el servidor Apache, por lo cual la solución más inmediata es definir un archivo index que muestre un mensaje al usuario cuando intente acceder al directorio o que automáticamente lo redireccione a otro lugar.

Por ejemplo con php el contenido del index podría ser:

header("Location: ../error_acceso.php")

Y el contenido del archivo error.php sería algo como:

echo 'Usted no tiene permisos para acceder a esta sección!
Contactar al administrador';

Error de acceso a directorio personalizado
Error de acceso a directorio personalizado con PHP

Otra manera de asegurar un directorio es haciendo uso del propio servidor Apache (el servidor http más usado en internet), el cual nos provee un mecanismo que permite mediante un archivo de configuración creado por nosotros mismos, agregar diferentes características a los directorios que conforman una aplicación web, entre ella la autenticación.

Para añadir autenticación (acceso con usuario y contraseña) a un directorio lo primero que debemos hacer es crear un archivo de texto plano llamado .htaccess el cual debe ser guardado en el directorio que debemos proteger y cuyo contenido debe ser algo como esto:

AuthName "Acceso restringido"
AuthType Basic
AuthUserFile /opt/lampp/var/.htpasswd
AuthGroupFile /dev/null
require valid-user

Lo cual en resumen es lo siguiente:

  • La primera línea especifica el texto que se mostrará en la ventana de autenticación
  • La segunda línea especifica que será una atenticación básica usando el módulo mod_auth_basic de apache. Más información aquí.
  • La tercera línea indica el archivo .httpasswd donde están almacenados el usuario y clave válidos, el cual se explicará unas líneas más adelante.
  • La cuarta línea especfica la ubicación de la lista de usuarios autorizados para autenticarse, que este caso es ninguna (null) ya que solo usaremos el que esté especificado en el archivo .htpasswd.
  • La quinta y última línea indica que solo tendrán acceso los usuario válidos (previamente autenticados).

Finalmente se debe generar el archivo .htpasswd que contendrá el nombre de usuario y la clave encriptada válidos para acceder al directorio. Para generarlo sólo basta con acceder a la carpeta bin de nuestra instalación de apache, que para mi caso que estoy sobre linux y uso XAMPP es /opt/lampp/bin, y desde allí ejecutar el programa httpasswd así:

sudo ./htpasswd -c /opt/lampp/var/.httpasswd usuario

Donde  /opt/lampp/var es la ruta donde se guadará el archivo, la cual debe coincidir con la especificada en el archivo .htaccess y debe ser una ruta interna accesible por la aplicación pero no accesible desde internet (por seguridad no usar ubicaciones contenidas en los archivos htdocs, www o similares); y usuario será el nombre de usuario que queremos usar para autenticarnos. una vez lo ejecutemos el programa nos preguntará la clave que asignaremos, la escribimos y la confirmamos:


Ejecutando httpasswd de apache
Ejecutando httpasswd de apache
Y listo, una vez creados los archivos y si apache tiene la configuración correcta con los módulos necesarios habilitados, cada vez que se intente acceder al directorio protegido el navegador nos solicitará usuario y clave; sin embargo no debemos ser confiados y usando el sentido común debemos evitar a la medida de lo posible publicar información sensible en los directorios y archivos de las aplicaciones web.