Voordat een bot een kwetsbaarheid probeert, moet hij weten met wat voor site hij te maken heeft. Vaak is één pagina van je site genoeg om "WordPress" te concluderen, en daarna een paar verzoeken om een lijst van je plugins en hun versies op te stellen. Dit artikel beschrijft de precieze signalen die Wappalyzer en WPScan gebruiken, wat je netjes kunt weghalen en wat zichtbaar blijft, wat je ook doet.
Korte definitie: Fingerprinting. Kant-en-klare oplossing: WordPress vermommen als ander CMS met WP Masquerade.
Waarom identificatie aan de aanval voorafgaat
Geautomatiseerde aanvallen op WordPress zijn zelden op "jouw" site gericht. Ze richten zich op een specifieke pluginversie waarvan bekend is dat ze kwetsbaar is, op duizenden sites tegelijk. Om die sites te sorteren, beantwoordt een bot drie vragen in deze volgorde: is het WordPress? welke core-versie? welke plugins, en in welke versie?
WPScan illustreert deze logica goed. Als hij in agressieve modus naar plugins zoekt, test hij standaard niet alle bestaande plugins: hij probeert de lijst met plugins in zijn databank die bekend staan om een kwetsbaarheid. Een site die op deze vragen niets bruikbaars terugzegt, valt sneller uit de wachtrij; een site die alles aankondigt, belandt in het juiste mandje.
Passieve signalen: wat de homepage verraadt
Een "passieve" tool doet geen bijzondere verzoeken: hij leest de HTML, de headers en het JavaScript van de pagina die elke bezoeker ontvangt. Dat geldt voor de browserextensie Wappalyzer.
De generator-tag
De core koppelt standaard de functie wp_generator aan de hook wp_head. Die toont <meta name="generator" content="WordPress 6.9" /> met het exacte versienummer. Dezelfde informatie staat in de feeds: <generator> in RSS 2, het attribuut version in Atom. Haal je de tag uit de <head> zonder de feeds aan te pakken, dan blijft de versie dus te zien op /feed/.
De paden /wp-content/ en /wp-includes/
Stylesheets, scripts, afbeeldingen: bijna alle bronnen van een WordPress-site lopen via /wp-content/ (thema's, plugins, media) of /wp-includes/ (core-bibliotheken). Dit is het meest robuuste signaal, en het levert er de namen van de plugins bij: /wp-content/plugins/plugin-naam/ staat leesbaar in de broncode.
De parameter ver=
Scripts en stijlen van de core worden geregistreerd met een standaardversie die gelijk is aan de WordPress-versie (default_version = get_bloginfo( 'version' ) in script-loader.php). Niet allemaal gebruiken ze die (jQuery heeft een eigen nummer), maar een script dat zonder versie is geregistreerd, zoals wp-includes/js/comment-reply.min.js, wordt geserveerd met ?ver= gevolgd door de core-versie, ook als de generator-tag is verdwenen. Plugins geven in diezelfde parameter vaak hun eigen versienummer mee.
De HTTP-headers
Link: <https://voorbeeld.nl/wp-json/>; rel="https://api.w.org/": verstuurd doorrest_output_link_header()op openbare pagina's om de REST API aan te kondigen. Wappalyzer herkent hem direct.X-Pingback: sinds WordPress 4.4 wordt deze header alleen verstuurd op een afzonderlijk item (bericht, pagina) dat pings accepteert, en verwijst hij naarxmlrpc.php.- Korte links:
wp_shortlink_header()voegt op content eenLinkvan het typeshortlinktoe.
JavaScript en CSS-klassen
De blokeditor laat wp-block-...-klassen achter in de gepubliceerde content. Aan de JavaScript-kant zijn objecten als wp.ajax, een variabele wp_username of het script wp-embed.min.js genoeg voor Wappalyzer. WooCommerce voegt zijn eigen markers toe (woocommerce_params, wc_add_to_cart_params).

| Signaal | Waar te zien | Geeft de versie? | Gelezen door |
|---|---|---|---|
| Generator-tag | <head> van elke pagina | Ja, exact | Wappalyzer, WPScan |
| Generator in feeds | /feed/, /feed/atom/ | Ja, exact | WPScan |
| Paden wp-content, wp-includes | Broncode | Nee (wel pluginnamen) | Wappalyzer, WPScan |
Parameter ver= | Adressen van scripts en stijlen | Vaak | WPScan |
| Link-header api.w.org | HTTP-antwoord | Nee | Wappalyzer |
| X-Pingback | HTTP-antwoord (berichten) | Nee | Wappalyzer |
| JavaScript-variabelen | Scripts van de pagina | Nee | Wappalyzer |
readme.txt van plugins | Apart verzoek | Ja (Stable tag) | WPScan |
| MD5-vingerafdrukken | Verzoeken naar statische bestanden | Ja | WPScan |
Hoe Wappalyzer beslist
Wappalyzer vergelijkt de pagina met een databank van definities: per technologie een lijst reguliere expressies om te zoeken in de HTML, de meta-tags, de headers, de cookies, de scriptadressen en de JavaScript-variabelen. De oorspronkelijke repository werd in augustus 2023 privé; de databank wordt verder ontwikkeld in open projecten zoals webappanalyzer (Enthec), dat hetzelfde formaat aanhoudt.
De definitie "WordPress" in deze databank is kort en leerzaam:
meta generator:^WordPress(?: ([\d.]+))?, waarbij het versienummer wordt vastgelegd;headers:X-Pingbackeindigend op/xmlrpc.php, enlinkmetrel="https://api.w.org/";scriptSrcenhtml: paden/wp-content/of/wp-includes/,wp-embed.min.js;js:wp.ajax,wp.receiveEmbedMessage,wp_username;implies: PHP en MySQL. De WooCommerce-definitie vereist op haar beurt WordPress (requires).
Praktisch gevolg: één signaal is genoeg. De generator-tag weghalen verandert niets aan het oordeel zolang de paden /wp-content/ in de pagina staan. Omgekeerd wordt een site die de markers van andere software toont, via hetzelfde mechanisme in die andere categorie ingedeeld.
Hoe WPScan verder gaat
WPScan is een beveiligingsscanner speciaal voor WordPress, die zowel door auditors als door aanvallers wordt gebruikt. De broncode is openbaar, zodat je precies kunt nagaan waar hij naar zoekt:
- Detectie van WordPress: de homepage en een 404-pagina worden onderzocht (paden, generator, HTML-commentaar waarin WordPress wordt genoemd,
admin-ajax.phpin een inline script). In gemengde of agressieve modus laadt hij ookwp-login.phpenwp-admin/install.php. - Core-versie: generators in de RSS-, Atom- en RDF-feeds,
readme.html(weinig betrouwbaar voor recente versies), daarna vingerafdrukken: hij vergelijkt de MD5 van statische bestanden met een databank van bekende checksums, met een betrouwbaarheid van 100%. - Plugins: adressen op de homepage en de 404-pagina, patronen in headers, commentaar en JavaScript-variabelen, daarna verzoeken naar
/wp-content/plugins/slug/. Een antwoord 200, 401, 403 of 500 geldt als aanwezig. - Pluginversie: lezen van
readme.txt, veldStable tag(betrouwbaarheid 80) of de changelogsectie (betrouwbaarheid 50).

De actieve stappen laten sporen na: tientallen verzoeken naar /wp-content/plugins/.../readme.txt met een 404 binnen enkele seconden wijzen op een opsomming. Daar kan een verdediging ook ingrijpen, door geen 200 of 403 terug te geven op bestanden die niet openbaar hoeven te zijn.
Wat je kunt beperken, en wat zichtbaar blijft
Met WordPress kun je verschillende aankondigingen weghalen met eenvoudige hooks, bijvoorbeeld in een eigen plugin:
remove_action( 'wp_head', 'wp_generator' );
add_filter( 'the_generator', '__return_empty_string' ); // inclusief feeds
remove_action( 'wp_head', 'rsd_link' );
remove_action( 'wp_head', 'wp_shortlink_wp_head', 10 );
remove_action( 'template_redirect', 'wp_shortlink_header', 11 );
remove_action( 'wp_head', 'rest_output_link_wp_head', 10 );
remove_action( 'template_redirect', 'rest_output_link_header', 11 );
Let op de prioriteit: remove_action() werkt alleen als je dezelfde prioriteit opgeeft als bij het toevoegen (11 voor de twee headers). Naar wlwmanifest_link hoef je daarentegen niet te zoeken: deze Windows Live Writer-link wordt sinds WordPress 6.3 niet meer door de core uitgegeven.
| Signaal | Verdediging | Effect | Beperking |
|---|---|---|---|
| Generator | Filter the_generator | Versie verwijderd uit pagina's en feeds | Thema's en plugins die hun eigen generator schrijven |
| Link api.w.org | De twee REST-hooks verwijderen | Aankondiging van de API verdwenen | De API blijft bereikbaar op /wp-json/ |
ver= | Parameter herschrijven of verwijderen | Core-versie minder zichtbaar | Kan het verversen van de browsercache hinderen |
| Paden wp-content | Adresaliassen + serverregels | Geen /wp-content/ meer in de HTML | Lastig: CSS, JS en JSON bevatten ook paden |
readme.txt van plugins | Blokkeren op de server (404) | Pluginversie moeilijker te lezen | Vingerafdrukken van statische bestanden blijven mogelijk |
| MD5-vingerafdrukken | Geen eenvoudige verdediging | Alleen bijwerken neemt de kwetsbaarheid weg |
Houd de rangorde in gedachten: de versie verbergen verhelpt geen enkele kwetsbaarheid. Een bot die je site niet kan identificeren, kan de exploit nog steeds blind proberen, en sommige doen dat ook. Verbergen vermindert de ruis en haalt je site uit gesorteerde doelwitlijsten; updates, back-ups en sterke authenticatie blijven de basis.
WordPress verbergen of andere software nabootsen?
Signalen weghalen laat een site "zonder identiteit" achter, en dat is op zich al een aanwijzing. De andere aanpak is de markers van andere software te tonen. Dat is het principe van CMS-imitatie van WP Masquerade:
| Functie | Gratis | Pro |
|---|---|---|
| WordPress-generator verwijderd uit pagina's en feeds | Ja | Ja |
| Echte generator-tag van andere software | 5 profielen (Joomla!, Drupal, PrestaShop, TYPO3, MediaWiki) | 41 profielen |
| Markers die Wappalyzer herkent (headers, JavaScript-variabelen) | Nee | Ja |
| RSD-, Windows Live Writer- en korte links verwijderd | Ja | Ja |
| Aankondigingen van de REST API en oEmbed verwijderd | Nee | Ja |
| Aliassen voor wp-content, media, wp-includes, plugins, thema's | Nee | Ja |
| Readme- en vertaalbestanden van de plugin op 404 (Apache, LiteSpeed) | Ja | Ja |
De beperkingen zijn gedocumenteerd: de mapnamen van plugins en thema's blijven onder hun hoofdmap aanwezig, CSS- en JavaScript-bestanden worden niet volledig herschreven, en er is geen enkel gegarandeerd resultaat in een detector. Zie ook de technische links en de bestandsadressen. Een overzicht van wat de WordPress-beveiligingsplugin WP Masquerade verder doet, vind je op onze homepage.
Je eigen site testen in tien minuten
- Open een privévenster (uitgelogd) en bekijk de broncode: zoek naar
generator,wp-content,wp-includes,ver=. - Open
/feed/en zoek naar de tag<generator>. - Lees de headers met
curl -sI https://jouw-site.nl/: staat er eenLinknaarapi.w.org? - Start de Wappalyzer-extensie op de homepage en daarna op een bericht.
- Probeer
/wp-content/plugins/een-plugin/readme.txt: een 200 geeft de versie aan iedereen. - Leeg na elke instelling de paginacache: een oude kopie kan de oude signalen bewaren.
- Gebruik je WPScan, doe dat dan alleen op een site waarvoor je verantwoordelijk bent.
Om te onthouden
- Eén signaal is genoeg voor Wappalyzer: de generator-tag weghalen volstaat niet zolang /wp-content/ zichtbaar blijft.
- De core-versie lekt ook via de feeds, de parameter ver= en de vingerafdrukken van bestanden.
- WPScan leest de Stable tag in de readme.txt van plugins: blokkeer die bestanden als ze 200 teruggeven.
- remove_action() vereist dezelfde prioriteit als bij het toevoegen (11 voor de Link-headers).
- Verbergen beperkt geautomatiseerde targeting, maar alleen updates nemen een kwetsbaarheid weg.
Bronnen
- webappanalyzer: technologiedefinities (w.json, vermelding WordPress) (opent in een nieuw tabblad)
- webappanalyzer: README (voortzetting van Wappalyzer, privé sinds augustus 2023) (opent in een nieuw tabblad)
- WordPress Developer: get_the_generator() (opent in een nieuw tabblad)
- WordPress Developer: rest_output_link_header() (opent in een nieuw tabblad)
Andere geraadpleegde bronnen: officiële documentatie en officiële pagina's van de leveranciers.


