Drupal 10.x Outbound HTTP SSL Verification Requires Trusted CA Bundle
0 reputation · 02 Apr 2021, 01:51 UTC
0 reputation · 02 Apr 2021, 01:51 UTC
In Drupal 10.x the default Guzzle client used for outbound HTTPS requests enables peer certificate verification (verify => true) unless the administrator overrides it via $settings['http_client_config']['verify'] in settings.php. This behavior causes requests to fail on environments that lack a trusted CA bundle, such as minimal Windows containers, unless verification is disabled or a custom certificate path is supplied.
The core team has not yet decided whether to expose a user‑interface toggle for relaxing SSL verification, which would let site builders disable verification for internal services without editing code. Any such toggle must weigh the security risk of man‑in‑the‑middle attacks against the need to integrate with legacy or self‑signed endpoints, and it would affect all Guzzle‑based calls including remote aggregators and OAuth providers.
Should a UI‑driven option be added to the administration interface, how should its scope be limited to avoid unintended side effects, and what safeguards or warnings should accompany it to ensure administrators understand the security implications?
Add a UI-driven option, but restrict it to per-service configuration rather than a global toggle. Each outbound service integration (remote aggregator, OAuth provider, custom HTTP client) should declare its own verification policy, and the administration interface should only allow relaxation for explicitly registered endpoints.
Drupal 10.x uses Guzzle with verify => true by default for all outbound HTTPS requests. The existing override $settings['http_client_config']['verify'] in settings.php applies globally, which is why a UI toggle must not replicate that behavior. A global disable would affect payment gateways, OAuth providers, and any other Guzzle-based call, exposing credentials and transaction data to man-in-the-middle attacks.
Confirmed fact: The HTTP client factory in \Drupal\Core\Http\ClientFactory reads $settings['http_client_config'] and merges it into every client instance. There is no built-in mechanism to vary verification per endpoint.
my_module.oauth_provider, aggregator.feed_1) via a http_client_options alter hook or a new HttpClientConfigInterface.http_client_config.my_module.oauth_provider.verify). This keeps the setting out of settings.php and under configuration management.ClientFactory::fromOptions() builds a client for a specific service, it merges the service-specific config after the global settings.php values, allowing a targeted verify => false or a custom CA bundle path without affecting other clients.administer site configuration permission (or a new dedicated permission configure http client ssl) to change verification settings.<endpoint> to interception. Only use for internal services with self-signed certificates where a proper CA bundle cannot be deployed."verify => false, require an explicit hostname or CIDR pattern (e.g., internal-api.example.com, 10.0.0.0/8). Reject bare false without a scope.warning) every time verification is disabled for a service, including the user ID, service ID, timestamp, and allowed host pattern.verification_expires timestamp (default 90 days). When expired, the UI shows a re-confirmation prompt and logs a notice.// In a module's http_client_options.alter.yml or a new EventSubscriber
function mymodule_http_client_options_alter(array &$options, string $service_id): void {
$config = \Drupal::config('http_client_config.' . $service_id);
if ($config->get('verify') === false) {
$allowed_hosts = $config->get('allowed_hosts');
$options['verify'] = function ($host) use ($allowed_hosts) {
return !_mymodule_host_matches($host, $allowed_hosts);
};
// Log the override
\Drupal::logger('http_client_ssl')->warning('SSL verification disabled for @service (hosts: @hosts)', [
'@service' => $service_id,
'@hosts' => implode(', ', $allowed_hosts),
]);
}
elseif ($ca_bundle = $config->get('ca_bundle')) {
$options['verify'] = $ca_bundle;
}
}
Does your site already use a custom ClientFactory decorator or a contributed module (e.g., http_client_manager) that intercepts client creation? If yes, the per-service merge point may already exist and the UI can hook into it directly. If not, a core patch or a small contrib module introducing HttpClientConfigInterface is the cleanest path.
Use comments to ask for clarification. Post a solution as an answer.
32,775 reputation · 02 Apr 2021, 06:45 UTC
A practical clarification for the minimal-container case: verify accepts a path to a CA bundle, not only a boolean. In Drupal 10 with Guzzle 7, verify => true delegates to PHP’s OpenSSL CA store, which is often missing on minimal Windows containers. Supplying $settings['http_client_config']['verify'] = '/path/to/cacert.pem' restores verification without disabling it site-wide.
Also note that http_client_config is merged in \Drupal\Core\Http\ClientFactory at container build time. Any change requires a cache rebuild, so a UI toggle would still be a deployment-level change and would affect all Guzzle-based calls — updates, remote streams, feeds, OAuth — until the container is rebuilt.