jsonapi_security
Introduction
JSON:API Security Hardening module enhances the security of JSON:API–based applications by enforcing strict, defense-in-depth controls.
While Drupal core and contributed modules such as JSON:API Extras allow for granular configuration, additional security hardening is often beneficial. This module provides a "Secure by Default" global policy layer with enhanced privacy controls, query limits, and access restrictions.
Requirements
- Drupal 10.6+ or 11.2+
- JSON:API (Drupal core)
Features
1. Query Depth Limiting
Limits the depth of relationship chains in include queries.
- Policy: Enforces a global limit on the depth of the include parameter.
- Default: Limits requests to a depth of 2.
- Per-Resource Overrides: Specific resource types can be configured with custom depth limits (e.g., allow
menu_link_content--menu_link_content
a depth of 5 for menu hierarchies).
2. Collection Access Control
Restricts access to entity collection endpoints (e.g., /jsonapi/user/user).
- Policy: A global "Restrict Collection Access" switch.
- Effect:Blocks access to JSON:API collection endpoints with a 403 Forbidden response if the requesting user does not have access to the corresponding entity type's administrative collection route (e.g., /admin/people for users).
- Exceptions: Administrators can define specific resource types and roles that are allowed to bypass this restriction, regardless of administrative permissions. For example,
resource_type|role1,role2 (e.g., node--event|anonymous,authenticated). - Mapping: Explicitly map a resource type to a collection route to check access against.
- Reason: Some resources (like file--file) use a Drupal View for their collection endpoint instead of the standard JSON:API route. In these cases, the standard check fails because it can't automatically determine the administrative route.
- Format:
resource_type|route_name (e.g., file--file|view.files.page_1).
3. Strict Read-Only Mode
Enforces read-only policies at the API level.
- Policy: A global "Block Write Operations" switch with an Allowlist.
- Effect: Rejects POST, PATCH, and DELETE requests with a 405 Method Not Allowed.
- Exceptions: Administrators can define specific resources and methods that are allowed to accept write operations (e.g.,
contact_message--feedback|POST, PATCH).
4. UID 1 (Super User) Protection
Provides additional protection for the UID 1 (super user) account.
- Information Hiding: By default, access to UID 1's user data via JSON:API is completely blocked. Requests return a 404 Not Found response, hiding the UUID and all information of the account.
- Configuration: To allow access to UID 1 data, add the following to your settings.php:
$settings['jsonapi_security_allow_uid1_access'] = TRUE;
- Configuration: To allow access to UID 1 data, add the following to your settings.php:
- Login Blocking: By default, attempts to authenticate as UID 1 via JSON:API using HTTP Basic Authentication are blocked. Authentication will silently fail, returning a 401 Unauthorized response.
- Requirement: This feature only affects when the basic_auth module is enabled and login via the basic auth service.
- Configuration: To allow UID 1 access, add the following to your settings.php:
$settings['jsonapi_security_allow_uid1_login'] = TRUE;
5. Two-Factor Authentication (TFA) Integration (Sub-module)
Integrates Two-Factor Authentication (TFA) into JSON:API workflows.
Note: This feature is provided as an optional sub-modulejsonapi_security_tfa and requires the TFA module to be installed.
- Effect: Requires users to enable Two-Factor Authentication (TFA) before they can access or modify data via JSON:API.
- Installation: Enable separately via
drush en jsonapi_security_tfa. - Important: Once enabled, all users with existing sessions must re-login through the TFA flow to gain JSON:API access.
6. Security Logging
Logs security-relevant actions performed via JSON:API for audit purposes.
Installation
- Place the module in the
modules/customormodules/contribdirectory. - Enable the module via the Drupal admin UI or Drush:
drush en jsonapi_security - Configure the global policies at
/admin/config/services/jsonapi-hardening.
Configuration
All settings are managed from a single configuration screen.
1. Query Depth
- Limit Query Depth: [Checkbox]
- Max Depth: (Integer, default: 2)
- Depth Overrides: (Text Area) — Per-resource depth overrides in format
resource_type:depth(e.g.,menu_link_content--menu_link_content:5).
2. Collection Access Control
- Restrict Collection Access: [Checkbox] — Blocks access to collection endpoints unless the user has administrative listing permissions.
- Collection Route Mapping: (Text Area) — Map a resource type to a collection route. Format:
resource_type|route_name. Supports * wildcard. - Collection Restriction Exceptions: (Text Area) — Bypass rules in format
resource_type|role. Supports * wildcard.
3. Strict Read-Only
- Block Write Operations: [Checkbox] — Globally blocks POST/PATCH/DELETE.
- Write Exceptions: (Text Area) — One per line. Format:
resource_type|METHODS(e.g.,contact_message--feedback|POST, PATCH). Supports wildcards.
Extension Points
This module provides events for developers to extend or customize security policies:
Event DescriptionJsonApiSecurityDepthCheckEvent
Fired before depth validation. Allows custom logic to modify or bypass depth limits.
JsonApiSecurityAnonymizeEvent
Fired during response normalization. Allows custom logic to control field anonymization.
JsonApiSecurityWriteCheckEvent
Fired before write operation validation. Allows custom logic to permit or deny writes.
Example usage:
use Drupal\jsonapi_security\Event\JsonApiSecurityDepthCheckEvent; use Symfony\Component\EventDispatcher\EventSubscriberInterface; class MySecuritySubscriber implements EventSubscriberInterface { public static function getSubscribedEvents() { return [ JsonApiSecurityDepthCheckEvent::class => 'onDepthCheck', ]; } public function onDepthCheck(JsonApiSecurityDepthCheckEvent $event) { // Allow deeper includes for authenticated users. if ($this->currentUser->isAuthenticated()) { $event->setMaxDepth(5); } } }
Maintenance
This module follows Drupal security best practices. Security-related issues should be reported to the Drupal Security Team following by the disclosure policy.