Indice
1.
Introducción
2.
Casos famosos
4. Principios básicos para la
seguridad
5. Mecanismos de
autorización
6.
Dominios de
protección
7. Matriz de
acceso
8. Listas de
acceso
9. Mecanismos de
autentificación
10.
Identificación
física
11. Criptografía
Vamos a hacer una distinción entre seguridad y
protección. El problema de la seguridad
consiste en lograr que los recursos de un
sistema sean,
bajo toda circunstancia, utilizados para los fines previstos.
Para eso se utilizan mecanismos de protección.
Los sistemas
operativos proveen algunos mecanismos de protección
para poder
implementar políticas
de seguridad. Las políticas
definen qué hay que hacer (qué datos y recursos deben
protegerse de quién; es un problema de administración), y los mecanismos
determinan cómo hay que hacerlo. Esta separación es
importante en términos de flexibilidad, puesto que las
políticas pueden variar en el tiempo y de una
organización a otra. Los mismos mecanismos,
si son flexibles, pueden usarse para implementar distintas
políticas.
Los mecanismos que ofrece el sistema operativo
necesariamente deben complementarse con otros de carácter
externo. Por ejemplo, impedir el acceso físico de personas
no autorizadas a los sistemas es un
mecanismo de protección cuya implementación no
tiene nada que ver con el sistema
operativo.
Un aspecto importante de la seguridad es el de impedir
la pérdida de información, la cual puede producirse por
diversas causas: fenómenos naturales, guerras,
errores de hardware o de software, o errores humanos.
La solución es una sola: mantener la información respaldada, de preferencia en
un lugar lejano.
Otro aspecto importante de la seguridad, es el que tiene
que ver con el uso no autorizado de los recursos:
- Lectura de datos.
- Modificación de datos.
- Destrucción de datos.
- Uso de recursos: ciclos de CPU,
impresora,
almacenamiento.
Aquí el sistema operativo
juega un rol fundamental, ofreciendo mecanismos de
autorización y autentificación.
Protección absoluta contra uso malicioso de los
sistemas es
imposible, pero si los costos de violar
un sistema son superiores a los potenciales beneficios que se
pueden obtener, entonces el sistema puede considerarse seguro. El
problema es que esa protección no obstaculice el uso del
sistema por parte de usuarios autorizados. Demasiada seguridad
podría ser contraproducente si es muy engorrosa para los
usuarios, pues estos tenderán a eludir los procedimientos
para facilitarse la vida.
Algunos de los Titanics y Hindenburgs de la seguridad en
computadores son los siguientes:
En Unix lpr -r
archivo
imprime archivo y
después lo elimina. En versiones antiguas de Unix se
podía hacer lpr -r /etc/passwd, lo que terminaba con la
eliminación del archivo donde se registran los
usuarios.
El comando mkdir xx era un programa que
ejecutaba en modo superusuario, creando un nodo-i para el
directorio xx, y luego cambiando el dueño de xx de
root al del usuario. Con un sistema lento y un poco de
suerte, se podía modificar el nodo-i para que apuntara a
cualquier archivo (por ejemplo, el passwd), justo antes de que
mkdir fijara el nuevo dueño.
Otro ejemplo ilustrativo de lo fácil que es
pensar que un sistema es seguro, cuando en
realidad no lo es, es el del sistema operativo TENEX, usado en
los DEC-10 de Digital. TENEX usaba memoria
virtual, y para permitir al usuario monitorear el comportamiento
de sus programas,
éste podía especificar una rutina que el sistema
ejecutaría cada vez que hay una falta de página. Al
mismo tiempo, los
archivos en
TENEX estaban protegidos por una clave: cada vez que se
abría un archivo, debía especificarse su clave. El
sistema operativo chequeaba las claves de un caracter a la
vez, deteniéndose apenas un caracter
difiriera. Gracias a eso y a que era posible saber cuándo
había una falta de página, se podía
descubrir la clave de cualquier archivo, de la siguiente
manera:
Poner primer caracter de posible clave en la
última posición de una página p, y
arreglárselas para que la siguiente (la p+1) estuviera
inválida (no presente en memoria física). Tratar de
abrir el archivo, usando esa posible clave. El resultado esperado
es un mensaje diciendo "clave incorrecta", pero dependiendo de si
hubo falta de página o no en p+1, podemos saber si el
primer caracter era correcto o no. Después de unas pocas
pruebas, se
habrá descubierto el primer caracter, y es cosa de seguir
la misma idea para descubrir el resto. Si hay 128 caracteres
posibles, necesitaremos 128n intentos para descubrir una clave de
n caracteres, en lugar de 128n
Probablemente la violación más famosa de
todos los tiempos ocurrió en 1988 cuando un estudiante
lanzó un gusano por la internet que botó
miles de máquinas
en cosa de horas. El gusano tomaba el control de una
máquina intentando diversos mecanismos. Uno de ellos era
un bugo en el programa finger.
Una vez obtenido el control, trataba
de descubrir las claves de los usuarios de esa máquina
intentando palabras comunes. Si descubría una, entonces
tenía acceso a todas las máquinas en que ese
usuario tuviera cuenta. El gusano no hacía ninguna
acción dañina en sí, pero usaba tantos
recursos de las máquinas infectadas que las
botaba.
Aunque estos defectos han sido corregido, todavía
hay más. En Unix, algunos nunca serán corregidos
(si se corrigen, dejaría de ser Unix).
3. Otras amenazas y
ataques posibles
- Virus. Un virus es
parecido a un gusano, en cuanto se reproduce, pero la
diferencia es que no es un programa por sí sólo,
si no que es un trozo de código que se adosa a un programa
legítimo, contaminándolo. Cuando un programa
contaminado se ejecuta, ejecutará también el
código del virus, lo que
permitirá nuevas reproducciones, además de alguna
acción (desde un simple mensaje inocuo hasta la
destrucción de todos los archivos). - Cabayo de troya. Un cabayo de troya es un programa
aparentemente útil que contiene un trozo de
código que hace algo no deseado. - Puerta trasera. Una puerta trasera es un punto de
entrada secreto, dejado por los implementadores del sistema
para saltarse los procedimientos
normales de seguridad. La puerta trasera puede haberse dejado
con fines maliciosos o como parte del diseño; en cualquier caso, son un
riesgo. - Caza claves. Dejar corriendo en un terminal un
programa que pida "login:" y luego "password:", para
engañar a los usuarios de modo que estos revelen su
clave. - Solicitar recursos como páginas de memoria o
bloques de disco, y ver qué información
contienen; muchos sistemas no los borran cuando se liberan, de
modo que se puede encontrar información
"interesante". - Sobornar o torturar al administrador
para que suelte la clave.
4. Principios
básicos para la seguridad
- Suponer que el diseño del sistema es
público. - El defecto debe ser: sin acceso.
- Chequear permanentemente.
- Los mecanismos de protección deben ser
simples, uniformes y construidos en las capas más
básicas del sistema. - Los mecanismos deben ser aceptados
sicológicamente por los usuarios.
En cualquier caso, hay que tener presente
que:
Seguridad = 1/Conveniencia
En otras palabras, mientras más seguro es tu
sistema, más desdichado serás.
Un sistema de computación puede verse como una
colección de objetos (procesos,
procesadores,
segmentos de memoria, discos, impresoras,
archivos, semáforos). Cada objeto debe tener un nombre
único para poder
identificarlo, y un número finito de operaciones que
los procesos
pueden efectuar sobre él (leer y escribir en archivos, P y
V en semáforos). Podemos ver a estos objetos como tipos
abstractos de datos.
Obviamente, un proceso no
debe poder accesar objetos sobre los que no tenga
autorización. También debe ser posible restringir
el uso de un objeto por parte de un proceso
sólo a ciertas operaciones. Por
ejemplo, un proceso podría tener autorización para
leer, pero no para escribir un determinado archivo.
Un dominio de
protección es un conjunto de pares (objeto, operaciones);
cada par identifica un objeto y las operaciones permitidas sobre
él.
En cada instante, cada proceso ejecuta dentro de un
dominio de
protección. Los procesos pueden cambiar de un dominio a
otro en el tiempo; el cómo depende mucho del sistema. En
UNIX, se asocia un dominio a cada usuario+grupo; dado un
usuario y el grupo al cual
pertenece, se puede construir una lista de todos los objetos que
puede accesar y con qué operaciones. Cuando un usuario
ejecuta un programa alamacenado en un archivo de propiedad de
otro usuario B, el proceso puede ejecutar dentro del dominio de
protección de A o B, dependiendo del bit de dominio o
SETUSERID bit del archivo. Este mecanismo se usa con
algunos utilitarios. Por ejemplo, el programa passwd debe tener
privilegios que un usuario común no tiene, para poder
modificar el archivo donde se guardan las claves. Lo que se hace
es que el archivo /bin/passwd que contiene el programa es
propiedad del
superusuario, y tiene el SETUSERID encendido. Este esquema es
peligroso: un proceso puede pasar de un estado en que
tiene poco poder a otro en que tiene poder absoluto (no hay
términos medios).
Cualquier error en un programa como passwd puede significar un
gran hoyo en la seguridad del sistema. Cuando se hace una llamada
al sistema también se produce un cambio de
dominio, puesto que la llamada se ejecuta en modo
protegido.
Ahora bien, ¿cómo se las arregla el
sistema para llevar la cuenta de quién puede accesar
qué objetos y con qué operaciones? Conceptualmente
al menos, podemos ver este modelo de
protección como una gran matriz de
acceso.
Los cambios de dominio que un proceso puede hacer
también podemos integrarlos a la matriz, tratando a los
dominios como otros objetos, con una operación:
entrar.
Una política de
protección involucra decidir cómo se va a llenar
esta matriz. Normalmente el usuario que crea un objeto es
quién decide cómo se va a llenar la columna de la
matriz correspondiente a ese objeto. La matriz de acceso es
suficientemente general como para apoyar diversas
políticas. Por ejemplo:
- La capacidad para copiar o transferir un derecho de
un objeto a otro dominio. - Capacidad de un dominio para modificar los derechos en otros dominios
(todos, o para un recurso específico).
El problema es cómo almacenar esta matriz. Como
es una matriz poco densa (muchos de los elementos son
vacíos), no resulta práctico representarla como
matriz propiamente. Podríamos usar una tabla con triples
(dominio, objeto, derechos). Si un proceso
dentro de un dominio D intenta efectuar una operación M
sobre un objeto O, se busca (D, O, C), y se verifica si M
pertenece a C. De todas maneras, la tabla es grande, y el esquema
no es muy eficiente. Además, si un objeto puede ser, por
ejemplo, leído por todo el mundo, debe tener entradas para
cada dominio.
Alternativamente, podemos guardar la matriz por columnas
(descartando las entradas vacías). Es decir, a cada objeto
se le asocia una lista de pares (dominio, derechos). Es lo que se
conoce como lista de acceso o ACL. Si pensamos en archivos de
Unix, podemos almacenar esta lista en el nodo-i de cada archivo,
y sería algo así como
((Juan, *, RW), (Pedro, Profes, RW), (*, Profes,
R))
En la práctica, se usa un esquema más
simple (y menos poderoso), pero que puede considerarse aún
una lista de accesos, reducida a 9 bits. 3 para el dueño
(RWX), 3 para el grupo, y 3 para el resto del mundo.
Windows NT usa listas de accesos con todo el nivel de
detalle que uno quiera: para cualquier usuario o grupo, se puede
especificar cualquier subconjunto de derechos para un archivo, de
entre {RWXDPO}. .
Capacidades
La otra posibilidad es almacenar la matriz por filas. En
este caso, a cada proceso se le asocia una lista de capacidades.
Cada capacidad corresponde a un objeto más las operaciones
permitidas.
Cuando se usan capacidades, lo usual es que, para
efectuar una operación M sobre un objeto O, el proceso
ejecute la operación especificando un puntero a la
capacidad correspondiente al objeto, en vez de un puntero al
objeto. La sola posesión de la capacidad por
parte del proceso quiere decir que tiene los derechos que en ella
se indican. Por lo tanto, obviamente, se debe evitar que los
procesos puedan "falsificar" capacidades.
Una posibilidad es mantener las listas de capacidades
dentro del sistema operativo, y que los procesos sólo
manejen punteros a las capacidades, no las capacidades
propiamente. Otra posibilidad es cifrar las capacidades con una
clave conocida por el sistema, pero no por el usuario. Este
enfoque es particularmente adecuado para sistemas
distribuidos, y es usado en Amoeba.
Un problema de las capacidades es que puede ser
difícil revocar derechos ya entregados. En Amoeba, cada
objeto tiene asociado un número al azar, grande, que
también está presente en la capacidad. Cuando se
presenta una capacidad, ambos números deben coincidir. De
esta menera, para revocar los derechos ya otorgados, se cambia el
número asociado al objeto. Problema: no se puede revocar
selectivamente. Las revocaciones con ACL son más simples y
más flexibles.
9. Mecanismos de
autentificación
La autentificación, que consiste en identificar a
los usuarios que entran al sistema, se puede basar en
posesión (llave o tarjeta), conocimiento
(clave) o en un atributo del usuario (huella digital).
Claves
El mecanismo de autentificación más
ampliamente usado se basa en el uso de claves o
passwords; es fácil de entender y fácil de
implementar. En UNIX, existe un archivo /etc/passwd donde se
guarda los nombres de usuarios y sus claves, cifradas mediante
una función
one-way F. El programa login pide nombre y clave,
computa F(clave), y busca el par (nombre, F(clave)) en el
archivo.
Con claves de 7 caracteres tomados al azar de entre los
95 caracteres ASCII que se
pueden digitar con cualquier teclado,
entonces las 957 posibles claves deberían
desincentivar cualquier intento por adivinarla. Sin embargo, una
proporción demasiado grande de las claves escogidas por
los usuarios son fáciles de adivinar, pues la idea es que
sean también fáciles de recordar. La clave
también se puede descubrir mirando (o filmando) cuando el
usuario la digita, o, si el usuario hace login remoto,
interviniendo la red y observando todos los
paquetes que pasan por ella. Por último, además de
que las claves se pueden descubrir, éstas también
se pueden "compartir", violando las reglas de seguridad. . En
definitiva, el sistema no tiene nunguna garantía de que
quien hizo login es realmente el usuario que se supone que
es.
Un enfoque diferente es usar un elemento físico
difícil de copiar, típicamente una tarjeta con una
banda magnética. Para mayor seguridad este enfoque se
suele combinar con una clave (como es el caso de los cajeros
automáticos). Otra posibilidad es medir
características físicas particulares del sujeto:
huella digital, patrón de vasos sanguíneos de la
retina, longitud de los dedos. Incluso la firma sirve.
Algunas medidas básicas
- Demorar la respuesta ante claves erróneas;
aumentar la demora cada vez. Alertar si hay demasiados
intentos. - Registrar todas las entradas. Cada vez que un usuario
entra, chequear cuándo y desde dónde entró
la vez anterior. - Hacer chequeos periódicos de claves
fáciles de adivinar, procesos que llevan demasiado
tiempo corriendo, permisos erróneos, actividades
extrañas (por ejemplo cuando usuario está de
vacaciones). - Para los más paranoicos: poner trampas para
descubrir intentos de uso no autorizado.
Los mecanismos de protección que hemos visto
hasta ahora muchas veces no son suficientes para mantener
información confidencial adecuadamente resguardada. Con el
uso masivo de las redes de computadores,
más y más información se transmite por ella,
y nadie puede estar seguro de que no hay mirones en el
alambre. Los métodos
criptográficos son los más comúnmente usados
para proteger información confidencial. Lo que se
envía por la red no es la
información original, sino la información
codificada, que carece de sentido salvo para el receptor, que
puede decodificarla.
Criptografía simétrica
La criptografía simétrica se basa en un
algoritmo
general de codificación C, un algoritmo
general de decodificación D, y una clave secreta k, tales
que
- Dk (Ck(m)) = m.
- Ck y Dk son computables
eficientemente. - La seguridad depende sólo de que la clave –no
los algoritmos—
sea secreta.
Un esquema ampliamente usado es el DES (data encryption
standard), creado por la NSA.
El inconveniente de la criptografía
simétrica es la distribución de la clave. Si quiero enviar
un texto
confidencial por la red, lo envío cifrado, pero
¿cómo le comunico la clave a mi interlocutor? Por
otra parte, se requiere una clave por cada par de
usuarios.
Criptografía de clave pública
La criptografía de clave pública es
asimétrica. Se basa en métodos
que requieren una clave pública para cifrar, y otra,
distinta y privada, para descifrar. Supongamos que los
procedimentos para cifrar y descifrar de los usuarios A y B, son,
respectivamente CA, DA, CB y
DB.
Para que B envíe mensaje m a A:
- B averigua la clave pública de A, en un
directorio público. - Envía CA(m)
- A descifra el mensaje con su clave:
m=DA(CA(m)). Sólo A puede hacerlo,
pues es el único que conoce la clave.
Los métodos de criptografía de clave
pública tienen la interesante propiedad
m=CA(DA(m))
que permite implementar también firmas digitales.
Una firma digital debe ser dependiente del firmador y del mensaje
que está firmando.
Un mensaje m firmado por B es
s=(DB(m))
Si se lo quiere mandar privadamente a B, además
lo cifra, enviando CA(s), pero esto es sólo
para privacidad.
A primero recupera s, descifrando el mensaje como antes,
si viene cifrado, y luego obtiene el mensaje original
con
m=CB(s)
Y ahora A posee el par (m,s) que equivale a un documento
firmado por B, puesto que:
- B no puede negar que envió m, pues nadie
más que B puede haber creado
s=(DB(m)). - A puede convencer a un juez que
m=CB(s). - A no puede modificar m, pues la firma habría
sido otra.
En particular, RSA opera de la siguiente
manera:
La clave pública de cifrado es un par (c,n), y la
clave privada un par (d,n). Cada mensaje se representa como un
número entre 0 y n-1.
Los procedimientos para cifrar y descifrar con esas
claves son:
C(m) = mc mod n = w
D(w)= wd mod n
El problema es escoger las claves. n es el producto de
dos números primos grandes (100 dígitos) p y q. d
se escoge al azar como un número grande relativamente
primo con (p-1)(q-1). Finalmente c se computa como el inverso de
d en módulo (p-1)(q-1), o sea:
c d mod (p-1)(q-1) = 1
A pesar de que n es público, p y q no lo son, y
todo se basa en la suposición de que es difícil
factorizar un número grande.
Criptografía híbrida
Los métodos de criptografía de clave
pública resuelven el problema del intercambio de claves,
pero son bastante más lentos (100 a 1000 veces) que los
métodos de criptografía simétrica. Se puede
obtener lo mejor de ambos mundos con un esquema híbrido:
se usa criptografía de clave pública para acordar
una clave privada, y el grueso de la
comunicación se cifra con esa clave usando
criptografía simétrica.
Trabajo enviado y realizado por:
Francisco Armando Dueñas
Rodríguez
Edad: 23 años
Universidad La
Salle
Lic. en Informática
Cancún, Quintana Roo México