/

Seguridad: listas negras de tablas y columnas

El verdadero límite de seguridad vive en src/Config.php, no en la llamada ->columns() de ninguna página concreta.

->columns() no es un límite de seguridad

Llamar a ->columns('name', 'email') en una página solo cambia lo que la cuadrícula de esa página muestra. No afecta en nada a core/ajax_crud.php, el endpoint REST con el que realmente habla el JavaScript de cada widget - la API resuelve la configuración de una página volviendo a ejecutar su ruta (xcrud_load_hooks_from_page()), pero las columnas que expone una tabla real de la base de datos están gobernadas por el propio esquema de la tabla, no por lo que una página haya decidido mostrar. Un visitante que llame a la API directamente (abriendo DevTools, repitiendo la petición con otro route/query) no está restringido por ningún filtrado de ->columns() de ninguna página.

En otras palabras: ->columns() es una comodidad de visualización. Nunca es lo que se interpone entre una columna sensible y la red.

$blacklistedTables - el verdadero límite a nivel de tabla

Toda tabla real de la base de datos conectada es accesible a través de Xcrud por defecto (introspección en vivo, sin necesidad de registrar nada primero) - $blacklistedTables en src/Config.php es lo que elimina por completo el acceso a una tabla, sin importar lo que intente el PHP de cualquier página:

public static array $blacklistedTables = [
    'sys_settings', 'sys_settings_other', 'sys_notifications', 'logs',
];

Una tabla en la lista negra nunca puede alcanzarse mediante ->table(), como destino de ->relation(), ni como tabla hija de ->gallery() - llamar a ->table('logs') lanza un error de inmediato en lugar de renderizar silenciosamente una cuadrícula vacía.

$blacklistedColumns - bloqueo a nivel de columna

Algunas tablas está bien exponerlas en general, pero tienen columnas concretas que nunca deberían viajar de ida y vuelta por la API - un hash de contraseña, un token interno, una columna blob heredada. $blacklistedColumns bloquea esas columnas dentro de una tabla que, por lo demás, es accesible, indexada por nombre de tabla:

public static array $blacklistedColumns = [
    'user' => [
        'password', 'confirm_password', 'session',
        'remember_token', 'remember_token_expires',
        'confirmation_code', 'app_key',
    ],
    'customers'    => ['avatar'],
    'productlines' => ['image'],
];

Una columna listada aquí queda oculta y bloqueada para escritura - nunca se devuelve en una respuesta JSON de lista/formulario ni se acepta en inserción/actualización, sin importar lo que pida cualquier llamada a ->columns()/->fields() de cualquier página. Esto es lo que realmente permite exponer con seguridad una tabla como user: la tabla en sí no necesita estar en la lista negra solo porque una de sus columnas sí deba estarlo.

$appSecret - firma, no lista negra

Una cuestión relacionada pero distinta: $appSecret firma con HMAC las condiciones ->where()/->subselect()/->pass_var() y los payloads de las condiciones lógicas antes de que viajen por el navegador, de modo que ajax_crud.php pueda rechazar una condición cuya firma no coincida. Protege el acotamiento intencional de una página (por ejemplo, "mostrar solo los pedidos de este cliente") frente a manipulaciones desde el cliente - no sustituye a la lista negra de tablas/columnas descrita arriba. Consulta Despliegue en producción para generar un valor robusto antes del lanzamiento.