sql >> Base de Datos >  >> RDS >> PostgreSQL

Privilegios y seguridad de PostgreSQL:bloqueo del esquema público

Introducción

En un artículo anterior, presentamos los conceptos básicos para comprender los esquemas de PostgreSQL, la mecánica de creación y eliminación, y revisamos varios casos de uso. Este artículo se extenderá sobre esos conceptos básicos y explorará la administración de privilegios relacionados con los esquemas.

Más sobrecarga terminológica

Pero hay un asunto preliminar que requiere aclaración. Recordemos que en el artículo anterior nos detuvimos en un posible punto de confusión relacionado con la sobrecarga del término “esquema”. El significado especializado de ese término en el contexto de las bases de datos PostgreSQL es distinto de cómo se usa generalmente en los sistemas de administración de bases de datos relacionales. Tenemos otro posible alboroto terminológico similar para el tema actual relacionado con la palabra "público".

Tras la creación de la base de datos inicial, la base de datos Postgresql recién creada incluye un esquema predefinido denominado "público". Es un esquema como cualquier otro, pero la misma palabra también se usa como una palabra clave que denota "todos los usuarios" en contextos en los que, de lo contrario, se podría usar un nombre de rol real, como... espera... gestión de privilegios de esquema . El significado y los dos usos distintos se aclararán en los ejemplos a continuación.

Consulta de privilegios de esquema

Antes de concretar esto con un código de ejemplo para otorgar y revocar privilegios de esquema, debemos revisar cómo examinar los privilegios de esquema. Utilizando la interfaz de línea de comandos de psql, enumeramos los esquemas y los privilegios asociados con el comando \dn+. Para una base de datos sampledb recién creada, vemos esta entrada para el esquema público:

sampledb=# \dn+ 
                          List of schemas
  Name  |  Owner   |  Access privileges   |      Description      
--------+----------+----------------------+------------------------
 public | postgres | postgres=UC/postgres+| standard public schema
        |          | =UC/postgres         |
(1 row)

Las dos primeras y la cuarta columnas son bastante sencillas:como se mencionó anteriormente, muestran el esquema creado por defecto llamado "público", descrito como "esquema público estándar" y propiedad del rol "postgres". (La propiedad del esquema, a menos que se especifique lo contrario, se establece en el rol que crea el esquema). La tercera columna que enumera los privilegios de acceso es de interés aquí. El formato de la información de privilegios proporciona tres elementos:el otorgante de privilegios, los privilegios y el otorgante de privilegios en el formato “concesionario=privilegios/otorgante”, es decir, a la izquierda del signo de igualdad está el rol que recibe los privilegios, inmediatamente a la derecha del signo de igualdad hay un grupo de letras que especifican los privilegios particulares y, por último, después de la barra oblicua, la función que se otorgó a los privilegios. Puede haber varias especificaciones de información de privilegios de este tipo, enumeradas separadas por un signo más, ya que los privilegios se suman.

Para los esquemas, hay dos posibles privilegios que se pueden otorgar por separado:U para "USO" y C para "CREAR". El primero es necesario para que un rol tenga la capacidad de buscar objetos de base de datos como tablas y vistas contenidas en el esquema; el último privilegio permite que un rol cree objetos de base de datos en el esquema. Hay otras letras para otros privilegios relacionados con diferentes tipos de objetos de base de datos, pero para esquemas, solo se aplican U y C.

Por lo tanto, para interpretar la lista de privilegios anterior, la primera especificación nos dice que al usuario de Postgres se le otorgaron los privilegios de actualización y creación por sí mismo en el esquema público.

Observe que para la segunda especificación anterior, aparece una cadena vacía a la izquierda del signo igual. Así es como se denotan los privilegios otorgados a todos los usuarios, mediante la palabra clave PUBLIC mencionada anteriormente.

Esta última especificación de otorgar privilegios de uso y creación en el esquema público a todos los usuarios es vista por algunos como posiblemente contraria a las mejores prácticas generales de seguridad, donde uno podría preferir comenzar con acceso restringido por defecto, requiriendo que el administrador de la base de datos otorgue explícitamente y privilegios de acceso mínimos necesarios. Estos privilegios liberales en el esquema público se configuran deliberadamente en el sistema como una conveniencia y compatibilidad heredada.

Tenga en cuenta también que, a excepción de la configuración de privilegios permisivos, la única otra cosa especial sobre el esquema público es que también aparece en la ruta de búsqueda, como discutimos en el artículo anterior. Esto es similar por conveniencia:la configuración de search_path y los privilegios liberales juntos dan como resultado una nueva base de datos que se puede usar como si no existiera el concepto de esquemas.

Antecedentes históricos del esquema público

Este problema de compatibilidad se originó hace unos quince años (antes de la versión 7.3 de PostgreSQL, consulte las notas de la versión 7.3) cuando la función de esquema no formaba parte de PostgreSQL. La configuración del esquema público con privilegios liberales y la presencia de ruta_búsqueda cuando se introdujeron los esquemas en la versión 7.3 permitió la compatibilidad de aplicaciones más antiguas, que no son compatibles con esquemas, para funcionar sin modificaciones con la función de base de datos actualizada.

De lo contrario, no hay nada más particularmente especial sobre el esquema público:algunos DBA lo eliminan si su caso de uso no lo requiere; otros lo bloquean revocando los privilegios predeterminados.

Muéstrame el código - Revocación de privilegios

Hagamos algo de código para ilustrar y expandir lo que hemos discutido hasta ahora.

Los privilegios de esquema se administran con los comandos GRANT y REVOKE para agregar y retirar privilegios, respectivamente. Probaremos algunos ejemplos específicos para bloquear el esquema público, pero la sintaxis general es:

REVOKE [ GRANT OPTION FOR ]
    { { CREATE | USAGE } [, ...] | ALL [ PRIVILEGES ] }
    ON SCHEMA schema_name [, ...]
    FROM { [ GROUP ] role_name | PUBLIC } [, ...]
    [ CASCADE | RESTRICT ]

Entonces, como ejemplo de bloqueo inicial, eliminemos el privilegio de creación del esquema público. Tenga en cuenta que en estos ejemplos, la palabra en minúsculas "público" se refiere al esquema y podría reemplazarse por cualquier otro nombre de esquema válido que pueda existir en la base de datos. La palabra "PÚBLICO" en mayúsculas es la palabra clave especial que implica "todos los usuarios" y podría reemplazarse con un nombre de rol específico o una lista de nombres de roles separados por comas para un control de acceso más detallado.

sampledb=# REVOKE CREATE ON SCHEMA public FROM PUBLIC;
REVOKE
sampledb=# \dn+
                          List of schemas
  Name  |  Owner   |  Access privileges   |      Description       
--------+----------+----------------------+------------------------
 public | postgres | postgres=UC/postgres+| standard public schema
        |          | =U/postgres          | 
(1 row)

La única diferencia en esta lista de privilegios de esquema con respecto al primero es la ausencia de la "C" en la segunda especificación de privilegios, lo que verifica que nuestro comando fue efectivo:los usuarios que no sean de postgres ya no pueden crear tablas, vistas u otros objetos en el esquema público.

Tenga en cuenta que el comando anterior que revoca los privilegios de creación del esquema público es la mitigación recomendada para una vulnerabilidad publicada recientemente, CVE-2018-1058, que surge de la configuración de privilegios predeterminada en el esquema público.

Otro nivel de bloqueo podría implicar la denegación total del acceso de búsqueda al esquema mediante la eliminación del privilegio de uso:

sampledb=# REVOKE USAGE ON SCHEMA public FROM PUBLIC;
REVOKE
sampledb=# \dn+
                          List of schemas
  Name  |  Owner   |  Access privileges   |      Description       
--------+----------+----------------------+------------------------
 public | postgres | postgres=UC/postgres | standard public schema
(1 row)

Dado que se han revocado todos los privilegios de esquema disponibles para los usuarios que no son propietarios, la especificación del segundo privilegio desaparece por completo en la lista anterior.

Lo que hicimos con dos comandos separados podría haberse logrado sucintamente con un solo comando especificando todos los privilegios como:

sampledb=# REVOKE ALL PRIVILEGES ON SCHEMA public FROM PUBLIC;
REVOKE

Además, también es posible revocar los privilegios del propietario del esquema:

sampledb=# REVOKE ALL PRIVILEGES ON SCHEMA public FROM postgres;
REVOKE
sampledb=# \dn+
                        List of schemas
  Name  |  Owner   | Access privileges |      Description       
--------+----------+-------------------+------------------------
 public | postgres |                   | standard public schema
(1 row)

pero eso realmente no logra nada práctico, ya que el propietario del esquema retiene todos los privilegios de los esquemas propios independientemente de la asignación explícita simplemente en virtud de la propiedad.

La asignación liberal de privilegios para el esquema público es un artefacto especial asociado con la creación inicial de la base de datos. Los esquemas creados posteriormente en una base de datos existente se ajustan a la mejor práctica de comenzar sin privilegios asignados. Por ejemplo, examinar los privilegios del esquema después de crear un nuevo esquema llamado "privado" muestra que el nuevo esquema no tiene privilegios:

sampledb=# create schema private;
CREATE SCHEMA
sampledb=# \dn+
                          List of schemas
  Name   |  Owner   |  Access privileges   |      Description       
---------+----------+----------------------+------------------------
 private | postgres |                      | 
 public  | postgres |                      | standard public schema
(2 rows)
Descargue el documento técnico hoy Administración y automatización de PostgreSQL con ClusterControlObtenga información sobre lo que necesita saber para implementar, monitorear, administrar y escalar PostgreSQLDescargar el documento técnico

Muéstrame el código:concesión de privilegios

La forma general del comando para agregar privilegios es:

GRANT { { CREATE | USAGE } [, ...] | ALL [ PRIVILEGES ] }
    ON SCHEMA schema_name [, ...]
    TO role_specification [, ...] [ WITH GRANT OPTION ]
where role_specification can be:
  [ GROUP ] role_name
  | PUBLIC
  | CURRENT_USER
  | SESSION_USER

Usando este comando podemos, por ejemplo, permitir que todos los roles busquen objetos de base de datos en el esquema privado agregando el privilegio de uso con

sampledb=# GRANT USAGE ON SCHEMA private TO PUBLIC;
GRANT
sampledb=# \dn+
                          List of schemas
  Name   |  Owner   |  Access privileges   |      Description       
---------+----------+----------------------+------------------------
 private | postgres | postgres=UC/postgres+| 
         |          | =U/postgres          | 
 public  | postgres |                      | standard public schema
(2 rows)

Observe cómo aparecen los privilegios de UC para el propietario de postgres como la primera especificación, ahora que hemos asignado privilegios distintos a los predeterminados al esquema. La segunda especificación, =U/postgres, corresponde al comando GRANT que acabamos de invocar como usuario postgres otorgando privilegios de uso a todos los usuarios (donde, recuerde, la cadena vacía a la izquierda del signo igual implica "todos los usuarios").

A un rol específico, llamado "usuario1", por ejemplo, se le pueden otorgar privilegios de creación y uso para el esquema privado con:

sampledb=# GRANT ALL PRIVILEGES ON SCHEMA private TO user1;
GRANT
sampledb=# \dn+
                          List of schemas
  Name   |  Owner   |  Access privileges   |      Description       
---------+----------+----------------------+------------------------
 private | postgres | postgres=UC/postgres+| 
         |          | =U/postgres         +| 
         |          | user1=UC/postgres    | 
 public  | postgres |                      | standard public schema
(2 rows)

Todavía no hemos mencionado la cláusula "CON OPCIÓN DE CONCESIÓN" del formulario de comando general. Tal como suena, esta cláusula permite que un rol otorgado tenga el poder de otorgar el privilegio especificado a otros usuarios, y se indica en la lista de privilegios con asteriscos adjuntos al privilegio específico:

sampledb=# GRANT ALL PRIVILEGES ON SCHEMA private TO user1 WITH GRANT OPTION;
GRANT
sampledb=# \dn+
                          List of schemas
  Name   |  Owner   |  Access privileges   |      Description       
---------+----------+----------------------+------------------------
 private | postgres | postgres=UC/postgres+| 
         |          | =U/postgres         +| 
         |          | user1=U*C*/postgres  | 
 public  | postgres |                      | standard public schema
(2 rows)

Conclusión

Esto concluye el tema de hoy. Sin embargo, como nota final, recuerde que solo hemos discutido los privilegios de acceso al esquema. Si bien el privilegio USAGE permite la búsqueda de objetos de base de datos en un esquema, para acceder realmente a los objetos para operaciones específicas, como lectura, escritura, ejecución, etc., el rol también debe tener los privilegios apropiados para esas operaciones en esos objetos de base de datos específicos.