NL EN UA Bespreek je project

Kennisbank · Websites

Website gehackt zonder dat je het merkt: wat een security-audit onthulde

Een website kan normaal werken en toch malware bevatten. Lees wat een technische audit controleert en wat herstel inhoudt. Vanaf €550 excl. btw.

Daniel OroszWeb developer & oprichter
Webdeveloper voert een security-audit uit op een website

Kort antwoord

Dit moet je weten

Een website kan normaal werken en toch malware bevatten. Lees wat een technische audit controleert en wat herstel inhoudt. Vanaf €550 excl. btw.

Gebruik de details hieronder om de juiste volgende stap te kiezen.

Kerngegevens
Onderwerpwebsite gehackt
RegioKerkrade · Zuid-Limburg · Nederland & België
ActueelGecontroleerd en bijgewerkt: 3 september 2026
Volgende stapEerst afbakenen, daarna een heldere prijsrichting

Een website kan snel laden, gebruikers laten inloggen en e-mails versturen, en toch gehackt zijn.

Dat ontdekte ik tijdens de overdracht van een bestaand PHP-project. Aan de buitenkant werkte het platform normaal. Diep in de opslag stonden web shells, vermomde PHP-bestanden en honderden sporen van een geautomatiseerde aanval. Ook een oude back-up was besmet.

Dit is precies waarom ik een onbekend project niet meteen lokaal start of op een nieuwe server zet. Eerst wil ik weten wat ik overneem: de broncode, serverinstellingen, accounts, afhankelijkheden, uploads, back-ups en beschikbare logs.

Heb je een waarschuwing van je hostingprovider of Google ontvangen, zie je vreemde redirects of vermoed je malware? OROS biedt een technische security-audit met herstel vanaf €550 excl. btw. Je kunt de eerste informatie gewoon via het contactformulier sturen. Een telefoongesprek is niet nodig om de beoordeling te starten.

Website gehackt: doe dit eerst

Begin niet willekeurig bestanden te verwijderen. Daarmee kun je bewijs wissen, een werkende functie breken of een besmette back-up aanzien voor een veilige herstelbron.

Leg eerst vast wat je ziet: waarschuwingen van Google of je hoster, onbekende pagina’s, redirects, vreemde beheerdersaccounts, gewijzigde bestanden en het tijdstip waarop het probleem begon. Bewaar beschikbare logs en maak een afzonderlijke kopie van de huidige situatie. Gebruik die kopie niet als schone back-up.

Beperk daarna de schade. Welke maatregel passend is, hangt af van het incident. Soms moet een uploadmap direct worden geblokkeerd. Bij phishing, betaalfraude of actieve verspreiding van malware kan het nodig zijn om delen van de site tijdelijk offline te halen. Verander toegangscodes gecontroleerd en in de juiste volgorde, zodat een aanvaller niet via een achtergebleven account opnieuw binnenkomt.

Een snelle antiviruscontrole is nuttig, maar geen bewijs dat een website schoon is. De case hieronder laat zien waarom.

De website leek gewoon te werken

De onderzochte omgeving bestond uit meerdere PHP-applicaties, een oudere versie die als back-up was blijven staan en meerdere jaren aan geüploade media. De openbare pagina’s werkten. Het inlogscherm ook. Er waren geen opvallend vervangen of beschadigde pagina’s.

In de publieke opslag vond ik bestanden met namen als cache.php, kleine index.php-loaders, aangepaste .htaccess-bestanden en PHP-code die als afbeelding of video was vermomd. Eén kwaadaardig bestand had een .bmp-extensie, maar bevatte PHP. Een ander bestand ontving versleutelde invoer via een webrequest, decodeerde die en liet de server het resultaat uitvoeren.

Zo’n bestand is een web shell. Daarmee kan een aanvaller PHP uitvoeren met de rechten van het websiteaccount. Dat kan toegang geven tot applicatiebestanden, geheime configuratiewaarden en databasegegevens. De aanvaller kan ook pagina’s aanpassen, nieuwe code uploaden of de server misbruiken voor spam en redirects.

Wat technisch mogelijk was, is niet automatisch bewezen gebeurd. De beschikbare gegevens bewezen niet dat persoonsgegevens waren geëxporteerd of advertenties waren geïnjecteerd. Ze bewezen wel dat de mogelijkheid bestond. Daarom moesten databasewachtwoorden en andere geheime toegangscodes als mogelijk blootgesteld worden behandeld.

Eén malwarescan miste de belangrijkste bestanden

De eerste antivirusscan gaf geen melding.

ClamAV vond de web shells niet in de gedownloade broncode en de geselecteerde onderzoeksbestanden. Handmatige controle en YARA-regels voor bekende patronen van web shells vonden ze wel. VirusTotal classificeerde de versleutelde cache.php-loader later bij 27 van 61 engines als kwaadaardig. Het bestand dat als bitmap was vermomd, werd door 12 van 60 engines gedetecteerd.

Dat verschil zegt twee dingen. De bestanden waren geen twijfelachtige applicatiecode: meerdere engines herkenden ze onafhankelijk als PHP-web shell, trojan of backdoor. Tegelijk is een bestand met 12 detecties niet veiliger dan een bestand met 27. Detectie hangt af van herkenningsregels, versluiering, het moment van scannen en het onderzochte bestand.

VirusTotal beschrijft zichzelf als een verzamelpunt voor resultaten van antivirusprogramma’s, URL-scanners, bestandsinformatie en signalen uit de securitycommunity. Ik gebruik het als één bron van bewijs, niet als een keurmerk. Ik upload daar nooit klantdatabases, configuratiebestanden met geheime gegevens, inloggegevens of privédocumenten. Ingestuurde bestanden kunnen volgens VirusTotal worden gedeeld met securitypartners en premiumklanten.

Bij een PHP-security-audit combineer ik daarom verschillende controles:

  • digitale vingerafdrukken, tijdstempels en andere bestandmetadata;
  • patroonanalyse die rekening houdt met PHP;
  • YARA-regels voor bekende typen web shells;
  • antiviruscontrole;
  • zoeken naar PHP-tags in bestanden met een andere extensie;
  • controle van .htaccess, .user.ini en PHP-configuratie;
  • inspectie van archieven zonder onbekende code uit te voeren;
  • Composer- en npm-audits;
  • handmatige beoordeling van de bevindingen met het hoogste risico.

Geen enkele scanner krijgt het laatste woord. Een gecomprimeerd JavaScript-bestand kan verdacht ogen en volkomen legitiem zijn. Een klein laadbestand kan onschuldig lijken en toch toegang geven tot veel meer kwaadaardige code. De context bepaalt wat een vondst betekent.

Het bestandssysteem liet een tijdlijn zien

De eerste web shells verschenen vóór een grotere aanvalsgolf. Later die dag werden honderden bestanden geschreven in de actieve applicatie en de bewaarde back-up. De meeste activiteit vond plaats binnen een kort tijdvenster. Terugkerende mapnamen, verschillende digitale vingerafdrukken, overeenkomende tijdstippen en identieke bundelstructuren wezen op automatische verspreiding.

De back-up was daardoor geen betrouwbare herstelbron. Hij bevatte een tweede kopie van de besmetting en had tijdens een latere noodsituatie de malware opnieuw kunnen introduceren.

De huidige applicatiecode en de bijgewerkte lijst met packageversies waren enkele dagen jonger dan de infectie. Dat past bij een nieuwe plaatsing of een gedeeltelijke schoonmaak, maar de resterende gegevens bewijzen niet precies wat er toen is gedaan. De schrijfbare opslagmap was hergebruikt. Nieuwe applicatiecode en oude web shells belandden zo in dezelfde websiteversie.

Nieuwe code plaatsen is geen volledig herstel. Zo’n update verwijdert geen bestanden buiten het pakket, vervangt gestolen wachtwoorden niet, controleert de database niet en sluit achtergebleven toegangsroutes niet uit.

Een kwetsbare versie is een aanwijzing, geen bewijs

De productieserver draaide PHP 8.3. Er was geen reden om een sterk verouderde PHP-versie of het hostingplatform als oorzaak aan te wijzen.

De versiegeschiedenis gaf wel een belangrijke aanwijzing. Het lock-bestand van vóór het incident bevatte Livewire 3.5.12. Volgens het officiële advies kunnen versies vóór 3.6.4 in bepaalde configuraties een aanvaller zonder inlog toegang geven tot het uitvoeren van opdrachten op de server. De kwetsbaarheid is als kritiek beoordeeld en heeft volgens de maintainer geen tijdelijke oplossing behalve upgraden (CVE-2025-54068).

Livewire was daardoor de sterkste hypothese voor de eerste toegang, maar geen bewezen oorzaak. De benodigde historische HTTP-logs waren niet meer beschikbaar. Gecompromitteerde hostinggegevens of een onveilige uploadroute bleven mogelijke alternatieven.

Dit onderscheid hoort in ieder betrouwbaar securityrapport. De zin “deze versie was kwetsbaar” kan een feit zijn. Voor de conclusie “de aanvaller gebruikte deze kwetsbaarheid” zijn requestlogs, exploitsporen of andere directe artefacten nodig.

Onderhoud stopt ook niet na één incident. De nieuwere applicatie gebruikte Filament 3.3.48. Een later Filament-advies beschreef unauthenticated tijdelijke uploads op authenticatiepagina’s en verhielp het probleem in de 3.x-tak in versie 3.3.52 (CVE-2026-48500). Deze latere kwetsbaarheid verklaarde de oorspronkelijke besmetting niet. Ze liet wel zien waarom één update geen onderhoudsstrategie is.

PHP heeft een openbare supportkalender. Frameworks en CMS’en hanteren hun eigen onderhoudsperioden. De onderzochte Kirby-installatie draaide 4.9.3. Kirby 4 zat al in de security-only-fase en de officiële lijst vermeldt meerdere problemen in 4.9.3 die in latere releases zijn opgelost. Kirby 5 was de actief ondersteunde generatie. Kirby publiceert release- en end-of-supportinformatie in het eigen securitybeleid.

Alleen PHP bijwerken is dus niet genoeg. Laravel, Livewire, Filament, Kirby, plugins, Composer-packages, JavaScript-packages en de serveromgeving hebben ieder hun eigen updates en risico’s.

Uploads werden uitvoerbare code

De applicatie bewaarde uploads onder een publiek gekoppelde opslagmap. De validatie van bestanden was ruim ingesteld. Geneste .htaccess-bestanden konden bovendien beïnvloeden hoe de webserver extensies behandelde. Een bestand dat eruitzag als een afbeelding kon daardoor als PHP worden uitgevoerd.

Om de eerste schade te beperken, werd toegang tot de publieke opslag geblokkeerd. Dat stopte de bekende shells, maar maakte ook legitieme documenten tijdelijk onbereikbaar. Zo’n brede blokkade kan bij een actief incident nodig zijn. Het is geen nette eindoplossing.

Een bestandsinventaris maakte gecontroleerd herstel mogelijk. Van de honderden bestanden die eerst apart waren gezet, bleek een groot deel uit legitieme foto’s, pdf’s en video’s met een geldige interne bestandsstructuur te bestaan. Die zijn pas na inhoudscontrole teruggezet. De verdachte en kwaadaardige set bevatte onder meer:

  • bestanden met uitvoerbare PHP-extensies;
  • veel geneste .htaccess-bestanden;
  • ongeldige bestanden die zich als media voordeden;
  • kleine ZIP-bundels uit het tijdvenster van de aanval.

De ZIP-bestanden volgden hetzelfde naamgevingspatroon en bevatten overeenkomende paren van tijdelijke schadelijke code. Het waren onderdelen van de malware, geen klantarchieven.

Historisch gebruik liet ook zien welke bestandsformaten het bedrijf werkelijk nodig had. Op basis daarvan kon een korte lijst met toegestane afbeeldingen, documenten en video’s worden gemaakt. Onbekende formaten, PHP, SVG, uitvoerbare extensies en ruwe ZIP-uploads bleven geblokkeerd.

De overgebleven media kwamen terug onder een static-only webserverhandler. Geneste serverconfiguratie werd uit de actieve map verwijderd, PHP-uitvoering werd geblokkeerd, uploaden vereiste authenticatie en er kwamen requestlimits. Een onschuldige test bevestigde dat een .php-bestand HTTP 403 kreeg en dat PHP-tekst met een .jpg-naam als gewone bytes werd verstuurd in plaats van uitgevoerd.

Dit was nog een tussenoplossing. Veiliger is opslag buiten de map die rechtstreeks via de website bereikbaar is. De applicatie controleert dan eerst de gebruiker en verstuurt daarna pas het bestand. De OWASP File Upload Cheat Sheet adviseert onder meer een zakelijke lijst van toegestane extensies, controle van inhoud en bestandsstructuur, gegenereerde bestandsnamen, limieten, geauthenticeerde uploads en waar mogelijk opslag buiten de publiek bereikbare webmap. De door de browser aangeleverde Content-Type is geen betrouwbaar bewijs van het bestandstype.

Wat controleert een website-security-audit?

Ik begin met een controle waarbij ik nog niets uitvoer of verander. Een installatiebestand, automatisch script of PHP-startbestand uitvoeren voordat de code is bekeken, kan schadelijke code op de computer van de onderzoeker activeren.

De precieze scope verschilt per website, maar een overdrachts- en security-audit controleert doorgaans:

  1. De hostingindeling, domeinen, publiek bereikbare mappen, PHP-versie, geplande taken, accounts, rechten en snelkoppelingen tussen mappen.
  2. Bestandsnamen, groottes, tijdstempels, eigenaarschap en digitale vingerafdrukken voordat er iets wordt verwijderd.
  3. De broncode in een geïsoleerde werkomgeving, los van productiegegevens en externe diensten.
  4. Uitvoerbare code op onverwachte locaties, vooral uploadmappen, tijdelijke mappen, oude websiteversies en back-ups.
  5. De werkelijke inhoud van bestanden. Een .jpg-extensie bewijst niet dat een bestand een afbeelding is.
  6. Serverconfiguratie die ongebruikelijke extensies uitvoerbaar kan maken.
  7. composer.lock en package-lock.json, aangevuld met controles van gebruikte softwarepakketten. composer audit controleert geïnstalleerde packages op bekende beveiligingsadviezen, verlaten packages en packages die als malware zijn gemarkeerd. npm audit rapporteert bekende problemen in de JavaScript-packages van het project.
  8. Verschillen tussen oude en huidige websiteversies. Versiewijzigingen, identieke bronbestanden en veel gelijke tijdstempels kunnen een gedeeltelijke schoonmaak of herstelactie zichtbaar maken.
  9. Een schone lokale testomgeving met nieuwe softwarepakketten en zonder productiegegevens.
  10. De beoogde productieconfiguratie voordat de publieke map, PHP-versie of plaatsingswijze wordt aangepast.

Een webserver hoort alleen de bedoelde publieke map aan te bieden. De installatiedocumentatie van Laravel waarschuwt dat het bereikbaar maken van de volledige applicatiemap gevoelige configuratie kan blootleggen. Verzoeken aan de website horen naar public/index.php te gaan (Laravel deployment documentation). Back-ups, .git, logs, broncode, configuratiebestanden en mappen met softwarepakketten horen niet rechtstreeks via de website bereikbaar te zijn.

Onderzoek, schade beperken en herstel zijn verschillende stappen

Een security-audit stelt vast wat er aantoonbaar aanwezig is, welke risico’s direct aandacht vragen en welk vervolgwerk nodig is. Daarna kan de klant gericht kiezen.

FaseDoelResultaat
Security-auditDe technische toestand en mogelijke besmetting vaststellenBevindingen, urgenties, bewijs versus hypotheses en een hersteladvies
Schade beperkenBekende aanvalsroutes en actieve schade stoppenVerdachte bestanden geïsoleerd, uitvoerbare uploads geblokkeerd en belangrijke functies gecontroleerd
HerstelEen controleerbare schone omgeving opbouwenBeoordeelde broncode, nieuwe softwarepakketten, geschoonde uploads, gecontroleerde accounts en vervangen toegangscodes
OnderhoudVoorkomen dat hetzelfde risico stil terugkomtUpdateproces, logging, herstelbare back-ups, toegangsbeheer en periodieke controle

Het beperken van de schade betekent niet dat een website volledig schoon is verklaard. De correcte formulering is specifieker: bekende uitvoeringsroutes zijn geblokkeerd, noodzakelijke functies zijn getest en resterende onzekerheden zijn vastgelegd.

Volledig herstel gaat verder. Het begint met beoordeelde broncode en nieuw geïnstalleerde softwarepakketten. Daarna worden de te behouden uploads, relevante databasegegevens en beschikbare logs gecontroleerd. Toegangscodes worden in de juiste volgorde vervangen, bestaande sessies vervallen en toegangsrechten worden getest. Monitoring controleert daarna op nieuwe bestanden, gewijzigde digitale vingerafdrukken en terugkerende verdachte requests.

Wat kost het herstellen van een gehackte website?

Bij OROS begint een technische security-audit met malwareherstel vanaf €550 excl. btw. Na een eerste beoordeling bevestig ik de scope en de prijs voordat het herstel begint.

De omvang hangt onder meer af van de gebruikte technologie, het aantal applicaties en domeinen, de hoeveelheid uploads, beschikbare toegangen en logs, de staat van back-ups en de vraag of ook databaseonderzoek of een schone herbouw nodig is. Een enkele besmette website met bruikbare toegang is ander werk dan meerdere gekoppelde applicaties met een onbekende geschiedenis.

De startprijs is daarom geen belofte dat ieder incident voor €550 kan worden opgelost. Je krijgt eerst duidelijkheid over wat er onderzocht wordt, wat aantoonbaar is gevonden en welk deel onder audit, schadebeperking of herstel valt.

Onderhoud na een infectie

Een PHP-project heeft na de oplevering een duidelijke technisch verantwoordelijke en een onderhoudsbudget nodig. Zonder beide stapelen risico’s in gebruikte softwarepakketten zich op totdat een klant of een nieuwe ontwikkelaar ermee wordt geconfronteerd.

Mijn basis voor doorlopend PHP-onderhoud bestaat uit geautomatiseerde Composer- en npm-controles, een maandelijkse beoordeling van softwarepakketten, geteste updates, bijgehouden supportdata en een inventaris van hosting- en plaatsingstoegang. Back-ups staan buiten de publieke webmap en worden tijdens tests ook werkelijk teruggezet. Uploadregels volgen het zakelijke gebruik. Logs en controle op onverwachte bestandswijzigingen hebben een afgesproken bewaartermijn. De testomgeving gebruikt dezelfde beoogde PHP-versie als productie.

Automatische auditrapporten zijn invoer voor onderhoud, geen automatische reparatie. Een onbeperkte Composer-update of npm audit fix --force kan onderdelen van de website breken. Updates horen in een afgescheiden werkversie, met tests en een plan om terug te kunnen naar de vorige toestand.

De audit beschermt de klant en de nieuwe ontwikkelaar

Een ontwikkelaar kan geen verantwoordelijkheid nemen voor code die nog niet is onderzocht. De klant moet tegelijk weten of hij betaalt voor regulier onderhoud, het beperken van acute schade of herstel van een bestaand incident.

De acceptatie-audit legt die grens vast. Hij registreert wat er aanwezig was voordat de nieuwe ontwikkelaar iets veranderde, benoemt urgente risico’s en scheidt bewezen bevindingen van hypotheses.

In deze case verborg een normaal ogende website een werkend commandokanaal, honderden bestanden die blijvende toegang mogelijk maakten, een besmette back-up en een versiegeschiedenis die een deel van de tijdlijn verklaarde. Een gewone projectoverdracht had dit allemaal meegenomen.

Daarom is mijn eerste deliverable bij een onbekend PHP-project soms geen nieuwe functie. Eerst moet één vraag beantwoord worden: is deze website veilig genoeg om eraan te werken?

Veelgestelde vragen

Hoe weet ik of mijn website gehackt is?

Mogelijke signalen zijn vreemde redirects, onbekende pagina’s in Google, waarschuwingen van je hostingprovider, nieuwe beheerdersaccounts, gewijzigde bestanden, spam vanuit je domein of een plotselinge blokkade door de browser. Een website kan ook besmet zijn zonder zichtbaar symptoom. Dan is technische inspectie nodig.

Wat moet ik als eerste doen bij malware op mijn website?

Bewaar waarschuwingen, logs en een kopie van de huidige toestand voordat je bestanden verwijdert. Beperk actieve schade en laat vervolgens vaststellen waar de malware staat, hoe code uitvoerbaar werd en welke toegangen mogelijk zijn blootgesteld. Zet niet automatisch een oude back-up terug zolang niet bekend is of die schoon is.

Kun je malware verwijderen zonder de website opnieuw te bouwen?

Soms wel. Dat hangt af van de kwaliteit van de broncode, de omvang van de besmetting en de betrouwbaarheid van uploads en back-ups. Bij ernstige of slecht afgebakende schade kan een volledig schone nieuwe plaatsing of gedeeltelijke herbouw veiliger en uiteindelijk goedkoper zijn.

Wat kost het herstellen van een gehackte website?

Een security-audit met malwareherstel begint bij OROS vanaf €550 excl. btw. De definitieve prijs volgt na beoordeling van de technologie, toegangen, omvang van de besmetting, beschikbare logs en gewenste herstelwerkzaamheden.

Is een schone virusscan bewijs dat mijn website veilig is?

Nee. In de beschreven case miste ClamAV bestanden die bij handmatige analyse en aanvullende scans wel als schadelijke toegangspunten werden herkend. Een scan is één controle binnen een bredere technische beoordeling.

Kun je ook een bestaande PHP- of Laravel-website overnemen?

Ja, als de technische toestand en verantwoordelijkheden eerst duidelijk worden. Bij een onbekende of lang niet onderhouden applicatie begin ik met een overdrachts- en security-audit. Daarna kan ik aangeven of regulier onderhoud mogelijk is of dat eerst herstelwerk nodig is.

Website laten onderzoeken

Vermoed je malware, heeft je hoster de website geblokkeerd of wil je weten of een bestaand PHP-project veilig kan worden overgenomen? Stuur via het contactformulier de URL, de gebruikte techniek als je die kent, wat je hebt gezien en welke toegang beschikbaar is.

Ik beoordeel de eerste informatie en reageer schriftelijk met wat ik nodig heb voor de volgende stap. De security-audit met malwareherstel begint vanaf €550 excl. btw. Bij actieve betaalfraude, een vermoedelijk datalek of een incident dat buiten mijn werkgebied valt, zeg ik dat direct zodat je geen tijd verliest.


Dit artikel is gebaseerd op een geanonimiseerde projectoverdracht. Namen, hostnames, paden, inloggegevens en persoonsgegevens zijn verwijderd. Detectieratio’s en ondersteunde versies zijn momentopnames en moeten voor publicatie opnieuw worden gecontroleerd.

De auteur

Daniel Orosz

Daniel Orosz

Web developer & oprichter

Daniel bouwt websites en digitale systemen vanuit Kerkrade. Hij werkt al meer dan 16 jaar met webtechniek en vertaalt complexe keuzes naar gewone taal.

Meer over Daniel →

Passende volgende stap

Bespreek je situatie

Stuur kort je vraag, huidige website of doel. Daniel bekijkt welke route past, wat binnen één week realistisch is en welke prijsrichting daarbij hoort.

Vraag een eerste beoordeling aan →