Saltar al contenido principal
SEC-501 • 34 Horas • Nivel Avanzado / Principal Database Security Architect

Seguridad de Bases de Datos: Sentinel-NGAC (NIST INCITS 565), Oracle PL/SQL, VPD, PostgreSQL RLS y TDE

Grafos dirigidos acíclicos de control de acceso basado en atributos (NIST NGAC: U -> UA -> PA <- OA <- O), mitigación de Confused Deputy en Oracle PL/SQL, Virtual Private Database (VPD), PostgreSQL Row-Level Security y cifrado TDE/KMS.

Módulo 1: Módulo 1: Teoría Formal de Grafos de Permisos: Estándar NIST NGAC (INCITS 565) vs RBAC y ABAC

Arquitectura Formal de NIST NGAC (Next Generation Access Control): Nodos, Asignaciones y Asociaciones (55 min)

Arquitectura Formal de NIST NGAC (Next Generation Access Control): Nodos, Asignaciones y Asociaciones

1. Por qué RBAC Explota Combinatoriamente (Role Explosion) y ABAC Puro Es Inauditable

- RBAC (Role-Based Access Control): Cuando los permisos dependen simultáneamente de Cargo $\times$ Sucursal ($100$) $\times$ Línea de Negocio ($10$) $\times$ Nivel de Clasificación ($4$), el sistema requiere crear $10 \times 100 \times 10 \times 4 = 40,000$ roles estáticos ingobernables. - ABAC Basado en Reglas Lógicas (XACML): Evalúa expresiones booleanas arbitrarias en tiempo de consulta, pero hace que el problema de responder "¿Qué objetos exactamente puede modificar hoy el usuario Juan?" (Auditoría de Revisión de Acceso) sea NP-Difícil.

NIST NGAC (Estándar INCITS 565) modela la seguridad como un Grafo Dirigido Acíclico (DAG) sobre cinco conjuntos finitos de nodos ($mathcal{U}, mathcal{UA}, mathcal{O}, mathcal{OA}, mathcal{PC}$) permitiendo combinar simultáneamente políticas discrecionales (DAC), obligatorias (MAC), RBAC y separación de funciones en tiempo lineal sobre la profundidad del grafo:

flowchart LR
    U["Usuario (u in U)"] -->|Assign| UA1["User Attribute (Rama Comercial)"]
    UA1 -->|Assign| UA2["User Attribute (Auditor Senior)"]
    UA2 ===|Associate: {read, approve}| OA2["Object Attribute (Créditos Hipotecarios)"]
    O["Objeto / Fila (o in O)"] -->|Assign| OA1["Object Attribute (Sucursal Santiago)"]
    OA1 -->|Assign| OA2
    UA2 -->|Assign| PC["Policy Class (Regulación Bancaria)"]
    OA2 -->|Assign| PC

2. Condición Matemática de Decisión de Acceso en Multi-Policy Classes

Dado un usuario $u \in \mathcal{U}$, una operación $op \in \text{AR}$ (Access Rights) y un objeto $o \in \mathcal{O}$, el acceso $P(u, op, o)$ se concede si y solo si, para cada Clase de Política $pc \in \mathcal{PC}$ que contiene a $o$, existe al menos una arista de asociación $(ua, \text{ops}, oa)$ tal que: 1. $ua$ es alcanzable desde $u$ por caminos de asignación ($u \to^+ ua$). 2. $op \in \text{ops}$. 3. $oa$ es alcanzable desde $o$ ($o \to^+ oa$) y $oa \to^+ pc$.'

Motor de Evaluación NGAC en Tiempo Real: Prohibiciones (Deny), Separación Dinámica de Deberes (SoD) y Obligaciones (55 min)

Motor de Evaluación NGAC en Tiempo Real: Prohibiciones (Deny), Separación Dinámica de Deberes (SoD) y Obligaciones

1. Obligaciones Basadas en Eventos (Event-Response Architecture: When-Do)

La característica más potente de Sentinel-NGAC frente a cualquier motor estático es que el grafo muta dinámicamente mediante Obligaciones (Event Pattern -> Response Actions) para imponer Separación Dinámica de Funciones (Dynamic Separation of Duty — DSoD): - Regla: "El mismo ingeniero o analista que crea una orden de pago (create_payment_order) queda automáticamente bloqueado para aprobar esa misma orden (approve_payment_order), aunque posea el rol de Supervisor". - Ejecución NGAC: En el milisegundo en que $u_1$ ejecuta create sobre el objeto $o_{99}$, la obligación dispara atómicamente create prohibition deny(u_1, {approve}, o_{99}) en el grafo.

export interface NgacAssociation {
  uaId: string;
  operations: ReadonlySet;
  oaId: string;
  policyClassId: string;
}

export interface NgacProhibition { subjectId: string; // u o ua deniedOperations: ReadonlySet; targetId: string; // o u oa }

export function evaluateNgacAccessDecision(params: { reachableUserAttrs: ReadonlySet; reachableObjectAttrs: ReadonlySet; requiredPolicyClasses: ReadonlySet; associations: readonly NgacAssociation[]; prohibitions: readonly NgacProhibition[]; operation: string; }): { granted: boolean; satisfiedPoliciesCount: number; blockedByProhibition: boolean } { const { reachableUserAttrs, reachableObjectAttrs, requiredPolicyClasses, associations, prohibitions, operation } = params;

for (const prohib of prohibitions) { if ( reachableUserAttrs.has(prohib.subjectId) && reachableObjectAttrs.has(prohib.targetId) && prohib.deniedOperations.has(operation) ) { return { granted: false, satisfiedPoliciesCount: 0, blockedByProhibition: true }; } }

const satisfiedPolicies = new Set(); for (const assoc of associations) { if ( reachableUserAttrs.has(assoc.uaId) && reachableObjectAttrs.has(assoc.oaId) && assoc.operations.has(operation) ) { satisfiedPolicies.add(assoc.policyClassId); } }

const allPoliciesSatisfied = Array.from(requiredPolicyClasses).every((pc) => satisfiedPolicies.has(pc) );

return { granted: requiredPolicyClasses.size > 0 && allPoliciesSatisfied, satisfiedPoliciesCount: satisfiedPolicies.size, blockedByProhibition: false }; }

Sentinel-NGAC Zero-Trust Identity: Bloqueo de Dominios Desechables, Contexto de Sesión Firmado y Excepción E2E (50 min)

Sentinel-NGAC Zero-Trust Identity: Bloqueo de Dominios Desechables, Contexto de Sesión Firmado y Excepción E2E

1. Validación Estricta de Identidad Antes de Poblar el Contexto de Base de Datos

En el ecosistema Sentinel-NGAC, ninguna identidad puede instanciar un nodo $\mathcal{U}$ en el grafo si proviene de dominios desechables (Throwaway / Temp-Mail Domains como mailinator.com, 10minutemail.com, yopmail.com), con la única excepción formal del dominio de automatización hermética @e2e.internal.local reservado para los runners de pruebas E2E (Playwright/Cypress) en entornos aislados.

Módulo 2: Módulo 2: Seguridad Avanzada en Oracle Database: PL/SQL Secure Coding, VPD y Contextos de Aplicación

Blindaje de Paquetes Oracle PL/SQL: AUTHID CURRENT_USER vs DEFINER, Prevención de Confused Deputy y DBMS_ASSERT (55 min)

Blindaje de Paquetes Oracle PL/SQL: AUTHID CURRENT_USER vs DEFINER, Prevención de Confused Deputy y DBMS_ASSERT

1. El Peligro Crítico del Modo por Defecto AUTHID DEFINER en PL/SQL

En Oracle Database, todo procedimiento o paquete PL/SQL creado sin cláusula explícita se compila por defecto con AUTHID DEFINER (Definer's Rights): esto significa que cualquier SQL dinámico dentro del paquete se ejecuta con los privilegios máximos del esquema propietario (ej. CORE_ADMIN), NO con los privilegios del usuario conectado.

Si un paquete con AUTHID DEFINER concatena un parámetro en un EXECUTE IMMEDIATE, un atacante con privilegios mínimos escala instantáneamente a administrador del esquema (Vulnerabilidad Confused Deputy).

Tres Reglas Inmutables para PL/SQL Seguro

1. Usar Variables Bind (:1, USING) para todo valor de datos. 2. Validar identificadores dinámicos (nombres de tablas/columnas) exclusivamente con SYS.DBMS_ASSERT: - DBMS_ASSERT.SIMPLE_SQL_NAME(p_col) - DBMS_ASSERT.SQL_OBJECT_NAME(p_table) 3. Declarar AUTHID CURRENT_USER (Invoker's Rights) o restringir mediante ACCESSIBLE BY (PACKAGE ...).

CREATE OR REPLACE PACKAGE sec_audit_pkg
  AUTHID CURRENT_USER
  ACCESSIBLE BY (PACKAGE api_gateway_pkg)
AS
  PROCEDURE purge_partition_safe(p_table_name IN VARCHAR2, p_cutoff_date IN DATE);
END sec_audit_pkg;
/

CREATE OR REPLACE PACKAGE BODY sec_audit_pkg AS PROCEDURE purge_partition_safe(p_table_name IN VARCHAR2, p_cutoff_date IN DATE) IS v_safe_table VARCHAR2(128); v_sql VARCHAR2(500); BEGIN -- Sanitización criptográfica/diccionario contra SQL Injection de segundo orden v_safe_table := SYS.DBMS_ASSERT.SQL_OBJECT_NAME( SYS.DBMS_ASSERT.SIMPLE_SQL_NAME(p_table_name) ); v_sql := 'DELETE FROM ' || v_safe_table || ' WHERE created_at < :1'; EXECUTE IMMEDIATE v_sql USING p_cutoff_date; END purge_partition_safe; END sec_audit_pkg; /

Oracle Virtual Private Database (VPD / FGAC): Políticas DBMS_RLS y Secure Application Contexts (SYS_CONTEXT) (55 min)

Oracle Virtual Private Database (VPD / FGAC): Políticas DBMS_RLS y Secure Application Contexts (SYS_CONTEXT)

1. Reescritura Transparente del Árbol Sintáctico en el Kernel de Oracle

Con Oracle Virtual Private Database (DBMS_RLS), la seguridad no depende de que el desarrollador backend recuerde escribir WHERE tenant_id = ... en sus $4,000$ consultas SQL. Cuando cualquier sesión ejecuta SELECT * FROM financial_accounts, el kernel de Oracle invoca automáticamente la función de política asociada y reescribe el predicado en el optimizador antes de ejecutar:

-- 1. Crear un Contexto de Aplicación Seguro vinculado exclusivamente a un paquete confiable
CREATE OR REPLACE CONTEXT sentinel_ngac_ctx USING sec_context_mgr_pkg ACCESSED GLOBALLY;

-- 2. Función de Política VPD que inyecta el predicado de aislamiento CREATE OR REPLACE FUNCTION fn_vpd_tenant_isolation( p_schema IN VARCHAR2, p_object IN VARCHAR2 ) RETURN VARCHAR2 DETERMINISTIC AS v_tenant_id VARCHAR2(64); BEGIN v_tenant_id := SYS_CONTEXT('sentinel_ngac_ctx', 'CURRENT_TENANT_ID'); IF v_tenant_id IS NULL THEN -- Fail-Closed: Cero filas visibles si no hay contexto autenticado RETURN '1 = 0'; END IF; RETURN 'tenant_id = SYS_CONTEXT(''sentinel_ngac_ctx'', ''CURRENT_TENANT_ID'')'; END; /

Column-Level VPD con SEC_RELEVANT_COLS_OPT => DBMS_RLS.ALL_ROWS: Permite devolver todas las filas de la tabla en un reporte estadístico pero enmascarando automáticamente con NULL las columnas sensibles (salary, tax_id) para las filas donde el usuario no tiene permiso granular.

Defensa Contra DBAs Maliciosos o Comprometidos: Oracle Database Vault Realms y Unified Auditing Inmutable (50 min)

Defensa Contra DBAs Maliciosos o Comprometidos: Oracle Database Vault Realms y Unified Auditing Inmutable

1. Separación entre Administración de Infraestructura (SYSDBA) y Acceso a Datos de Negocio

En una base de datos tradicional sin blindaje, un administrador de sistemas con rol DBA o SYSDBA puede ejecutar SELECT * FROM hr.executive_salaries o alterar saldos contables. Oracle Database Vault crea un Realm (Reino Protegido) alrededor de los esquemas de negocio de modo que el DBA puede hacer backups, gestionar tablespaces y aplicar parches, pero recibe ORA-47401: Realm violation si intenta leer o modificar una sola fila de las tablas de clientes.'

Módulo 3: Módulo 3: PostgreSQL Row-Level Security (RLS), Políticas Leaky y Criptografía TDE / KMS

Arquitectura de PostgreSQL Row-Level Security (RLS): Cláusulas USING vs WITH CHECK, FORCE RLS y Funciones LEAKPROOF (55 min)

Arquitectura de PostgreSQL Row-Level Security (RLS): Cláusulas USING vs WITH CHECK, FORCE RLS y Funciones LEAKPROOF

1. Diferencia Exacta entre USING (Visibilidad de Filas Existentes) y WITH CHECK (Validación de Mutaciones)

En PostgreSQL, una política RLS en modo PERMISSIVE o RESTRICTIVE controla dos momentos distintos del ciclo de vida de una tupla: - Expresión USING (...): Filtra qué filas existentes en disco pueden ser vistas por SELECT, UPDATE o DELETE. - Expresión WITH CHECK (...): Valida que la nueva versión de la fila producida por un INSERT o UPDATE cumpla la invariante de seguridad (impidiendo que el Tenant A inserte o transfiera maliciosamente una fila asignándole tenant_id = 'Tenant B').

ALTER TABLE ledger_entries ENABLE ROW LEVEL SECURITY;
-- Crítico: Sin FORCE, el propietario de la tabla ignora silenciosamente el RLS
ALTER TABLE ledger_entries FORCE ROW LEVEL SECURITY;

CREATE POLICY pol_tenant_isolation ON ledger_entries AS RESTRICTIVE FOR ALL TO app_runtime_role USING ( tenant_id = NULLIF(current_setting('app.current_tenant_id', true), '') ) WITH CHECK ( tenant_id = NULLIF(current_setting('app.current_tenant_id', true), '') );

2. Prevención de Ataques de Canal Lateral por Optimizador (Optimizer Side-Channel Leaks)

Si un atacante escribe SELECT * FROM payroll WHERE f_divide_by_zero_if_match(salary) > 0, el optimizador de PostgreSQL jamás empujará la función maliciosa del usuario antes del filtro RLS porque las políticas RLS actúan como una security_barrier, evaluando antes únicamente operadores nativos certificados como LEAKPROOF.

Prevención de Fuga de Contexto entre Tenants (Context Bleeding) en Pools de Conexiones con SET LOCAL (50 min)

Prevención de Fuga de Contexto entre Tenants (Context Bleeding) en Pools de Conexiones con SET LOCAL

1. El Error Catastrófico de Usar SET app.current_tenant_id en PgBouncer Transaction Pooling

Si un microservicio usa SET app.current_tenant_id = 'TENANT_VIP' (nivel de sesión) sobre un pool de conexiones compartido, cuando la petición termina y devuelve la conexión física al pool, la siguiente petición de otro cliente que reutilice ese socket heredará la variable TENANT_VIP y verá los datos del cliente anterior.

La Regla de Oro Inquebrantable: SET LOCAL Dentro de un Bloque Transaccional

Al ejecutar SET LOCAL app.current_tenant_id = 'TENANT_VIP' (o set_config('app.current_tenant_id', $1, true) con is_local = true), PostgreSQL destruye y limpia automáticamente la variable en el instante exacto del COMMIT o ROLLBACK, garantizando Cero Context Bleeding incluso bajo fallos inesperados.

Criptografía de Datos en Reposo y en Uso: Envelope Encryption (KEK/DEK), TDE y Blind Indexing con HMAC-SHA256 (50 min)

Criptografía de Datos en Reposo y en Uso: Envelope Encryption (KEK/DEK), TDE y Blind Indexing con HMAC-SHA256

1. Transparent Data Encryption (TDE) vs Column-Level Application Encryption

- TDE (Cifrado Transparente de Bloques/Tablespaces): Protege contra el robo físico de los discos duros o snapshots en S3, pero los datos están completamente en claro en la memoria RAM del motor y para cualquier consulta SQL autenticada. - Cifrado de Campo en Aplicación (AES-256-GCM) con Blind Indexing: Para columnas ultra-sensibles (RUT/SSN, número de tarjeta PAN) donde la base de datos nunca debe ver el texto plano pero necesitamos seguir haciendo búsquedas exactas WHERE tax_id_blind_idx = $1 usando un índice B+Tree: 1. Se almacena el cifrado autenticado aleatorio $\text{AES-GCM}_{\text{DEK}}(\text{IV}, \text{PII})$. 2. Se almacena en una columna indexada adjunta el Blind Index determinista calculado con una clave secreta independiente en HSM/Vault: $\text{BlindIndex}(\text{PII}) = \text{HMAC-SHA256}\left(K_{\text{index}}, \; \text{Normalize}(\text{PII})\right)$

Módulo 4: Módulo 4: Auditoría Forense de Base de Datos, Laboratorio SQL NGAC y Certificación

Diseño de Tablas de Auditoría Inmutables con Encadenamiento Criptográfico de Hashes (Tamper-Evident Ledger) (50 min)

Diseño de Tablas de Auditoría Inmutables con Encadenamiento Criptográfico de Hashes (Tamper-Evident Ledger)

1. Cómo Detectar Matemáticamente si un Atacante con Acceso Root Borró o Alteró un Log

En una tabla de auditoría bancaria o militar, cada fila insertada $i$ incluye el hash criptográfico encadenado del registro anterior $H_{i-1}$:

$H_i = \text{SHA256}\left( H_{i-1} \;\|\; \text{seq\_id}_i \;\|\; \text{actor}_i \;\|\; \text{action}_i \;\|\; \text{payload}_i \;\|\; \text{ts}_i \right)$

Si alguien modifica una columna de la fila $500$ o elimina la fila $500$, toda la cadena de verificación desde $i=500$ hacia adelante se rompe instantáneamente.

Laboratorio Práctico SQL: Auditoría de Decisiones del Motor Sentinel-NGAC y Separación Dinámica de Funciones (DSoD) (60 min)

Laboratorio Práctico SQL: Auditoría de Decisiones del Motor Sentinel-NGAC y Separación Dinámica de Funciones (DSoD)

Contexto del Laboratorio

Auditas el motor de control de acceso Sentinel-NGAC de una plataforma bancaria. Tienes tres tablas en PostgreSQL: 1. ngac_access_requests: solicitudes de operación evaluadas (req_id, user_id, user_attr, operation, object_id, object_attr). 2. ngac_associations: aristas de permiso válidas en el grafo (user_attr, operation, object_attr). 3. ngac_dynamic_prohibitions: prohibiciones dinámicas activas generadas por obligaciones de Separación de Funciones (user_id, denied_operation, object_id).

Reglas de Negocio a Consultar

Para cada solicitud en ngac_access_requests, determina su resolución exacta y luego agrupa por user_id para calcular: 1. total_requests: total de solicitudes del usuario (COUNT(*)::INT). 2. granted_count: solicitudes que tienen una asociación válida en ngac_associations (r.user_attr = a.user_attr AND r.operation = a.operation AND r.object_attr = a.object_attr) Y NO tienen una prohibición activa en ngac_dynamic_prohibitions (r.user_id = p.user_id AND r.operation = p.denied_operation AND r.object_id = p.object_id). 3. dsod_blocked_count: solicitudes que sí tenían asociación de permiso pero fueron bloqueadas por existir una prohibición en ngac_dynamic_prohibitions (COUNT(*) FILTER (...)::INT). 4. unauthorized_no_assoc_count: solicitudes que no tenían asociación válida en ngac_associations. 5. Ordena el resultado por user_id ASC.

Examen de Certificación: Principal Database Security, Sentinel-NGAC & Oracle/PostgreSQL Architect (SEC-501) (45 min)

Examen de Certificación: Principal Database Security, Sentinel-NGAC & Oracle/PostgreSQL Architect (SEC-501)

Certifica tu dominio de nivel Principal sobre el estándar NIST NGAC (INCITS 565), blindaje de paquetes Oracle PL/SQL y Virtual Private Database (VPD), PostgreSQL Row-Level Security (RLS) y criptografía de datos.