Siguiendo con el ataque en el que inyectaron código malicioso en la base de datos de Odoo; ahora llega el momento de proteger a la base de datos. Uno podría hacerlo de forma indirecta mejorando la seguridad del sistema de login; pero es algo indirecto. Mejor hacerlo bloqueando la creación o actualización de acciones en el servidor que contengan código malicioso.
El código problemático del ataque de días atras (ataque descripto en este post) contenía las siguientes instrucciones que no pueden (o no tienen porque estar) en una acción planificada:
- env.cr.execute; no tiene sentido usar SQL en una acción de servidor o acción planificada
- import; cual es la necesidad de importar módulos de python en una acción de servidor?
- to program; permite desde PostgreSQL ejecutar comandos en el servidor. Va de la mano de la sentencia COPY
- subprocess; es una librería de Python que permite ejecutar código en el servidor
- chr(; utilizado frecuentemente para enmascarar código malicioso
No tiene sentido utilizar acciones de servidor que utilicen estas palabras. Si uno necesita realizar dichas acciones, lo puede hacer por medio de un método en Odoo. Para ello se necesita crear un módulo en el servidor; lo cual no siempre es posible. Pero la verdad es que si uno necesita ejecutar SQL o correr procesos en el servidor; debería poder instalar o actualizar módulos.
Bien; paso siguiente es bloquear el intento de actualización o inserción de registros con dichas palabras clave. Para ello lo podemos hacer por medio de otro módulo (lo cual se hace sin inconvenientes) o por medio de triggers en la base de datos (lo cual es más potente). En este caso el código de la función y del trigger es la siguiente:
CREATE OR REPLACE FUNCTION block_suspicious_ir_act_server()
RETURNS TRIGGER AS $$
DECLARE
blocked_patterns TEXT[] := ARRAY[
'env.cr.execute',
'to program',
'copy',
'import',
'subprocess',
'chr('
];
pattern TEXT;
lowered_code TEXT;
BEGIN
-- Normalize to lowercase for case-insensitive matching
lowered_code := lower(COALESCE(NEW.code, ''));
FOREACH pattern IN ARRAY blocked_patterns
LOOP
IF lowered_code LIKE '%' || lower(pattern) || '%' THEN
RAISE EXCEPTION
'Blocked: ir_cron record contains forbidden pattern "%"', pattern
USING ERRCODE = 'raise_exception';
END IF;
END LOOP;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
DROP TRIGGER IF EXISTS trg_block_suspicious_ir_act_server ON ir_act_server;
CREATE TRIGGER trg_block_suspicious_ir_act_server
BEFORE INSERT OR UPDATE ON ir_act_server
FOR EACH ROW
EXECUTE FUNCTION block_suspicious_ir_act_server();
Varias cosas que hace el código es testear por minúsculas o mayúsculas, y no buscar la palabra completa sino que el texto malicioso se encuentre en el comando SQL. Al fin y al cabo; la idea es bloquear la inserción o actualización del campo code con código malicioso. De vuelta, si uno necesita ejecutar ciertas instrucciones en una acción planificada o acción de servidor; lo puee hacer mediante un método.
Este control podría haberlo hecho con un módulo... es verdad. Pero bueno... los triggers son una herramienta potente y rápida para mantener las bases de datos. Por último; tengan en cuenta que asegurar un servidor de Odoo requiere de más acciones de seguridad (por ejemplo fortificar passwords, rotarlos, backups, etc etc.)