- Image from Unsplash, user Kim Gorga, @kimgorga
1-Introduction
It's very common, when you're working on projects, to receive a ticket from the client requesting the removal of signals that make it easier to know with which technology the website has been generated.
Normally, the client performs a security audit to the platform and from there several frequent items are generated: update the core to keep up to date in security, Normally, the client performs a security audit to the platform and from there several frequent items are generated: updating the core to keep up to date in security (being aligned with https://www.drupal.org/security in core and patches), as well as some common places, which often go through hiding sensitive information to possible attackers.
2-Premise
- Okay, but are there ways to completely hide the fact that the website was built using Drupal?
- Well, no. In fact, anyone can open the code inspector console of a decent browser (Chrome, Firefox) and when in doubt as to whether they are looking at a Drupal-based site, call up the Drupal JavaScript object. And it will always respond with its associated properties and methods:
And usually a quick scan of their associated JavaScript libraries will reveal names like drupal.js, which makes it difficult to hide the technology (sometimes we even get the request to rename these JavaScript libraries to hide the keyword 'drupal'...).
Having explained this, it is true that we cannot hide the generator from a human eye, but perhaps we can help hide it (on a basic level) from the machines. Some tactics even include offering an adulterated robots.txt structure to simulate another technology and make crawlers believe that it's another platform (WordPress for example), and building a honeypots subsystem internal to the spoofed addresses to detect spying... but I think that's already another topic for another article.
3-Targets
Here (having stated this former important premise) I would just like to collect some solutions to hide meta-information in some parts of the Drupal installation when you wanna obfuscate that you are running a Drupal installation:
1- First of all: hide the "Generator" meta tag from the 'head' section of a document - page delivered to the web browser:
2- Then: I would also like to remove from the server -> client response headers a specific Drupal header called X-Generator, which delivers the server version of Drupal:
X-Generator is created in Drupal installations and fullfilled with info about the system version (xhr is a shortened way for XMLHttpRequest).
The tag is setted from the class ResponseGeneratorSubscriber present in the Core of Drupal:
Is managed through an onRespond() function that follows the Drupal event subscription pattern (itself based on Symfony event management):
/**
* Sets extra X-Generator header on successful responses.
*
* @param \Symfony\Component\HttpKernel\Event\FilterResponseEvent $event
* The event to process.
*/
public function onRespond(FilterResponseEvent $event) {
if (!$event->isMasterRequest()) {
return;
}
$response = $event->getResponse();
// Set the generator in the HTTP header.
list($version) = explode('.', \Drupal::VERSION, 2);
$response->headers->set('X-Generator', 'Drupal ' . $version . ' (https://www.drupal.org)');
}
4- Tasks
To make the hides of the information shown in the previous section, we will use a combined action of the paradigms that currently exist within Drupal: the procedural of the Hooks system (vestigial) and the OOP of the event subscription systems. We are going to use both techniques in a combined way.
4.1- Building a custom module
We're going to create a new custom module for our goals, I will call it "headers_manager" -in a clear show of creativity, of course- and I will create the basic resource:
headers_manager
\_headers_manager.info.yml
And as info:
name: Headers Manager
description: Custom Module created to manage meta-info from head and headers.
package: 'Workshop Drupal'
type: module
core: 8.x
4.2- Building a Hook
Next, we're going to work over the metatags in the
section of the HTML content, for wich we'll need a Drupal Hook, something called hook_page_attachments_alter, just a procedural function to change assets to a page before the rendering phase.According to its own documentation:
Use this hook when you want to remove or alter attachments on the page, or add attachments to the page that depend on another module's attachments (this hook runs after hook_page_attachments().
So we're going to use the hook within a .module file. In the hook only we'll review the html_head charged as attachment to every page sended to render. And if the keyname of the attachment is equals to the meta tag that we're looking for, then we'll unset the value.
/**
* Implements hook_page_attachements_alter().
* @param array $attachments
*/
function headers_manager_page_attachments_alter(array &$attachments) {
foreach ($attachments['#attached']['html_head'] as $key => $attachment) {
if ($attachment[1] == 'system_meta_generator') {
unset($attachments['#attached']['html_head'][$key]);
}
}
}
Now our custom module has:
headers_manager
\_headers_manager.module
\_headers_manager.info.yml
4.3- Building an Event Subscriber
The nex step is disable the X-Generator header in responses from the Server. For this, we'll build a new EventSubscriber as in the original case where the header is attached (has been seen before).
First, we're creating a new service for our Subscribe in a .service.yml file:
services:
headers_manager_response_header:
class: Drupal\headers_manager\EventSubscriber\HeadersManagerResponseSubscriber
tags:
- { name: event_subscriber }
Then, we'll create the Subscriber using a path like headers_manager/src/EventSubscriber/HeadersManagerResponseSubscriber.php
.
In our new Subscriber class file:
<?php
namespace Drupal\headers_manager\EventSubscriber;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
/**
* Response subscriber to remove thes X-Generator header tag.
*/
class HeadersManagerResponseSubscriber implements EventSubscriberInterface {
/**
* Remove extra X-Generator header on successful responses.
*
* @param \Symfony\Component\HttpKernel\Event\FilterResponseEvent $event
* The event to process.
*/
public function HeadersManagerOptions(FilterResponseEvent $event) {
$response = $event->getResponse();
$response->headers->remove('X-Generator');
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
$events[KernelEvents::RESPONSE][] = ['HeadersManagerOptions', -10];
return $events;
}
}
So we'll capture events from the Kernel, and specifically we are asking for the event RESPONSE, assigning it in an array the name of the function that is responsible for interacting with the event, and a figure that represents the 'weight' as an order of priority of execution of our event alteration. Thus with a low weight, we ensure that our alteration is executed just after the attachment of X-Generator in the previous subscriber. Using a low value we avoid that our change is executed before the loading of the header.
Finally our module will have the internal structure:
headers_manager
\_headers_manager.info.yml
\_headers_manager.module
\_headers_manager.services.yml
\_src
\_EventSubscriber
\_HeadersManagerResponseSubscriber.php
And so with this custom module, after enabling it in our Drupal installation, it will process the pages delivered by the server from the hook and from the event subscriber to remove the information we have configured.
You can download the custom module here, from my Gitlab profile.
Read more about Events and Subscribers (Symfony, Drupal)
Here you can find much more information about the concepts previously exposed and consult a multitude of use cases and examples:
- DOC: Use of events in the Drupal Rules module.
- DOC: Subscribe to and dispatch events (Drupal Event Systems Overview).
- DOC Event Dispatcher examples in the Symfony documentation.
- DOC: The HttpKernel in Symfony.
- DOC: The KernelEvents class in Symfony.
- DOC: The EventSubscriberInterface from Symfony in Drupal.
Top comments (0)