Debe introducir al menos 3 caracteres en el buscador.
Inicio / Wikis / Tutoriales / Seguridad en Unix y redes - Programación segura

Seguridad en Unix y redes - Programación segura

 ****- (7 opiniones)
GNU Free Documentation License Tutorial de Antonio Villalón Huerta - 28 de Febrero de 2006
Temas Relacionados: Seguridad informática
24. Programación segura
Parece obvio que después de analizar los problemas que un código malicioso o simplemente mal diseñado puede causar, dediquemos un apartado a comentar brevemente algunos aspectos a tener en cuenta a la hora de crear programas seguros. Vamos a hablar de programación en C, obviamente por ser el lenguaje más utilizado en Unix; para aquellos interesados en la seguridad de otros lenguajes que también se utilizan en entornos Unix, existen numerosos artículos que hablan de la programación segura - e insegura - en lenguajes que van desde Java ([MS98], [DFW96], [Gal96b]...) a SQL ([PB93]).
El principal problema de la programación en Unix lo constituyen los programas setuidados; si un programa sin este bit activo tiene un fallo, lo normal es que ese fallo solamente afecte a quien lo ejecuta. Al tratarse de un error de programación, algo no intencionado, su primera consecuencia será el mal funcionamiento de ese programa. Este esquema cambia radicalmente cuando el programa está setuidado: en este caso, el error puede comprometer tanto a quien lo ejecuta como a su propietario, y como ese propietario es por norma general el root automáticamente se compromete a todo el sistema. Para la codificación segura de este tipo de programas, [Bis86] proporciona unas líneas básicas:
  • Máximas restricciones a la hora de elegir el UID y el GID.
    Una medida de seguridad básica que todo administrador de sistemas Unix ha de seguir es realizar todas las tareas con el mínimo privilegio que estas requieran ([Sim90]); así, a nadie se le ocurre (o se le debería ocurrir) conectar a IRC o aprender a manejar una aplicación genérica bajo la identidad de root. Esto es directamente aplicable a la hora de programar: cuando se crea un programa setuidado (o setgidado) se le ha de asignar tanto el UID como el GID menos peligroso para el sistema. Por ejemplo, si un programa servidor se limita a mostrar un mensaje en pantalla y además escucha en un puerto por encima de 1024, no necesita para nada estar setuidado a nombre de root (realmente, es poco probable que ni siquiera necesite estar setuidado); si pensamos en un posible error en dicho programa que permita a un atacante obtener un shell vemos claramente que cuanto menos privilegio tenga el proceso, menos malas serán las posibles consecuencias de tal error.
  • Reset de los UIDs y GIDs efectivos antes de llamar a exec().
    Uno de los grandes problemas de los programas setuidados es la ejecución de otros programas de manera inesperada; por ejemplo, si el usuario introduce ciertos datos desde teclado, datos que se han de pasar como argumento a otra aplicación, nada nos asegura a priori que esos datos sean correctos o coherentes. Por tanto, parece obvio resetear el UID y el GID efectivos antes de invocar a exec(), de forma que cualquier ejecución inesperada se realice con el mínimo privilegio necesario; esto también es aplicable a funciones que indirectamente realicen el exec(), como system() o popen().
  • Es necesario cerrar todos los descriptores de fichero, excepto los estrictamente necesarios, antes de llamar a exec().
    Los descriptores de ficheros son un parámetro que los procesos Unix heredan de sus padres; de esta forma, si un programa setuidado está leyendo un archivo, cualquier proceso hijo tendrá acceso a ese archivo a no ser que explícitamente se cierre su descriptor antes de ejecutar el exec().
    La forma más fácil de prevenir este problema es activando un flag que indique al sistema que ha de cerrar cierto descriptor cada vez que se invoque a exec(); esto se consigue mediante las llamadas fcntl() e ioctl().
  • Hay que asegurarse de que chroot() realmente restringe.
    Los enlaces duros entre directorios son algo que el núcleo de muchos sistemas Unix no permiten debido a que genera bucles en el sistema de ficheros, algo que crea problemas a determinadas aplicaciones; por ejemplo, Linux no permite crear estos enlaces, pero Solaris o Minix sí. En estos últimos, en los clones de Unix que permiten hard links entre directorios, la llamada chroot() puede perder su funcionalidad: estos enlaces pueden seguirse aunque no se limiten al entorno con el directorio raíz restringido. Es necesario asegurarse de que no hay directorios enlazados a ninguno de los contenidos en el entorno chroot() (podemos verlo con la opción `-l' de la orden ls, que muestra el número de enlaces de cada archivo).
  • Comprobaciones del entorno en que se ejecutará el programa.
    En Unix todo proceso hereda una serie de variables de sus progenitores, como el umask, los descriptores de ficheros, o ciertas variables de entorno ($PATH, $IFS...); para una ejecución segura, es necesario controlar todos y cada uno de estos elementos que afectan al entorno de un proceso. Especialmente críticas son las funciones que dependen del shell para ejecutar un programa, como system() o execvp(): en estos casos es muy difícil asegurar que el shell va a ejecutar la tarea prevista y no otra. Por ejemplo, imaginemos el siguiente código:#include <stdlib.h> main(){ system("ls"); } A primera vista, este programa se va a limitar a mostrar un listado del directorio actual; no obstante, si un usuario modifica su $PATH de forma que el directorio `.' ocupe el primer lugar, se ejecutará ./ls en lugar de /bin/ls. Si el programa ./ls fuera una copia del shell, y el código anterior estuviera setuidado por el root, cualquier usuario podría obtener privilegios de administrador.
    Quizás alguien puede pensar que el problema se soluciona si se indica la ruta completa (/bin/ls) en lugar de únicamente el nombre del ejecutable; evidentemente, esto arreglaría el fallo anterior, pero seguirían siendo factibles multitud de ataques contra el programa. Desde la modificación del $IFS (como veremos más adelante) hasta la ejecución en entornos restringidos, existen muchísimas técnicas que hacen muy difícil que un programa con estas características pueda ser considerado seguro.
  • Nunca setuidar shellscripts.
    Aunque en muchos sistemas Unix la activación del bit setuid en shellscripts no tiene ningún efecto, muchos otros aún permiten que los usuarios - especialmente el root - creen procesos interpretados y setuidados. La potencia de los intérpretes de órdenes de Unix hace casi imposible controlar que estos programas no realicen acciones no deseadas, violando la seguridad del sistema, por lo que bajo ningún concepto se ha de utilizar un proceso por lotes para realizar acciones privilegiadas de forma setuidada.
  • No utilizar creat() para bloquear.
    Una forma de crear un fichero de bloqueo es invocar a creat() con un modo que no permita la escritura del archivo (habitualmente el 000), de forma que si otro usuario tratara de hacer lo mismo, su llamada a creat() fallaría. Esta aproximación, que a primera vista parece completamente válida, no lo es tanto si la analizamos con detalle: en cualquier sistema Unix, la protección que proporcionan los permisos de un fichero sólo es aplicable si quien trata de acceder a él no es el root. Si esto es así, es decir, si el UID efectivo del usuario que está accediendo al archivo es 0, los permisos son ignorados completamente y el acceso está permitido; de esta forma, el root puede sobreescribir archivos sin que le importen sus bits rwx, lo que implica que si uno de los procesos que compiten por el recurso bloqueado está setuidado a nombre del administrador, el esquema de bloqueo anterior se viene abajo.
    Para poder bloquear recursos en un programa setuidado se utiliza la llamada link(), ya que si se intenta crear un enlace a un fichero que ya existe link() falla aunque el proceso que lo invoque sea propiedad del root (y aunque el fichero sobre el que se realice no le pertenezca).También es posible utilizar la llamada al sistema flock() de algunos Unices, aunque es menos recomendable por motivos de portabilidad entre clones.
  • Capturar todas las señales.
    Un problema que puede comprometer la seguridad del sistema Unix es el volcado de la imagen en memoria de un proceso cuando éste recibe ciertas señales (el clásico core dump). Esto puede provocar el volcado de información sensible que el programa estaba leyendo: por ejemplo, en versiones del programa login de algunos Unices antiguos, se podía leer parte de /etc/shadow enviando al proceso la señal SIGTERM y consultando el fichero de volcado.
    No obstante, este problema no resulta tan grave como otro también relacionado con los core dump: cuando un programa setuidado vuelca su imagen el fichero resultante tiene el mismo UID que el UID real del proceso. Esto puede permitir a un usuario obtener un fichero con permiso de escritura para todo el mundo pero que pertenezca a otro usuario (por ejemplo, el root): evidentemente esto es muy perjudicial, por lo que parece claro que en un programa setuidado necesitamos capturar todas las señales que Unix nos permita (recordemos que SIGKILL no puede capturarse ni ignorarse, por norma general).
  • Hay que asegurarse de que las verificaciones realmente verifican.
    Otra norma básica a la hora de escribir aplicaciones setuidadas es la desconfianza de cualquier elemento externo al programa; hemos de verificar siempre que las entradas (teclado, ficheros...) son correctas, ya no en su formato sino más bien en su origen: >de quién proviene un archivo del que nuestro programa lee sus datos, de una fuente fiable o de un atacante que por cualquier método - no nos importa cuál - ha conseguido reemplazar ese archivo por otro que él ha creado?
  • Cuidado con las recuperaciones y detecciones de errores.
    Ante cualquier situación inesperada - y por lo general, poco habitual, incluso forzada por un atacante - un programa setuidado debe detenerse sin más; nada de intentar recuperarse del error: detenerse sin más. Esto, que quizás rompe muchos de los esquemas clásicos sobre programación robusta, tiene una explicación sencilla: cuando un programa detecta una situación inesperada, a menudo el programador asume condiciones sobre el error (o sobre su causa) que no tienen por qué cumplirse, lo que suele desembocar en un problema más grave que la propia situación inesperada. Para cada posible problema que un programa encuentre (entradas muy largas, caracteres erróneos o de control, formatos de datos erróneos...) es necesario que el programador se plantee qué es lo que su código debe hacer, y ante la mínima duda detener el programa.
  • Cuidado con las operaciones de entrada/salida.
    La entrada/salida entre el proceso y el resto del sistema constituye otro de los problemas comunes en programas setuidados, especialmente a la hora de trabajar con ficheros; las condiciones de carrera aquí son algo demasiado frecuente: el ejemplo clásico se produce cuando un programa setuidado ha de escribir en un archivo propiedad del usuario que ejecuta el programa (no de su propietario). En esta situación lo habitual es que el proceso cree el fichero, realize sobre él un chown() al rUID y al rGID del proceso (es decir, a los identificadores de quién está ejecutando el programa), y posteriormente escriba en el archivo; el esqueleto del código sería el siguiente:fd=open("fichero",O_CREAT); fchown(fd,getuid(),getgid()); write(fd,buff,strlen(buff)); Pero, >qué sucede si el programa se interrumpe tras realizar el open() pero antes de invocar a fchown(), y además el umask del usuario es 0? El proceso habrá dejado un archivo que pertenece al propietario del programa (generalmente el root) y que tiene permiso de escritura para todo el mundo. La forma más efectiva de solucionar el problema consiste en que el proceso engendre un hijo mediante fork(), hijo que asignará a sus eUID y eGID los valores de su rUID y rGID (los identificadores del usuario que lo ha ejecutado, no de su propietario). El padre podrá enviar datos a su hijo mediante pipe(), datos que el hijo escribirá en el fichero correspondiente: así el fichero en ningún momento tendrá por qué pertenecer al usuario propietario del programa, con lo que evitamos la condición de carrera expuesta anteriormente.

Sin embargo, un correcto estilo de programación no siempre es la solución a los problemas de seguridad del código; existen llamadas a sistema o funciones de librería que son un clásico a la hora de hablar de bugs en nuestro software. Como norma, tras cualquier llamada se ha de comprobar su valor de retorno y manejar los posibles errores que tenga asociados ([Sho00]), con la evidente excepción de las llamadas que están diseñadas para sobreescribir el espacio de memoria de un proceso (la familia exec() por ejemplo) o las que hacen que el programa finalice (típicamente, exit()) . Algunas de las llamadas consideradas más peligrosas (bien porque no realizan las comprobaciones necesarias, bien porque pueden recibir datos del usuario) son las siguientes6.5:

  • system(): Esta es la llamada que cualquier programa setuidado debe evitar a toda costa. Si aparece en un código destinado a ejecutarse con privilegios, significa casi con toda certeza un grave problema de seguridad; en algunas ocasiones su peligrosidad es obvia (por ejemplo si leemos datos tecleados por el usuario y a continuación hacemos un system() de esos datos, ese usuario no tendría más que teclear /bin/bash para conseguir los privilegios del propietario del programa), pero en otras no lo es tanto: imaginemos un código que invoque a system() de una forma similar a la siguiente:#include <stdio.h> #include <stdlib.h> main(){ system("/bin/ls"); } El programa anterior se limitaría a realizar un listado del directorio desde el que lo ejecutemos. Al menos en teoría, ya que podemos comprobar que no es difícil `engañar' a system(): no tenemos más que modificar la variable de entorno $IFS (Internal Field Separator) del shell desde el que ejecutemos el programa para conseguir que este código ejecute realmente lo que nosotros le indiquemos. Esta variable delimita las palabras (o símbolos) en una línea de órdenes, y por defecto suele estar inicializada a Espacio, Tabulador, y Nueva Línea (los separadores habituales de palabras); pero, >qué sucede si le indicamos al shell que el nuevo carácter separador va a ser la barra, `/'?. Muy sencillo: ejecutar `/bin/ls' será equivalente a ejecutar `bin ls', es decir, una posible orden denominada `bin' que recibe como parámetro `ls'. Por ejemplo, bajo SunOS - bajo la mayoría de Unices -, y utilizando sh (no bash) podemos hacer que `bin' sea un programa de nuestra elección, como `id':$ cp /bin/id bin $ ejemplo bin ejemplo.c ejemplo $ IFS=/ $ export IFS $ ejemplo uid=672(toni) gid=10(staff) $ Como podemos ver, acabamos de ejecutar un programa arbitrario; si en lugar de `id' hubiéramos escogido un intérprete de órdenes, como `bash' o `sh', habríamos ejecutado ese shell. Y si el programa anterior estuviera setudiado, ese shell se habría ejecutado con los privilegios del propietario del archivo (si imaginamos que fuera root, podemos hacernos una idea de las implicaciones de seguridad que esto representa).
  • exec(), popen(): Similares a la anterior; es preferible utilizar execv() o execl(), pero si han de recibir parámetros del usuario sigue siendo necesaria una estricta comprobación de los mismos.
  • setuid(), setgid()...: Los programas de usuario no deberían utilizar estas llamadas, ya que no han de tener privilegios innecesarios.
  • strcpy(), strcat(), sprintf(), vsprintf()...: Estas funciones no comprueban la longitud de las cadenas con las que trabajan, por lo que son una gran fuente de buffer overflows. Se han de sustituir por llamadas equivalentes que sí realicen comprobación de límites (strncpy(), strncat()...) y, si no es posible, realizar dichas comprobaciones manualmente.
  • getenv(): Otra excelente fuente de desbordamientos de buffer; además, el uso que hagamos de la información leída puede ser peligroso, ya que recordemos que es el usuario el que generalmente puede modificar el valor de las variables de entorno. Por ejemplo, >qué sucedería si ejecutamos desde un programa una orden como `cd $HOME', y resulta que esta variable de entorno no corresponde a un nombre de directorio sino que es de la forma `/;rm -rf /'? Si algo parecido se hace desde un programa que se ejecute con privilegios en el sistema, podemos imaginarnos las consecuencias...
  • gets(), scanf(), fscanf(), getpass(), realpath(), getopt()...: Estas funciones no realizan las comprobaciones adecuadas de los datos introducidos, por lo que pueden desbordar en algunos casos el buffer destino o un buffer estático interno al sistema. Es preferible el uso de read() o fgets() siempre que sea posible (incluso para leer una contraseña, haciendo por supuesto que no se escriba en pantalla), y si no lo es al menos realizar manualmente comprobaciones de longitud de los datos leídos.
  • gethostbyname(), gethostbyaddr(): Seguramente ver las amenazas que provienen del uso de estas llamadas no es tan inmediato como ver las del resto; generalmente hablamos de desbordamiento de buffers, de comprobaciones de límites de datos introducidos por el usuario...pero no nos paramos a pensar en datos que un atacante no introduce directamente desde teclado o desde un archivo, pero cuyo valor puede forzar incluso desde sistemas que ni siquiera son el nuestro. Por ejemplo, todos tendemos a asumir como ciertas las informaciones que un servidor DNS - más o menos fiables, por ejemplo alguno de nuestra propia organización - nos brinda. Imaginemos un programa como el siguiente (se han omitido las comprobaciones de errores habituales por cuestiones de claridad):#include <stdio.h> #include <stdlib.h> #include <netdb.h> #include <unistd.h> #include <arpa/inet.h> int main(int argc, char argv){ struct in_addr *dir=(struct in_addr *)malloc(sizeof(struct in_addr)); struct hostent *maquina=(struct hostent *)malloc(sizeof(struct \ hostent)); char *orden=(char *)malloc(30); dir->s_addr=inet_addr(*++argv); maquina=gethostbyaddr((char *)dir,sizeof(struct in_addr),AF_INET); sprintf(orden,"finger @%s\n",maquina->h_name); system(orden); return(0); } Este código recibe como argumento una dirección IP, obtiene su nombre vía /etc/hosts o DNS,y ejecuta un finger sobre dicho nombre; aparte de otros posibles problemas de seguridad (por ejemplo, >seríamos capaces de procesar cualquier información que devuelva el finger?, >qué sucede con la llamada a system()?), nada extraño ha de suceder si el nombre de máquina devuelto al programa es `normal':luisa:~/tmp$ ./ejemplo 192.168.0.1 [rosita] No one logged on. luisa:~/tmp$ Pero, >qué pasaría si en lugar de devolver un nombre `normal' (como `rosita') se devuelve un nombre algo más elaborado, como `rosita;ls'? Podemos verlo:luisa:~/tmp$ ./ejemplo 192.168.0.1 [rosita;ls] No one logged on. ejemplo ejemplo.c luisa:~/tmp$ Exactamente: se ha ejecutado la orden `finger @rosita;ls' (esto es, un `finger' a la máquina seguido de un `ls'). Podemos imaginar los efectos que tendría el uso de este programa si sustituimos el inocente `ls' por un `rm -rf $HOME'. Un atacante que consiga controlar un servidor DNS (algo no muy complicado) podría inyectarnos datos maliciosos en nuestra máquina sin ningún problema. Para evitar esta situación debemos hacer una doble búsqueda inversa y además no hacer ninguna suposición sobre la corrección o el formato de los datos recibidos; en nuestro código debemos insertar las comprobaciones necesarias para asegurarnos de que la información que recibimos no nos va a causar problemas.
  • syslog(): Hemos de tener la precaución de utilizar una versión de esta función de librería que compruebe la longitud de sus argumentos; si no lo hacemos y esa longitud sobrepasa un cierto límite (generalmente, 1024 bytes) podemos causar un desbordamiento en los buffers de nuestro sistema de log, dejándolo inutilizable.
  • realloc(): Ningún programa - privilegiado o no - que maneje datos sensibles (por ejemplo, contraseñas, correo electrónico...y especialmente aplicaciones criptográficas) debe utilizar esta llamada; realloc() se suele utilizar para aumentar dinámicamente la cantidad de memoria reservada para un puntero. Lo habitual es que la nueva zona de memoria sea contigua a la que ya estaba reservada, pero si esto no es posible realloc() copia la zona antigua a una nueva ubicación donde pueda añadirle el espacio especificado. >Cuál es el problema? La zona de memoria antigua se libera (perdemos el puntero a ella) pero no se pone a cero, con lo que sus contenidos permanecen inalterados hasta que un nuevo proceso reserva esa zona; accediendo a bajo nivel a la memoria (por ejemplo, leyendo /proc/kcore o /dev/kmem) sería posible para un atacante tener acceso a esa información.
    Realmente, malloc() tampoco pone a cero la memoria reservada, por lo que a primera vista puede parecer que cualquier proceso de usuario (no un acceso a bajo nivel, sino un simple malloc() en un programa) podría permitir la lectura del antiguo contenido de la zona de memoria reservada. Esto es falso si se trata de nueva memoria que el núcleo reserva para el proceso invocador: en ese caso, la memoria es limpiada por el propio kernel del operativo, que invoca a kmalloc() (en el caso de Linux, en otros Unices el nombre puede variar aunque la idea sea la misma) para hacer la reserva. Lo que sí es posible es que si liberamos una zona de memoria (por ejemplo con free()) y a continuación la volvemos a reservar, en el mismo proceso, podamos acceder a su contenido: esa zona no es `nueva' (es decir, el núcleo no la ha reservado de nuevo), sino que ya pertenecía al proceso. De cualquier forma, si vamos a liberar una zona en la que está almacenada información sensible, lo mejor en cualquier caso es ponerla a cero manualmente, por ejemplo mediante bzero() o memset().
  • open(): El sistema de ficheros puede modificarse durante la ejecución de un programa de formas que en ocasiones ni siquiera imaginamos; por ejemplo, en Unix se ha de evitar escribir siguiendo enlaces de archivos inesperados (un archivo que cambia entre una llamada a lstat() para comprobar si existe y una llamada a open() para abrirlo en caso positivo, como hemos visto antes). No obstante, no hay ninguna forma de realizar esta operación atómicamente sin llegar a mecanismos de entrada/salida de muy bajo nivel; Peter Gutmann propone el siguiente código para asegurarnos de que estamos realizando un open() sobre el archivo que realmente queremos abrir, y no sobre otro que un atacante nos ha puesto en su lugar:struct stat lstatInfo; char *mode="rb+"; int fd; if(lstat(fileName,&lstatInfo)
    -1) { if(errno!=ENOENT) return( -1 ); if((fd=open(fileName,O_CREAT|O_EXCL|O_RDWR,0600))
    -1) return(-1); mode="wb"; } else { struct stat fstatInfo; if((fd=open(fileName,O_RDWR))
    -1) return(-1); if(fstat(fd,&fstatInfo)
    -1 || \ lstatInfo.st_mode!=fstatInfo.st_mode || \ lstatInfo.st_ino!=fstatInfo.st_ino || \ lstatInfo.st_dev!=fstatInfo.st_dev) { close(fd); return(-1); } if(fstatInfo.st_nlink>1||!S_ISREG(lstatInfo.st_mode)) { close(fd); return(-1); } #ifdef NO_FTRUNCATE close(fd); if((fd=open(fileName,O_CREAT|O_TRUNC|O_RDWR))
    -1) return( -1 ); mode="wb"; #else ftruncate(fd,0); #endif /* NO_FTRUNCATE */ } stream->filePtr=fdopen(fd,mode); if(stream->filePtr
    NULL) { close(fd); unlink(fileName); return(-1); /* Internal error, should never happen */ } } Como podemos ver, algo tan elemental como una llamada a open() se ha convertido en todo el código anterior si queremos garantizar unas mínimas medidas de seguridad; esto nos puede dar una idea de hasta que punto la programación `segura' puede complicarse. No obstante, en muchas ocasiones es preferible toda la complicación y parafernalia anteriores para realizar un simple open() a que esa llamada se convierta en un fallo de seguridad en nuestro sistema. No hay ningún programa que se pueda considerar perfecto o libre de errores (como se cita en el capítulo 23 de [GS96], una rutina de una librería puede tener un fallo...o un rayo gamma puede alterar un bit de memoria para hacer que nuestro programa se comporte de forma inesperada), pero cualquier medida que nos ayude a minimizar las posibilidades de problemas es siempre positiva.
Tabla de contenidos
  1. 1 - Introducción y conceptos previos
  2. 2 - Sobre la seguridad
  3. 3 - Sobre las redes
  4. 4 - Seguridad física de los sistemas
  5. 5 - Protección del hardware
  6. 6 - Protección de los datos
  7. 7 - Radiaciones electromagnéticas
  8. 8 - Administradores, usuarios y personal
  9. 9 - Ataques potenciales
  10. 10 - Qué hacer ante estos problemas
  11. 11 - El atacante interno
  12. 12 - El sistema de ficheros
  13. 13 - Sistemas de ficheros
  14. 14 - Permisos de un archivo
  15. 15 - Los bits SUID, SGID y sticky
  16. 16 - Atributos de un archivo
  17. 17 - Listas de control de acceso: ACLs
  18. 18 - Recuperación de datos
  19. 19 - Almacenamiento seguro
  20. 20 - Programas seguros, inseguros y nocivos
  21. 21 - La base fiable de cómputo
  22. 22 - Errores en los programas
  23. 23 - Fauna y otras amenazas
  24. 24 - Programación segura
  25. 25 - Auditoría del sistema
  26. 26 - El sistema de log en Unix
  27. 27 - El demonio syslogd
  28. 28 - Algunos archivos de log
  29. 29 - Logs remotos
  30. 30 - Registros físicos
  31. 31 - Copias de seguridad
  32. 32 - Dispositivos de almacenamiento
  33. 33 - Algunas órdenes para realizar copias de seguridad
  34. 34 - Políticas de copias de seguridad
  35. 35 - Autenticación de usuarios
  36. 36 - Sistemas basados en algo conocido: contraseñas
  37. 37 - Sistemas basados en algo poseído: tarjetas inteligentes
  38. 38 - Sistemas de autenticación biométrica
  39. 39 - Autenticación de usuarios en Unix: autenticación clasi
  40. 40 - Autenticación de usuarios en Unix: mejora de la seguridad (II)
  41. 41 - PAM
  42. 42 - Solaris
  43. 43 - Seguridad física en SPARC
  44. 44 - Servicios de red
  45. 45 - Usuarios y accesos al sistema
  46. 46 - El sistema de parcheado
  47. 47 - Extensiones de la seguridad
  48. 48 - El subsistema de red
  49. 49 - Parametros del núcleo
  50. 50 - Linux
  51. 51 - Seguridad física en x86
  52. 52 - Usuarios y accesos al sistema
  53. 53 - El sistema de parcheado
  54. 54 - El subsistema de red
  55. 55 - El núcleo de Linux
  56. 56 - AIX
  57. 57 - Seguridad física en RS/6000
  58. 58 - Servicios de red
  59. 59 - Usuarios y accesos al sistema (I)
  60. 60 - Usuarios y accesos al sistema (II)
  61. 61 - El sistema de log
  62. 62 - El sistema de parcheado
  63. 63 - Extensiones de la seguridad: filtros IP
  64. 64 - El subsistema de red
  65. 65 - HP-UX
  66. 66 - Seguridad física en PA-RISC
  67. 67 - Usuarios y accesos al sistema
  68. 68 - El sistema de parcheado
  69. 69 - Extensiones de la seguridad
  70. 70 - El subsistema de red
  71. 71 - El núcleo de HP-UX
  72. 72 - Seguridad de la subred: el sistema de red
  73. 73 - Algunos ficheros importantes
  74. 74 - Algunas órdenes importantes
  1. 75 - Servicios
  2. 76 - Algunos servicios y protocolos
  3. 77 - Servicios basicos de red
  4. 78 - El servicio FTP
  5. 79 - El servicio TELNET
  6. 80 - El servicio SMTP
  7. 81 - Servidores WWW
  8. 82 - Los servicios r-
  9. 83 - XWindow
  10. 84 - Cortafuegos: Conceptos teóricos
  11. 85 - Características de diseño
  12. 86 - Componentes de un cortafuegos
  13. 87 - Arquitecturas de cortafuegos
  14. 88 - Firewall-1
  15. 89 - ipfwadm/ipchains/iptables
  16. 90 - IPFilter
  17. 91 - PIX Firewall (I)
  18. 92 - PIX Firewall (II)
  19. 93 - Escaneos de puertos
  20. 94 - Spoofing
  21. 95 - Negaciones de servicio
  22. 96 - Interceptación
  23. 97 - Ataques a aplicaciones
  24. 98 - Sistemas de detección de intrusos
  25. 99 - Clasificación de los IDSes
  26. 100 - Requisitos de un IDS
  27. 101 - IDSes basados en maquina
  28. 102 - IDSes basados en red
  29. 103 - Detección de anomalías
  30. 104 - Detección de usos indebidos
  31. 105 - Implementación real de un IDS (I)
  32. 106 - Implementación real de un IDS (II)
  33. 107 - Algunas reflexiones
  34. 108 - Kerberos
  35. 109 - Arquitectura de Kerberos
  36. 110 - Autenticación
  37. 111 - Problemas de Kerberos
  38. 112 - Criptología
  39. 113 - Criptosistemas
  40. 114 - Clasificación de los criptosistemas
  41. 115 - Criptografía clasica
  42. 116 - Un criptosistema de clave secreta: DES
  43. 117 - Criptosistemas de clave pública
  44. 118 - Funciones resumen
  45. 119 - Esteganografía
  46. 120 - Algunas herramientas de seguridad
  47. 121 - Titan (I)
  48. 122 - Titan (II)
  49. 123 - TCP Wrappers
  50. 124 - SSH
  51. 125 - Tripwire
  52. 126 - Nessus
  53. 127 - Crack
  54. 128 - Gestión de la seguridad
  55. 129 - Políticas de seguridad
  56. 130 - Analisis de riesgos
  57. 131 - Estrategias de respuesta
  58. 132 - Outsourcing
  59. 133 - El "Área de Seguridad"
  60. 134 - Apéndice 1: Seguridad basica para administradores (I)
  61. 135 - Apéndice 1: Seguridad basica para administradores (II)
  62. 136 - Apéndice 2: Normativa (I)
  63. 137 - Apéndice 2: Normativa (II)
  64. 138 - Apéndice 2: Normativa (III)
  65. 139 - Apéndice 2: Normativa (IV)
  66. 140 - Recursos de interés en INet
  67. 141 - Glosario de términos anglosajones
  68. 142 - Conclusiones
  69. 143 - Bibliografía (I)
  70. 144 - Bibliografía (II)
  71. 145 - Bibliografía (III)
  72. 146 - Bibliografía (IV)
  73. 147 - Bibliografía (V)
  74. 148 - libro
Autor y licencia de 'Seguridad en Unix y redes - Programación segura'
Antonio Villalón Huerta Extraído de: http://es.tldp.org/Manuales-LuCAS/doc-unixsec/unixsec-html/ GNU Free Documentation License
Licencia GNU Free Documentation License: http://www.gnu.org/copyleft/
Este contenido ha sido recopilado por el equipo de Wikilearning. Todo el contenido recopilado se ha obtenido respetando y comunicando en nuestro site la licencia de cada fuente.
Wikilearning tiene permiso expreso por escrito de los autores para publicar los contenidos que ha extraído de otras webs, incluyendo su uso comercial.

Wikis relacionados con 'Seguridad en Unix y redes - Programación segura'

Es muy fácil crear archivos en el sistema operativo UNIX. Por lo tanto, los usuarios... Más »
Hablar de redes de ordenadores siempre implica hablar de Unix. Por supuesto, Unix no es... Más »
Ken Thompson y Dennis Ritchie decidieron esbozar un sistema operativo que supliera las necesidades de... Más »
Esta guía no es un documento general de seguridad. Esta guía está específicamente orientada a... Más »
Quisiera por lo tanto partir ahora de un conjunto de apuntes generales, de una veloz... Más »
Gente Wiki
Rene Castañeda
Hola estoy en este momento dirigiendo un grupo de empresas de seguridad, busco darle una cultura y un enfoque mas...
Control de calidad, Dirección de la producción,...
Eduardo
Fundador y director del departamento de investigación periodística del circulo de la prensa y jefe de redacción de la revista...
Carla
Hola, soy de uruguay y me encanta la literatura, además me interesa investigar cosas que tienen que ver con las...
Idioma chino
Tufik Oscar Bechir Abdala
Soy ya un hombre mayor (65 años) a quien le encanta la informática y me gano la vida como técnico...
Jaime
Trabajo en los sistemas GIS desde el año 1998 cuando me inicie en un proyecto de censo de poblacion...
Ruben Cañihua Florez
El connotado rubén cañihua florez inicio su vida académica como un investigador científico de línea en aplicaciones de realidad virtual...
Suscribirse
¿Estás seguro de que deseas eliminar este capítulo?