logo

Extra Block Types (EBT) - New Layout Builder experience❗

Extra Block Types (EBT) - styled, customizable block types: Slideshows, Tabs, Cards, Accordions and many others. Built-in settings for background, DOM Box, javascript plugins. Experience the future of layout building today.

Demo EBT modules Download EBT modules

❗Extra Paragraph Types (EPT) - New Paragraphs experience

Extra Paragraph Types (EPT) - analogical paragraph based set of modules.

Demo EPT modules Download EPT modules

Scroll
21/06/2025, by Ivan

Le module JSON:API est conçu pour prendre le modèle de données défini dans Drupal via l’Entity API, le Field API et le Typed Data API, et l’exposer via une API conforme à la spécification JSON:API afin de faciliter l’interaction avec les données (entités) gérées par Drupal.

Ce faisant, il respecte toutes les mesures de sécurité de Drupal pour ces données :

  • L’accès aux entités est respecté.
  • L’accès aux champs est respecté.
  • Lors de la modification des données, les contraintes de validation sont respectées.
  • Le drapeau internal est respecté (voir la documentation sur la manière dont il peut être défini sur une définition de type d’entité, de champ ou de propriété).

En d’autres termes : JSON:API ne contourne aucune des mesures de sécurité existantes et n’ajoute aucune couche supplémentaire ; il réutilise les fondations de Drupal.

Des bugs dans les types d’entités, types de champs et types de données peuvent entraîner des vulnérabilités de sécurité

Cependant, des bugs existent dans le code implémentant les types d’entités, types de champs et types de données, ainsi que leurs gestionnaires de contrôle d’accès et contraintes de validation. Cela s’explique en grande partie par l’héritage de Drupal : initialement Drupal n’avait pas de contraintes de validation mais des callbacks de validation de formulaire ; le passage à une mentalité API-first est considéré comme terminé dans le cœur de Drupal, mais n’est pas garanti pour les modules contrib ou personnalisés.

Ces bugs peuvent mener à des vulnérabilités de sécurité ; cela a déjà été le cas. Ces vulnérabilités ne sont pas limitées au module JSON:API ; elles affectent aussi, par exemple, le module RESTful Web Services ainsi que tout code PHP interagissant avec l’Entity API.

Cependant, comme un utilisateur malveillant peut plus facilement accéder à une API HTTP comme JSON:API ou RESTful Web Services qu’à une API PHP, une attention supplémentaire est nécessaire. Contrairement à d’autres modules API HTTP, JSON:API offre une plus grande surface d’API par défaut : tous les types d’entités non internal sont disponibles par défaut (tout en respectant l’accès aux entités) pour faciliter l’expérience développeur.

Six considérations de sécurité

1. L’importance d’utiliser des modules stables et contribué

Les vulnérabilités de sécurité causées par les types d’entités, types de champs et types de données sont corrigées aussi vite que possible uniquement pour les modules stables publiés sur Drupal.org et couverts par la politique des avis de sécurité. Les modules personnalisés et les modules contrib non stables ne sont pas couverts. Si vous utilisez certains de ces derniers, soyez particulièrement vigilant.

2. Audit de l’accès aux entités et champs

Que vous utilisiez JSON:API ou un autre module de type API, il est toujours recommandé de réaliser un audit de l’accès aux entités et champs sur les sites Drupal. Ceci est particulièrement important si les capacités d’écriture de JSON:API sont activées.

3. N’exposer que ce que vous utilisez

Lorsque certains types de ressources spécifiques (types d’entités + bundles) n’ont pas besoin d’être exposés, après avoir refusé l’accès, vous pouvez aller plus loin et les désactiver. Pour désactiver un type de ressource ou un champ, il existe une API PHP que vous pouvez implémenter dans un module personnalisé, ou vous pouvez utiliser le module contrib JSON:API Extras, qui fournit une interface pour désactiver des types de ressources et champs. Cela n’est pas toujours possible, mais si le propriétaire du site possède aussi tous les clients API, vous pouvez réduire la surface de l’API au minimum.

4. Mode lecture seule

Si vous avez uniquement besoin de lire les données, vous pouvez activer le mode lecture seule de JSON:API à /admin/config/services/jsonapi. Cela atténue les risques liés à des bugs hypothétiques, encore inconnus, dans les contraintes de validation et la logique d’écriture existantes. Comme la plupart des configurations Drupal découplées modernes ont seulement besoin de lire les données, le mode lecture seule est activé par défaut. (Dans le JSON:API du cœur de Drupal et la version 2.4 et ultérieures du module contrib.)

5. Sécurité par l’obscurité : chemin de base secret

Le chemin de base par défaut de JSON:API est /jsonapi. Il peut être changé en quelque chose comme /hidden/b69dhj027ooae/jsonapi, ce qui réduit l’efficacité des attaques automatisées. Créez sites/example.com/services.yml s’il n’existe pas encore et ajoutez ceci :

parameters:
  jsonapi.base_path: /hidden/b69dhj027ooae/jsonapi

6. Limiter quels bundles d’entités peuvent être créés ou modifiés en supprimant certaines routes

Si vous devez seulement créer ou mettre à jour certains bundles d’entités via JSON:API, vous pouvez implémenter un event subscriber pour supprimer toutes les routes POST et PATCH sauf une liste blanche dans un module personnalisé. Cela s’applique après la désactivation du mode lecture seule et peut nécessiter une reconstruction du routeur.

Ajoutez un service dans le fichier services.yml de votre module :

services:
  mymodule.route_subscriber:
    class: Drupal\mymodule\Routing\JsonapiLimitingRouteSubscriber
    tags:
      - { name: event_subscriber }

Créez l’event subscriber. Cet exemple empêche aussi la suppression de contenu via JSON:API :

<?php

namespace Drupal\mymodule\Routing;

use Drupal\Core\Routing\RouteSubscriberBase;
use Symfony\Component\Routing\RouteCollection;

/**
 * Classe JsonapiLimitingRouteSubscriber.
 *
 * Supprime toutes les routes DELETE des ressources JSON:API pour protéger le contenu.
 *
 * Supprime les routes POST et PATCH sauf celles autorisées pour que les utilisateurs puissent créer et modifier via l’API découplée.
 */
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)) {
          // Nous ne voulons jamais supprimer de données, seulement dépublier.
          $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);
            }
          }
        }
      }
    }
  }

  /**
   * Obtient les types de ressources modifiables, accessibles aux modifications via l’API.
   *
   * @return array
   *   Liste des types de ressources JSON:API modifiables sous forme de clés.
   */
  public function mutableResourceTypes(): array {
    return [
      'node--article' => TRUE,
      'node--document' => TRUE,
      'custom_entity--custom_entity' => TRUE,
    ];
  }

}

Limiter l’accès à toutes les routes JSON:API avec une permission supplémentaire

Lorsque vous utilisez JSON:API pour des intégrations backend, des clients API limités ou d’autres cas non publics, il peut être souhaitable de restreindre toutes les routes JSON:API aux utilisateurs avec une permission spécifique. Pour cela, ajoutez ce snippet dans l’event subscriber mentionné :

    // Limiter l’accès à toutes les routes JSON:API avec une permission supplémentaire.
    foreach ($collection as $route) {
      $defaults = $route->getDefaults();
      if (!empty($defaults['_is_jsonapi'])) {
        $route->setRequirement('_permission', 'FOO custom access jsonapi');
      }
    }

Puis définissez cette permission dans FOO.permissions.yml et attribuez-la aux rôles utilisateurs souhaités.

Article tiré de la documentation Drupal.