Considerazioni sulla sicurezza
Il modulo JSON:API è progettato per prendere il modello di dati definito in Drupal utilizzando l’Entity API, la Field API e la Typed Data API di Drupal ed esporlo tramite un’API conforme alla specifica JSON:API allo scopo di facilitare l’interazione con i dati (entità) gestiti da Drupal.
Nel farlo, rispetta tutte le misure di sicurezza di Drupal per tali dati:
- L’Entity Access è rispettato.
- Il Field Access è rispettato.
- Durante la modifica dei dati, i vincoli di validazione sono rispettati.
- Il flag
internal
è rispettato (vedi la documentazione su come può essere impostato su una definizione di tipo di entità, di campo o di proprietà).
In altre parole: JSON:API non aggira nessuna delle misure di sicurezza esistenti e non aggiunge un proprio livello; riutilizza le fondamenta di Drupal.
Bug in entity type, field type e data type possono portare a vulnerabilità di sicurezza
Ciononostante, esistono bug nel codice che implementa entity type, field type e data type, così come nei relativi access control handler e vincoli di validazione. Ciò può essere in gran parte attribuito all’eredità storica di Drupal: originariamente Drupal non aveva vincoli di validazione ma callback di validazione dei form; il passaggio a una mentalità “API-first” può essere considerato completo nel core di Drupal, ma non è garantito per i moduli contrib o personalizzati.
Tali bug possono portare a vulnerabilità di sicurezza; in passato è già accaduto. Queste vulnerabilità non sono limitate al modulo JSON:API; riguardano anche, per esempio, il modulo RESTful Web Services nonché qualsiasi codice PHP che interagisce con la Entity API.
Tuttavia, poiché un utente malintenzionato può accedere più facilmente a un’API HTTP come JSON:API o RESTful Web Services che non a una API PHP, in questo caso è necessaria particolare attenzione. A differenza di altri moduli di API HTTP, JSON:API ha una superficie di API più ampia “out of the box”: tutti gli entity type non internal
sono resi disponibili per impostazione predefinita (ovviamente continuando a rispettare l’Entity Access) per rendere l’esperienza di sviluppo la più fluida possibile.
Sei considerazioni sulla sicurezza
1. L’importanza di utilizzare moduli contrib stabili
Le vulnerabilità di sicurezza causate da entity type, field type e data type vengono risolte nel più breve tempo possibile solo per i moduli stabili pubblicati su Drupal.org e coperti dalla security advisory policy. I moduli personalizzati e i moduli contrib non stabili non sono coperti. Se stai usando alcuni di questi, presta particolare attenzione.
2. Audit di Entity & Field Access
Indipendentemente dal fatto che tu stia usando JSON:API o qualsiasi altro modulo di tipo API, è sempre raccomandato effettuare un audit di Entity Access & Field Access sui siti Drupal. Ciò è particolarmente importante se sono abilitate le funzionalità di scrittura di JSON:API.
3. Esporre solo ciò che utilizzi
Quando specifici tipi di risorsa (entity type + bundle) non devono essere esposti, dopo esserti assicurato che l’accesso sia negato, puoi andare oltre e disabilitarli. Per disabilitare un tipo di risorsa o un campo, c’è una PHP API che puoi implementare in un modulo personalizzato, oppure puoi usare il modulo contrib JSON:API Extras, che fornisce una UI per disabilitare tipi di risorsa e campi. Non sempre è possibile, ma nei casi in cui il proprietario del sito possiede anche tutti i client dell’API, puoi farlo per rendere la superficie dell’API il più piccola possibile.
4. Modalità sola lettura
Se per le tue esigenze specifiche ti serve solo leggere i dati, puoi scegliere di abilitare la modalità sola lettura di JSON:API in /admin/config/services/jsonapi
. Questo mitiga i rischi dovuti a bug ipotetici, ancora sconosciuti, nei vincoli di validazione e nella logica di scrittura preesistenti. Poiché la maggior parte delle moderne configurazioni decoupled di Drupal necessita solo di leggere i dati, la modalità sola lettura è attivata per impostazione predefinita. (Nel modulo JSON:API del core di Drupal e dalla versione 2.4 in poi del modulo contrib.)
5. Sicurezza per oscuramento: base path segreta
Il base path per JSON:API è /jsonapi
per impostazione predefinita. Questo può essere cambiato in qualcosa come /hidden/b69dhj027ooae/jsonapi
, che è un modo per ridurre l’efficacia degli attacchi automatici. Crea sites/example.com/services.yml
se non esiste già e aggiungi quanto segue:
parameters:
jsonapi.base_path: /hidden/b69dhj027ooae/jsonapi
6. Limitare quali bundle di entità possono essere creati o modificati rimuovendo alcune route
Se devi poter creare o aggiornare solo alcuni bundle di entità tramite JSON:API, puoi implementare un event subscriber per rimuovere tutte le route POST e PATCH tranne una whitelist in un modulo personalizzato. Questo avrà effetto dopo aver disabilitato la modalità sola lettura e può richiedere la ricostruzione del router.
Aggiungi un servizio al file services.yml del tuo modulo:
services:
mymodule.route_subscriber:
class: Drupal\mymodule\Routing\JsonapiLimitingRouteSubscriber
tags:
- { name: event_subscriber }
Crea l’event subscriber. Questo esempio rende anche impossibile eliminare qualsiasi contenuto tramite JSON:API
<?php
namespace Drupal\mymodule\Routing;
use Drupal\Core\Routing\RouteSubscriberBase;
use Symfony\Component\Routing\RouteCollection;
/**
* Classe JsonapiLimitingRouteSubscriber.
*
* Rimuove tutte le route DELETE dalle risorse jsonapi per proteggere i contenuti.
*
* Rimuove le route POST e PATCH dalle risorse jsonapi ad eccezione di quelle
* che vogliamo consentire agli utenti finali di creare e aggiornare tramite l'API decoupled.
*/
class JsonapiLimitingRouteSubscriber extends RouteSubscriberBase {
/**
* {@inheritdoc}
*/
protected function alterRoutes(RouteCollection $collection) {
$mutable_types = $this->mutableResourceTypes();
foreach ($collection as $name => $route) {
$defaults = $route->getDefaults();
if (!empty($defaults['_is_jsonapi']) && !empty($defaults['resource_type'])) {
$methods = $route->getMethods();
if (in_array('DELETE', $methods)) {
// Non vogliamo mai eliminare dati, solo annullarne la pubblicazione.
$collection->remove($name);
}
else {
$resource_type = $defaults['resource_type'];
if (empty($mutable_types[$resource_type])) {
if (in_array('POST', $methods) || in_array('PATCH', $methods)) {
$collection->remove($name);
}
}
}
}
}
}
/**
* Ottieni i tipi di risorsa modificabili, esposti alle modifiche via API.
*
* @return array
* Elenco dei tipi di risorsa jsonapi modificabili come chiavi.
*/
public function mutableResourceTypes(): array {
return [
'node--article' => TRUE,
'node--document' => TRUE,
'custom_entity--custom_entity' => TRUE,
];
}
}
Limitare l’accesso a tutte le route di JSON:API con un permesso aggiuntivo
Quando si usa JSON:API per integrazioni backend, client API limitati o altri casi d’uso non pubblici, può essere desiderabile limitare tutte le route JSON:API agli utenti con uno specifico permesso. In alternativa/in aggiunta, aggiungi il seguente snippet all’event subscriber citato:
// Limita l'accesso a tutte le route jsonapi con un permesso aggiuntivo.
foreach ($collection as $route) {
$defaults = $route->getDefaults();
if (!empty($defaults['_is_jsonapi'])) {
$route->setRequirement('_permission', 'FOO custom access jsonapi');
}
}
Quindi definisci quel permesso in FOO.permissions.yml e assegnalo ai ruoli utente desiderati.
Articolo tratto dalla Documentazione di Drupal.