La seguridad basada en capacidades es un concepto en el diseño de sistemas informáticos seguros , uno de los modelos de seguridad existentes . Una capacidad (conocida en algunos sistemas como clave ) es una señal de autoridad comunicable e infalsificable . Se refiere a un valor que hace referencia a un objeto junto con un conjunto asociado de derechos de acceso . Un programa de usuario en un sistema operativo basado en capacidades debe usar una capacidad para acceder a un objeto. La seguridad basada en capacidades se refiere al principio de diseñar programas de usuario de manera que compartan directamente capacidades entre sí de acuerdo con el principio del mínimo privilegio y con la infraestructura del sistema operativo necesaria para que dichas transacciones sean eficientes y seguras. La seguridad basada en capacidades debe contrastarse con un enfoque que utiliza permisos tradicionales de UNIX y listas de control de acceso .
Aunque la mayoría de los sistemas operativos implementan una función que se asemeja a las capacidades, normalmente no brindan el respaldo suficiente para permitir que el intercambio de capacidades entre entidades que posiblemente desconfíen entre sí sea el medio principal para otorgar y distribuir derechos de acceso en todo el sistema. Un sistema basado en capacidades, por el contrario, está diseñado con ese objetivo en mente.
Las capacidades logran su objetivo de mejorar la seguridad del sistema al ser utilizadas en lugar de referencias falsificables . Una referencia falsificable (por ejemplo, un nombre de ruta ) identifica un objeto, pero no especifica qué derechos de acceso son apropiados para ese objeto y el programa de usuario que contiene esa referencia. En consecuencia, cualquier intento de acceder al objeto referenciado debe ser validado por el sistema operativo, en función de la autoridad ambiental del programa solicitante, normalmente mediante el uso de una lista de control de acceso (ACL). En cambio, en un sistema con capacidades, el mero hecho de que un programa de usuario posea esa capacidad le da derecho a utilizar el objeto referenciado de acuerdo con los derechos que se especifican por esa capacidad. En teoría, un sistema con capacidades elimina la necesidad de cualquier lista de control de acceso o mecanismo similar al dar a todas las entidades todas y solo las capacidades que realmente necesitarán.
Una capacidad se implementa típicamente como una estructura de datos privilegiada que consta de una sección que especifica los derechos de acceso y una sección que identifica de forma única el objeto al que se accederá. El usuario no accede a la estructura de datos o al objeto directamente, sino a través de un identificador . En la práctica, se utiliza de forma muy similar a un descriptor de archivo en un sistema operativo tradicional (un identificador tradicional), pero para acceder a todos los objetos del sistema. Las capacidades suelen almacenarse en el sistema operativo en una lista, con algún mecanismo para evitar que el programa modifique directamente el contenido de la capacidad (para falsificar los derechos de acceso o cambiar el objeto al que apunta). Algunos sistemas también se han basado en el direccionamiento basado en capacidades (soporte de hardware para capacidades), como Plessey System 250 .
Los programas que poseen capacidades pueden realizar funciones en ellas, como pasarlas a otros programas, convertirlas a una versión con menos privilegios o eliminarlas. El sistema operativo debe garantizar que solo se puedan realizar operaciones específicas en las capacidades del sistema, a fin de mantener la integridad de la política de seguridad.
Las capacidades que se analizan en este artículo no deben confundirse con las "capacidades" de la interfaz de sistema operativo portátil ( POSIX ) 1e/2c. Estas últimas son privilegios de granularidad gruesa que no se pueden transferir entre procesos.
Una capacidad se define como una referencia a un objeto protegido que, en virtud de su posesión por un proceso de usuario, otorga a ese proceso la capacidad (de ahí el nombre) de interactuar con un objeto de determinadas maneras. Esas maneras pueden incluir la lectura de datos asociados con un objeto, la modificación del objeto, la ejecución de los datos en el objeto como un proceso y otros derechos de acceso concebibles. La capacidad consiste lógicamente en una referencia que identifica de forma única un objeto en particular y un conjunto de uno o más de estos derechos.
Supongamos que, en el espacio de memoria de un proceso de usuario, existe la siguiente cadena:
/etc/contraseña
Aunque esto identifica un objeto único en el sistema, no especifica derechos de acceso y, por lo tanto, no es una capacidad. Supongamos que, en cambio, existe el siguiente par de valores:
/etc/contraseñaO_RDWR
Este par identifica un objeto junto con un conjunto de derechos de acceso. Sin embargo, el par aún no es una capacidad porque la posesión de estos valores por parte del proceso de usuario no dice nada sobre si ese acceso sería realmente legítimo.
Supongamos ahora que el programa de usuario ejecuta con éxito la siguiente declaración:
int fd = abierto ( "/etc/passwd" , O_RDWR );
La variable fd
ahora contiene el índice de un descriptor de archivo en la tabla de descriptores de archivos del proceso. Este descriptor de archivo es una capacidad. Su existencia en la tabla de descriptores de archivos del proceso es suficiente para demostrar que el proceso tiene de hecho acceso legítimo al objeto. Una característica clave de esta disposición es que la tabla de descriptores de archivos está en la memoria del núcleo y no puede ser manipulada directamente por el programa de usuario.
En los sistemas operativos tradicionales, los programas suelen comunicarse entre sí y con el almacenamiento mediante referencias como las de los dos primeros ejemplos. Los nombres de ruta se suelen pasar como parámetros de línea de comandos, se envían a través de sockets y se almacenan en el disco. Estas referencias no son capacidades y deben validarse antes de poder usarse. En estos sistemas, una pregunta central es "¿con qué autoridad se debe evaluar una referencia dada?". Esto se convierte en un problema crítico, especialmente para los procesos que deben actuar en nombre de dos entidades con autoridad diferente. Se vuelven susceptibles a un error de programación conocido como el problema del diputado confuso , que muy frecuentemente resulta en un agujero de seguridad .
En un sistema basado en capacidades, las capacidades mismas se transfieren entre los procesos y el almacenamiento mediante un mecanismo que el sistema operativo conoce para mantener la integridad de esas capacidades.
Un nuevo enfoque para resolver este problema implica el uso de un sistema operativo persistente ortogonal . En un sistema de este tipo, no es necesario descartar entidades ni invalidar sus capacidades, por lo que no es necesario un mecanismo similar a una ACL para restaurar esas capacidades en un momento posterior. El sistema operativo mantiene la integridad y la seguridad de las capacidades contenidas en todo el almacenamiento, tanto volátil como no volátil, en todo momento; en parte, al realizar todas las tareas de serialización por sí mismo, en lugar de exigir que lo hagan los programas de usuario, como es el caso en la mayoría de los sistemas operativos. Como los programas de usuario se liberan de esta responsabilidad, no es necesario confiar en ellos para que reproduzcan solo capacidades legales, ni para validar las solicitudes de acceso mediante un mecanismo de control de acceso . Un ejemplo de implementación es la máquina Flex de principios de la década de 1980.
El borrador 1003.1e de la Interfaz de sistema operativo portátil (POSIX) especifica un concepto de permisos denominado "capacidades". Sin embargo, las capacidades POSIX difieren de las capacidades de este artículo. Una capacidad POSIX no está asociada a ningún objeto; un proceso que tenga la capacidad CAP_NET_BIND_SERVICE puede escuchar en cualquier puerto TCP por debajo del 1024. Este sistema se encuentra en Linux. [1]
En cambio, Capsicum Unix combina un modelo de sistema de capacidades real con un diseño Unix y una API POSIX. Las capacidades de Capsicum son una forma refinada de descriptor de archivos, un derecho delegable entre procesos y tipos de objetos adicionales más allá del POSIX clásico, como los procesos, a los que se puede hacer referencia mediante capacidades. En el modo de capacidad de Capsicum, los procesos no pueden utilizar espacios de nombres globales (como el espacio de nombres del sistema de archivos) para buscar objetos y, en su lugar, deben heredarlos o delegarlos. Este sistema se encuentra de forma nativa en FreeBSD, pero hay parches disponibles para otros sistemas. [2]
Entre los sistemas comerciales y de investigación notables que emplean seguridad basada en capacidades se incluyen los siguientes:
"Capacidades" POSIX en Linux: