Estoy tratando de encontrar una manera sencilla de mesas privadas, sin embargo, que los expone a ciertos clientes, si están autenticados.
Esta autenticación se puede lograr mediante un sistema de token que permite al cliente realizar consultas sólo si el token o las credenciales son válidas.
El enfoque que aquí iba a tener una función con la lógica de autenticación y lo consultas u operaciones que usted necesita para exponer, y llame a esa función desde el cliente junto con sus credenciales.
El problema con esto es que usted termina con un pg de la función para cada operación, la necesidad de definir con precisión la entrada y la salida de la función, no polimorphy, así que cada vez que algo cambia (como un tipo de datos), todas las funciones deben ser recreado. No es muy flexible.
Otra posibilidad sería tener sólo una función que actúa como un contenedor para lo SQL que usted envía, comprueba las credenciales, esteriliza el sql y devuelve la respuesta.
CREATE OR REPLACE FUNCTION runSQL(thesql text,client text, hash text) RETURNS SETOF RECORD as $$
DECLARE
sql text;
expiry time;
client_info RECORD;
m varchar;
--here go the blacklisted strings
blacklist varchar[] := array['UPDATE ','INSERT ', 'ALTER ', 'DROP ', 'TRUNCATE', 'DELETE '];
BEGIN
expiry:=INTERVAL '1 hour';
sql:= 'SELECT * FROM auth WHERE client_id = $1 AND client_hash = $2 AND created_at > (NOW() - $3)';
EXECUTE sql using client, hash, expiry INTO client_info ;
-- check if it's a valid user and has an up to date token
IF client_info IS NULL THEN
RAISE EXCEPTION 'Authorization failed for client %', client;
END IF;
sql:= thesql;
-- sanitize the sql
FOREACH m IN ARRAY blacklist
LOOP
IF position(m in upper(thesql)) = 1 OR position(concat(' ', m) in upper(thesql))>0 THEN
RAISE EXCEPTION 'Not enough privilleges';
END IF;
END LOOP;
--send back results
RETURN QUERY EXECUTE sql ;
END;
$$ LANGUAGE plpgsql
SECURITY DEFINER;
Y de uso sería:
SELECT * FROM runSQL('SELECT cartodb_id, the_geom FROM sometable', 'client_id', 'token') as f(cartodb_id int, geom geometry)
Mi preocupación aquí no es la apertura de un enorme agujero en la seguridad de mi base de datos. ¿Crees que sería suficiente sólo para comprobar potencialmente peligrosos de las cadenas en la consulta (como INSERT, DELETE, DROP, ALTER, OTORGAR, REVOCAR...) o existen otros problemas de seguridad con este enfoque?
Otras ideas sobre cómo tener una SEGURIDAD DEFINIDOR función que sólo permite que ciertas operaciones, como leer, o el acceso solo a algunas tablas?
Gracias!
David