A Guide to CVE-2018-1058: Protect Your Search Path/es

==Información general==
El 1 de marzo de 2018, el Grupo Global de Desarrollo de PostgreSQL lanzó una actualización para todas las versiones soportadas del sistema de base de datos PostgreSQL, incluyendo las versiones 10.3, 9.6.8, 9.5.12, 9.4.17 y 9.3.22.
El propósito de este lanzamiento fue solucionar CVE-2018-1058, el cual describe cómo un usuario puede crear objetos con el mismo nombre en diferentes esquemas, los cuales pueden cambiar el comportamiento de las consultas de otros usuarios y causar un comportamiento inesperado o malicioso, también conocido como ataque "troyano". La mayor parte de este lanzamiento se centró en agregar documentación que describa el problema y qué medidas tomar para mitigar el impacto en bases de datos PostgreSQL.
La siguiente guía es una explicación detallada del CVE-2018-1058 y de cómo protegerse contra usuarios que quieran aprovechar la vulnerabilidad en PostgreSQL.
==Antecedentes: ¿Qué es CVE-2018-1058?==
El lanzamiento de PostgreSQL 7.3 introdujo los "esquemas," que permitirían a los usuarios crear objetos (por ejemplo: tablas, funciones, etc.) en diferentes espacios de nombre. Cuando un usuario crea una base de datos, de forma predeterminada, PostgreSQL crea un esquema llamado public donde, de forma predeterminada, se crean todos los objetos nuevos (por ejemplo: tablas, funciones). Con esta configuración, una consulta como:
SELECT * FROM tabla_a;
equivale a:
SELECT * FROM public.tabla_a;
Sin ajustar la configuración o los parámetros de control de acceso, cualquier usuario que pueda conectarse a una base de datos también puede crear objetos en el esquema public de esa base de datos. Un administrador de PostgreSQL puede conceder y revocar permisos de un usuario tanto para usar como para crear objetos dentro de un esquema en particular.
Los esquemas permiten a los usuarios poner a los objetos en un espacio de nombres, así objetos con el mismo nombre pueden existir en diferentes esquemas dentro de la misma base de datos. Si hay objetos con el mismo nombre en diferentes esquemas y no se especifica el par esquema/objeto específico (es decir esquema.objeto, PostgreSQL decide qué objeto utilizar de acuerdo a la configuración del search_path. La configuración del search_path especifica el orden de los esquemas en los que se busca un objeto. El valor predeterminado para search_path es $user,public donde $user se refiere al nombre del usuario conectado (el cual puede ser determinado ejecutando SELECT SESSION_USER;).
Por ejemplo, si el SESSION_USER es alice y existen las siguientes tablas:
CREATE TABLE alice.a AS SELECT 1::int AS id;
CREATE TABLE public.a AS SELECT 'a'::text AS id;
Entonces, si alice ejecuta "SELECT * FROM a;", obtendrá el siguiente resultado:
 id 
----
 1
Independientemente del contenido de search_path, PostgreSQL busca en el esquema del catálogo del sistema, pg_catalog, para ver si hay algún objeto que coincida ahí. El contenido de pg_catalog incluye objetos como operadores y funciones integradas. Si no se especifica pg_catalog en el search_path, PostgreSQL busca los objetos en pg_catalog antes de buscar en cualquier otro esquema.
==El problema: CVE-2018-1058==
El problema descrito en CVE-2018-1058 se centra en el esquema predeterminado "public" y en cómo PostgreSQL utiliza el parámetro search_path. La capacidad de crear objetos con el mismo nombre en diferentes esquemas, junto con la forma en que PostgreSQL busca objetos dentro de los esquemas, presenta una oportunidad para que un usuario modifique el comportamiento de una consulta para otros usuarios. Por ejemplo, un usuario malicioso podría insertar una función troyana que, al ser ejecutada por un superusuario, le conceda privilegios elevados al usuario malicioso.
La manera más fácil de explicar esto es mediante un ejemplo.
Hay dos usuarios de base de datos, alice y bob, ambos tienen acceso a la misma base de datos que contiene el esquema predeterminado public y una tabla en ese esquema con la siguiente definición:
CREATE TABLE a (nombre_completo varchar(255));
En la aplicación que utilizan tanto alice como bob, hay una línea de código que ambos usuarios ejecutan para obtener los nombres de la tabla a como cadenas de texto en minúsculas, esto es
SELECT lower(nombre_completo) FROM a;
La función lower está definida en el esquema pg_catalog y recibe un solo argumento del tipo text. El analizador de consultas de PostgreSQL sabe que puede convertir nombre_completo del tipo varchar a text, y así utilizar la función lower.
Sabiendo que el sistema solo tiene configurado el esquema predeterminado public, el usuario alice decide crear la siguiente función en el esquema public:
CREATE FUNCTION lower(varchar) RETURNS text AS $$
 SELECT 'ALICE ESTUVO AQUÍ: ' || $1;
$$ LANGUAGE SQL IMMUTABLE;
Aunque hay una función llamada lower en el esquema pg_catalog, la función anterior se crear con éxito en el esquema public pues está en un espacio de nombres diferente.
Además, la función lower en el esquema public es un mejor candidato para los datos de la columna nombre_completo, por lo que si bob intenta ejecutar la siguiente consulta:
SELECT lower(nombre_completo) FROM a;
Terminará viendo un mensaje sorpresa por parte de alice indicándole que ella "estuvo aquí", además de los datos de retorno esperados. Así, alice ha insertado con éxito una función troyana.
==Impacto: ¿Están afectados mis sistemas PostgreSQL?==
La repuesta corta es: dependiendo de su configuración, su sistema probablemente esté afectado, pero puede no estar en peligro inminente.
El problema existe en todas las versiones soportadas de PostgreSQL a fecha del 1 de marzo de 2018. Sin embargo, ya hay métodos disponibles para proteger su base de datos en todas las versiones soportadas de PostgreSQL. Estos métodos se describen con más detalle en la siguiente sección.
Su instalación puede no estar en riesgo si ya ha hecho una de las siguientes cosas:
* Si escribe sus consultas de la forma específica esquema.objeto, incluyendo para objetos que existan en pg_catalog (por ejemplo, ejecutar SELECT pg_catalog.lower('ALICE');), no es inmediatamente vulnerable a este problema.
* Si tiene un solo usuario accediendo a la base de datos, y confía en cualquiera que tenga acceso a ese usuario, probablemente no sea inmediatamente vulnerable a este problema.
* Si ya ha tomado las medidas de mitigación de riesgos de la siguiente sección, no es vulnerable a este problema.
Si tiene funcionando su instalación de PostgreSQL con acceso multiusuario a una base de datos y depende de la configuración del search_path para encontrar objetos, por favor lea la siguiente sección para entender cuáles son las mejores maneras para proteger sus bases de datos.
==Medidas: ¿Cómo puedo proteger mi base de datos?==
Hay varias formas de proteger su instalación de PostgreSQL contra CVE-2018-1058.
===No permitir a los usuarios crear nuevos objetos en el esquema public===
Como superusuario, ejecute la siguiente sentencia en todas sus bases de datos:
REVOKE CREATE ON SCHEMA public FROM PUBLIC;
Ejecutar REVOKE CREATE ON SCHEMA public FROM PUBLIC; evita que cualquier usuario que no sea superusuario cree objetos en el esquema public. Esta configuración protegerá una base de datos PostgreSQL del problema descrito en CVE-2018-1058.
Una vez que se ejecute esta sentencia, ciertas operaciones podrían fallar dentro de su base de datos. Por ejemplo, un usuario que no sea superusuario ya no será capaz de crear tablas o funciones dentro del esquema public, lo cual puede afectar la forma en que un usuario gestione migraciones de esquema de aplicación.
Tenga en cuenta que la sentencia REVOKE es más poderosa que ejecutar DROP SCHEMA public; pues pg_dump no conserva la eliminación del esquema public.
Luego de ejecutar esta sentencia, debería considerar seriamente auditar su esquema public para ver si algún usuario ha creado funciones que tengan nombres similares a las de pg_catalog. Desde la herramienta de línea de órdenes ( psql), puede ver una lista de funciones disponibles en el esquema public ejecutando:
\df public.*
Para ver una lista completa de funciones definidas en el esquema pg_catalog, por favor ejecute:
\df pg_catalog.*
===Establecer el search_path predeterminado para usuarios de la base de datos===
Un superusuario puede ejecutar la siguiente sentencia para cada usuario en su sistema para quitar el esquema public del search_path predeterminado para un usuario:
ALTER ROLE usuario SET search_path = "$user";
La sentencia anterior conserva el search_path predeterminado que PostgreSQL proporciona, es decir que si hay un esquema con el mismo nombre que SESSION_USER, PostgreSQL primero buscará objetos en el esquema SESSION_USER.
Tenga en cuenta que cualquier usuario con el permiso CREATEROLE tiene la capacidad de modificar el search_path predeterminado para otros usuarios. Si ese es el caso, por favor utilice el método "No permitir a los usuarios crear nuevos objetos en el esquema public" descrito antes para proteger su sistema contra CVE-2018-1058.
===Establecer el search_path predeterminado en el fichero de configuración de PostgreSQL (postgresql.conf)===
De forma similar al método anterior, un administrador puede quitar el esquema public del parámetro search_path en el fichero de configuración postgresql.conf. Un usuario que tenga los permisos CREATEROLE o CREATEDB o es el dueño de la base de datos puede modificar el search_path para otros usuarios o crear objetos en el esquema public de una base de datos. Si ese es el caso, por favor utilice el método "No permitir a los usuarios crear nuevos objetos en el esquema public" descrito antes para proteger su sistema contra CVE-2018-1058.
==Obteniendo ayuda: Dónde encontrar más información==
Por favor, revise la documentación actualizada (en inglés) para entender cómo proteger su instalación de PostgreSQL contra CVE-2018-1058:
* Definición de datos: Esquemas
* dblink: Opciones de conexión
* ECPG: Ejemplos de conexiones
* Empaquetamiento de objetos relacionados en una extensión
* libpq: Funciones para control de conexiones a la base de datos
* Objeto grande: ejemplo
* psql
* Seguridad en funciones
Si tiene más preguntas sobre CVE-2018-1058, por favor suscríbase y envíe un mensaje a la lista de correos pgsql-es-ayuda@postgresql.org.
Si desea hacer contribuciones técnicas adicionales al proyecto PostgreSQL, por favor suscríbase y envíe un mensaje a la lista de correos pgsql-hackers@postgresql.org (en inglés).
Si cree haber encontrado una nueva vulnerabilidad de seguridad en PostgreSQL, por favor envíe un correo a security@postgresql.org (en inglés).
==Reconocimientos==
Al Grupo Global de Desarrollo de PostgreSQL le gustaría agradecer a Arseniy Sharoglazov por reportar este problema al equipo de seguridad.
==Enlaces (en inglés)==
* Descargue PostgreSQL
* Notas de la versión para PostgreSQL 10.3
* Seguridad en PostgreSQL
* Política de versionado para PostgreSQL