Artikler

DDoS-angreb: hvad det er, og hvad en webshop kan gøre for at holde åben

Et DDoS-angreb lægger et site ned ved at overbelaste det med trafik. Ifølge Styrelsen for Samfundssikkerhed er det meget sandsynligt, at danske organisationer bliver mål, og angrebene er blevet en fast del af trusselsbilledet. Her er, hvad et DDoS-angreb er og ikke er, hvad der er sket mod danske sites, og hvilken DDoS-beskyttelse en webshop kan sætte op på forhånd. Til teknikeren er der Cloudflare-regler, nginx-konfiguration og kommandoer til at se et angreb i loggen.

Hassan Aziz
Partner & Projektleder, Bullmade

Sikkerhed14. oktober 202621 min læsning

DDoS-angreb: hvad det er, og hvad en webshop kan gøre for at holde åben

Hvad et DDoS-angreb er

DDoS står for Distributed Denial of Service og er et overbelastningsangreb. Angriberen styrer et stort antal kompromitterede enheder, fx servere, routere og kameraer, der er overtaget i forvejen, og bruger dem til at sende så meget trafik mod en hjemmeside eller et netværk, at det ikke kan følge med. Mens angrebet står på, kan almindelige besøgende ikke komme ind.

Styrelsen for Samfundssikkerhed (SAMSIK), der har overtaget opgaverne fra Center for Cybersikkerhed, beskriver det sådan i trusselsvurderingen Cybertruslen mod Danmark 2025:

> Hackere udnytter kompromitterede enheder til at generere usædvanligt store mængder datatrafik mod en hjemmeside (webserver) eller et netværk, så hjemmesiden eller netværket overbelastes. — Styrelsen for Samfundssikkerhed, Cybertruslen mod Danmark 2025

Teknikere deler angrebene op efter, hvilket lag i netværksmodellen (OSI) de rammer. Det er ikke akademisk. Laget afgør, hvem der kan stoppe angrebet, og hvad I selv kan gøre:

TypeLagHvad der rammesMåles iHvem kan stoppe det
Volumenangreb3 og 4Internetforbindelsen til serverenBit pr. sekundKun et netværk, der er større end angrebet
Protokolangreb3 og 4Firewalls, load balancere og serverens forbindelsestabelPakker pr. sekundNetværksfilter hos CDN eller hosting
Applikationsangreb7Selve webshoppenForespørgsler pr. sekundCDN-regler, WAF, rate limiting og cache, som I selv styrer

Et volumenangreb fylder linjen. En udbredt metode er forstærkning (amplification), hvor angriberen sender små forespørgsler til åbne tjenester på internettet, fx DNS-servere, med jeres IP-adresse som falsk afsender. Svarene er langt større end forespørgslerne og sendes alle til jer. Når linjen er fuld, hjælper det ikke, hvor hurtig serveren er, for trafikken når aldrig frem. Det kan kun et netværk, der er større end angrebet, absorbere.

Et protokolangreb udnytter, hvordan forbindelser oprettes. Ved et SYN-flood sender angriberen tusindvis af anmodninger om at åbne en TCP-forbindelse uden at gøre forbindelsen færdig. Serveren holder plads til hver halvåbne forbindelse, indtil tabellen er fuld, og så kan rigtige kunder ikke forbinde. Cloudflare nævner UDP-floods, SYN-floods, SYN-ACK-refleksion og DNS-floods som eksempler på angreb, deres netværksfilter på lag 3 og 4 tager sig af.

Et applikationsangreb på lag 7 ligner almindelig trafik. Hver forespørgsel er en gyldig HTTP-anmodning, der åbner en side, søger eller lægger noget i kurven. Det er derfor, de er svære at filtrere. For en webshop er det denne type, der gør mest ondt. Det kræver ikke ret meget trafik at lægge en tung side ned, hvis hver forespørgsel får serveren til at køre PHP og slå op i databasen.

Hvad DDoS ikke er

Et DDoS-angreb er ikke et indbrud. Angriberen kommer ikke ind på serveren, stjæler ikke kundedata og ændrer ikke i shoppen. SAMSIK skriver, at angrebet ikke er ødelæggende for de ramte systemer, og at det oftest kan udbedres inden for kort tid og uden større konsekvenser. Da den danske forsvarsvirksomhed Terma blev ramt i november 2025, oplyste den, at der ikke var sikkerhedsbrud, og at ingen data gik tabt.

Det betyder ikke, at det er ufarligt. Et angreb midt i en kampagne koster salg, og der er tre forbehold, I skal kende:

  • Afledning: SAMSIK skriver, at DDoS kan bruges til at aflede opmærksomheden, mens angriberne forsøger at stjæle data et andet sted i systemerne. Når I er ramt af DDoS, er det derfor værd at holde øje med login-forsøg og ændringer på serveren.
  • Afpresning: Kriminelle grupper bruger ifølge SAMSIK til tider DDoS til at lægge ekstra pres på et offer for ransomware.
  • Længere nedetid: De fleste angreb varer kort, men SAMSIK nævner eksempler på mere koordinerede angreb med væsentligt længere nedetid. Nordea afværgede ifølge rapporten 90 procent af angrebene i efteråret 2024, men kundernes adgang til netbank var alligevel periodisk påvirket i 25 dage.

Og det er ikke alt, der ligner DDoS, der er DDoS. En shop, der går ned, fordi et nyhedsbrev sender mange kunder ind på én gang, eller fordi en søgemaskine-robot eller en AI-crawler henter tusindvis af filterkombinationer, oplever det samme for kunderne. Forskellen ses i loggen: En kampagne giver mange forskellige IP-adresser, der går den normale vej fra forside til produkt til kurv. En crawler giver få IP-adresser og en ærlig user agent. Et angreb rammer typisk de samme få dyre stier igen og igen. Tiltagene nedenfor hjælper i alle tre tilfælde.

Hvem der angriber danske sites

Det er ikke en antagelse, at danske sites bliver ramt. SAMSIK vurderer truslen fra cyberaktivisme som HØJ og skriver, at det er meget sandsynligt, at danske organisationer vil blive mål for DDoS-angreb. Ifølge rapporten er DDoS-angreb mod danske hjemmesider 'en del af normalbilledet'.

Det er især pro-russiske hackergrupper, der står bag, og SAMSIK vurderer, at nogle af dem sandsynligvis har forbindelse til den russiske stat. Grupperne går typisk efter myndigheder og virksomheder i kritisk infrastruktur, især finans og transport, men også energi og tele. SAMSIK skriver samtidig, at angrebene også rammer bredere og mere tilfældigt, og at enhver organisation med en hjemmeside derfor er et potentielt mål.

Grupperne beskriver typisk angrebene som en straf mod Danmark som land og bruger gerne et valg eller en politisk udmelding som anledning. SAMSIK skriver også, at grupperne overdriver for at få omtale, så ikke alle påståede angreb har haft en effekt.

DDoS er samtidig nemt at købe. Rapporten nævner DDoS-for-hire og botnets-for-hire som tjenester, der gør angrebene tilgængelige for flere. Derfor er det heller ikke kun politisk motiverede grupper, der kan stå bag. En utilfreds kunde eller en konkurrent kan i princippet leje et angreb.

Angreb mod Danmark det seneste år

Der er flere dokumenterede bølger af DDoS-angreb mod danske sites det seneste halvandet år:

HvornårHvad skete derKilde
Efteråret 2024Kraftige DDoS-angreb mod finanssektoren. Nordeas netbank var periodisk påvirket i 25 dageSAMSIK, Cybertruslen mod Danmark 2025
Marts 2025En gruppe, der angiveligt støtter Hamas, angreb danske myndigheders hjemmesiderSAMSIK, Cybertruslen mod Danmark 2025
12.-13. november 2025Flere kommuner, bl.a. Gentofte, Rødovre, Ishøj og Tårnby, og senere Transportministeriet, borger.dk og Terma blev ramt. Gruppen NoName057(16) tog ansvaretThe Local Denmark og The Record
17. november 2025Dagen før kommunal- og regionsrådsvalget var hjemmesider for flere partier kortvarigt nede. Valget blev ikke påvirketThe Record og SAMSIK

Gruppen bag angrebene i november 2025 fik ifølge The Record beslaglagt over 100 servere ved en international politiaktion i juli 2025, men fortsatte med at udpege nye mål. Det siger noget om, hvorfor DDoS ikke forsvinder: det er billigt at starte forfra.

I september 2026 hævede SAMSIK trusselsniveauet for destruktive cyberangreb fra middel til høj. Det handler om angreb, der sletter data eller ødelægger styringssystemer, ikke om DDoS. Men det viser, at trusselsbilledet mod Danmark er skærpet, og at det er værd at have sit beredskab i orden.

Hvorfor en webshop er sårbar

En webshop er mere udsat end en almindelig hjemmeside, fordi de vigtigste sider ikke kan caches. Forsiden og kategorisiderne kan lægges i et cache-lag og serveres uden at belaste serveren. Søgning, kurv, login, checkout og filtre i kategorier skal derimod beregnes for hver enkelt besøgende, og det er netop dem, et angreb på lag 7 går efter.

Regnestykket er skævt. En forespørgsel, der kommer fra cache, koster næsten ingenting. En forespørgsel, der rammer serveren, starter en PHP-proces, kører måske flere databaseforespørgsler og holder en arbejdsproces optaget, indtil siden er færdig. En server med plads til et par dusin samtidige PHP-processer er fyldt op, så snart et par dusin tunge forespørgsler venter på databasen. Resten står i kø, og kunderne ser en side, der aldrig bliver færdig, eller fejlen 502 eller 504.

I kan selv se forskellen. Den her kommando måler, hvor lang tid der går, før serveren sender den første byte, for en almindelig side og for en søgning. I WooCommerce er søgning en parameter, ?s=, på forsiden:

for url in 'https://www.eksempel.dk/' 'https://www.eksempel.dk/?s=test&post_type=product'; do
  curl -s -o /dev/null -w "%{http_code}  %{time_starttransfer}s  $url\n" "$url"
done

time_starttransfer er tiden fra forespørgslen starter, til den første byte kommer tilbage, og den omfatter den tid, serveren bruger på at beregne siden. Er forsiden 0,1 sekund og søgningen 1,5 sekund, så er søgningen 15 gange dyrere at ramme, og det er den, et angreb vil gå efter.

Ligger shoppen bag Cloudflare, viser headeren cf-cache-status, om svaret kom fra cache:

curl -sI https://www.eksempel.dk/ | grep -i cf-cache-status
VærdiBetydning
HITSvaret kom fra Cloudflares cache. Serveren blev ikke ramt
MISSSvaret kunne caches, men lå der ikke, så serveren blev ramt
EXPIREDKopien i cache var for gammel, så serveren blev ramt
BYPASSSvaret måtte ikke caches, fx fordi serveren sendte en cookie
DYNAMICForespørgslen blev slet ikke betragtet som cachebar og gik direkte til serveren

Står der DYNAMIC på forsiden og kategorisiderne, går hver eneste visning til serveren. Cloudflare cacher som standard ikke HTML, og svar med en Set-Cookie-header eller Cache-Control: private eller no-store bliver heller ikke cachet.

Typiske svage punkter:

  • Søgefeltet, hvor hver søgning er et databaseopslag, og hvor tilfældige søgeord aldrig ligger i cache.
  • Filtre og sortering, der skaber uendeligt mange URL'er, som ikke ligger i cache.
  • Kurv og checkout, der skal kunne skrive i databasen.
  • Login og glemt adgangskode, som også er mål for forsøg på at gætte adgangskoder.
  • API'er og endpoints som xmlrpc.php i WordPress, der kan modtage mange kald i én forespørgsel.
  • Delt hosting, hvor jeres shop deler server med andre. Et angreb mod en nabo kan ramme jer, og hostingudbyderen kan vælge at lukke for jeres site for at beskytte de andre.

En mindre server kan blive lagt ned af overraskende lidt trafik, hvis den rammer de tunge sider. Det er derfor, rate limiting og cache betyder mere for en webshop end ren båndbredde.

DDoS-beskyttelse lag for lag

God DDoS-beskyttelse består af flere lag. Ingen af dem løser det hele alene.

LagHvad det gørHvem leverer det
CDN og DDoS-filterOpsuger trafikken i et stort netværk, før den når serverenFx Cloudflare. Hostingudbydere har ofte deres egen
WAF (web application firewall)Blokerer kendte angrebsmønstre og mistænkelig trafikCDN-udbyderen eller hostingen
Rate limitingBegrænser, hvor mange forespørgsler én IP-adresse må sende til fx søgning og loginCDN, WAF eller webserveren
Skjult og låst server-IPSørger for, at angriberen ikke kan gå uden om filteretJer eller jeres udvikler
CacheServerer de sider, der kan caches, uden at ramme databasenCDN, hosting og shopsystemet
Aftale med hostingAfklarer, hvad der sker, når I bliver ramtHostingudbyderen

Cloudflare skriver i sin dokumentation, at DDoS-beskyttelsen er ubegrænset og gælder for alle kunder på alle planer. Den dækker lag 3, 4 og 7 og består af to sæt regler, som Cloudflare selv vedligeholder: HTTP DDoS Attack Protection til lag 7 og Network-layer DDoS Attack Protection til lag 3 og 4. Der findes andre udbydere, og mange hostingudbydere har filtre på netværksniveau. Det vigtige er, at trafikken bliver filtreret, før den når jeres server.

Når trafikken går gennem Cloudflares proxy, ender forbindelserne hos Cloudflare. Et SYN-flood eller et volumenangreb mod jeres domæne rammer derfor Cloudflares netværk og ikke jeres linje. Det holder kun, så længe angriberen ikke kender serverens rigtige IP-adresse.

Det lag, der oftest bliver glemt, er netop den skjulte server-IP. Hvis en angriber kender serverens rigtige IP-adresse, kan angrebet sendes direkte mod den, uden om CDN'et. Cloudflare nævner selv to typiske lækager: gamle DNS-poster, der stadig kan findes i historiske opslag, og mailopsætningen, hvis mails sendes fra samme server som shoppen. Mails, som shoppen sender, har serverens IP-adresse i headeren Received, så hver ordrebekræftelse kan afsløre den. Cloudflare anbefaler at blokere al trafik til serveren, der ikke kommer fra Cloudflares IP-adresser eller fra betroede partnere.

SAMSIK anbefaler også at indgå aftaler om DDoS-beskyttelse med internet- eller hostingudbyderen. Spørgsmålene står i beredskabsplanen længere nede.

Opsætning trin for trin

Med Cloudflare passer den her opsætning til de fleste webshops:

  1. Flyt DNS til Cloudflare, og sørg for, at posterne for webshoppen er sat til at gå gennem Cloudflare (den orange sky), ikke kun DNS.
  2. Tjek, at mailposter (MX) og andre underdomæner ikke afslører serverens IP. Sendes mail fra webserveren, så overvej at flytte mailudsendelsen til en separat tjeneste.
  3. Begræns adgangen til serveren, så den kun tager imod webtrafik fra Cloudflares IP-adresser. Det gøres i serverens firewall eller hos hostingudbyderen. Se næste afsnit.
  4. Overvej at få en ny IP-adresse til serveren, hvis den gamle har været offentligt kendt i længere tid.
  5. Opret regler i WAF og rate limiting for de tunge sider, fx søgning og login. Eksempler følger herunder.
  6. Sørg for, at statiske filer og de sider, der kan caches, faktisk bliver det. Tjek, at kurv, checkout og min side aldrig caches.
  7. Lær at slå Under Attack Mode til. Det sker i oversigten for domænet under Quick Actions. Den sender besøgende gennem et ekstra tjek, før de slipper ind. Cloudflare kalder det selv en sidste udvej, og den kan påvirke statistik og tredjepartsscripts, så brug den kun under et angreb.

Regler i Cloudflare skrives i Cloudflares regelsprog. Et udtryk består af felter som http.request.uri.path (stien), http.request.uri.query (alt efter ?), ip.src.country (landekode), ip.src.asnum (netværksnummer) og cf.client.bot (verificerede robotter som Googlebot), kombineret med and, or og not. Funktionen starts_with() matcher begyndelsen af et felt.

WAF custom rules. Gratisplanen giver fem regler, Pro 20 og Business 100. Til en WordPress-shop er de her et godt udgangspunkt:

# Regel 1: Bloker XML-RPC, hvis I ikke bruger det (handling: Block)
(http.request.uri.path eq "/xmlrpc.php")

# Regel 2: Ekstra tjek på login uden for Danmark (handling: Managed Challenge)
(http.request.uri.path eq "/wp-login.php" and not ip.src.country in {"DK"})

# Regel 3: Kun under et angreb: tjek søgninger, men lad Google slippe igennem (handling: Managed Challenge)
(starts_with(http.request.uri.query, "s=") and not cf.client.bot)

# Regel 4: Kun under et angreb: bloker de netværk, angrebet kommer fra (handling: Block)
(ip.src.asnum in {64496 64511})

Managed Challenge viser et tjek, som rigtige browsere normalt klarer uden at kunden mærker det, mens scripts bliver stoppet. Regel 2 kan give problemer, hvis I har ansatte, der logger ind fra udlandet, og regel 3 og 4 er nødregler, som slås til og fra efter behov. Et tjek returnerer en HTML-side, så det virker ikke på kald, hvor browseren venter et andet svar, fx en søgning, der henter forslag med JavaScript, mens kunden skriver. Netværksnumrene i regel 4 er numre, der er reserveret til dokumentation. De rigtige finder I i Cloudflares oversigt over trafikken under angrebet.

Rate limiting rules. Her afhænger mulighederne meget af planen:

FreeProBusiness
Antal regler125
Felter i udtrykketSti og verificerede robotterOgså host, URI og queryOgså metode, IP og user agent
Tælleperiode10 sekunderOp til 1 minutOp til 10 minutter
Blokeringstid10 sekunderOp til 1 timeOp til 1 døgn
Tæller pr.IP-adresseIP-adresseIP-adresse, også med hensyn til NAT

På gratisplanen kan reglen altså kun se på stien. Det passer til login, men ikke til WooCommerce-søgning, som ligger i query-delen:

# Free: login. Fx 5 forespørgsler pr. 10 sekunder pr. IP, bloker i 10 sekunder
(http.request.uri.path eq "/wp-login.php")

# Pro: søgning. Fx 20 forespørgsler pr. minut pr. IP
(starts_with(http.request.uri.query, "s=") and not cf.client.bot)

# Business: tæl kun POST mod login, så det ikke rammer kunder, der bare åbner siden
(http.request.method eq "POST" and http.request.uri.path eq "/wp-login.php")

Tallene er udgangspunkter. Se i loggen, hvor mange forespørgsler en rigtig kunde laver, og sæt grænsen et godt stykke over.

Cache rules. Gratisplanen giver ti regler. Den vigtigste regel for en WooCommerce-shop er at sikre, at sider med kundedata aldrig caches. WooCommerce anbefaler selv at undtage kurv, checkout og min konto og de cookies, der viser, at en kunde har noget i kurven:

# Cache eligibility: Bypass cache
(starts_with(http.request.uri.path, "/kurv")
 or starts_with(http.request.uri.path, "/kassen")
 or starts_with(http.request.uri.path, "/min-konto")
 or http.cookie contains "woocommerce_items_in_cart"
 or http.cookie contains "wp_woocommerce_session_"
 or http.cookie contains "wordpress_logged_in_")

Stierne skal passe til jeres shop. På en dansk WooCommerce er de ofte oversat, så tjek de faktiske adresser. Først når den regel er på plads, kan I overveje en regel, der gør HTML for anonyme besøgende Eligible for cache med en kort Edge TTL. Det kræver en test med to forskellige browsere, så I er sikre på, at kunder aldrig ser hinandens kurve.

Under Attack Mode på udvalgte stier. Under Attack Mode kan også slås til på udvalgte stier via en konfigurationsregel, hvor indstillingen I'm Under Attack sættes til On. Udtrykket kan fx være (starts_with(http.request.uri.path, "/wp-login.php")). Det er en god mellemvej, hvis det kun er en del af shoppen, der bliver ramt.

Test altid betalingsflowet efter ændringer. Betalingsudbydere sender ofte besked tilbage til shoppen om, at en betaling er gennemført, og de beskeder må ikke blive blokeret af rate limiting eller ekstra tjek, fordi en server ikke kan løse et tjek, der er beregnet til en browser. Lav en regel med handlingen Skip for betalingsudbyderens callback-adresse, før I strammer andre regler. Samme hensyn gælder integrationer til lager, ERP og fragt.

Serveren bag CDN'et: firewall, rigtige IP'er og nginx

Et CDN beskytter kun, hvis serveren ikke kan nås uden om det. Det her afsnit er til den, der drifter serveren, og viser de tre ting, der skal være på plads: firewallen, den rigtige klient-IP og et sidste lag rate limiting på selve serveren.

Lås firewallen til Cloudflare. Cloudflare udgiver sine IP-intervaller som tekstfiler på https://www.cloudflare.com/ips-v4 og https://www.cloudflare.com/ips-v6. På en Ubuntu-server med ufw kan reglerne oprettes sådan:

for net in $(curl -s https://www.cloudflare.com/ips-v4) $(curl -s https://www.cloudflare.com/ips-v6); do
  sudo ufw allow proto tcp from "$net" to any port 80,443 comment 'cloudflare'
done
sudo ufw status numbered

Derefter skal den gamle regel, der tillader port 80 og 443 fra alle, fjernes med sudo ufw delete <nummer>. I ufw gælder den første regel, der passer, så en åben regel øverst gør de nye regler virkningsløse. Har standardpolitikken for indgående trafik ikke allerede afvisning, sættes den med sudo ufw default deny incoming. Husk at tillade SSH fra jeres egne adresser, før I ændrer politikken. Cloudflares lister ændrer sig sjældent, men de ændrer sig, så kør opdateringen med jævne mellemrum.

Test bagefter fra en maskine uden for Cloudflare. Her er 203.0.113.10 serverens adresse. Kommandoen skal give timeout, ikke et svar:

curl -sv --max-time 10 --resolve www.eksempel.dk:443:203.0.113.10 https://www.eksempel.dk/ -o /dev/null

Authenticated Origin Pulls. En firewall på IP-adresser tillader al trafik fra Cloudflare, også fra andre Cloudflare-kunder, der peger på jeres IP. Authenticated Origin Pulls lukker det hul ved at lade Cloudflare vise et klientcertifikat, som serveren kræver. Det kræver krypteringstilstanden Full eller højere. Med Cloudflares fælles certifikat, authenticated_origin_pull_ca.pem, ser nginx-delen sådan ud:

# Trin 1: tag imod certifikatet uden at kræve det, og tjek loggen
ssl_client_certificate /etc/nginx/certs/cloudflare.crt;
ssl_verify_client optional;

# Trin 2: når alt virker, kræv det
ssl_verify_client on;

Funktionen slås til under SSL/TLS, Origin Server og fanen Authenticated Origin Pulls. Det fælles certifikat beviser kun, at forespørgslen kommer fra Cloudflares netværk, ikke fra jeres konto. Vil I have det, skal I bruge den variant, hvor I uploader jeres eget certifikat for zonen.

Den rigtige klient-IP. Bag Cloudflare ser serveren Cloudflares IP-adresser som afsender. Uden en rettelse står Cloudflares adresser i loggen, og rate limiting på serveren tæller alle kunder som én. Cloudflare sender den rigtige adresse i headeren CF-Connecting-IP, og nginx-modulet ngx_http_realip_module kan bruge den. Modulet er ikke med i nginx, når det bygges fra kildekode uden tilvalg, så tjek først med nginx -V 2>&1 | grep -o with-http_realip_module:

# I http-blokken. Én linje pr. interval fra ips-v4 og ips-v6
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 2400:cb00::/32;
# ... resten af Cloudflares intervaller
real_ip_header CF-Connecting-IP;

Det er vigtigt, at kun Cloudflares intervaller står som betroede. Ellers kan hvem som helst sende en falsk CF-Connecting-IP og vælge sin egen IP-adresse i jeres log.

Rate limiting i nginx. Selv med Cloudflare er det fornuftigt med et lag på serveren, fordi det også virker, hvis trafikken kommer en anden vej, og fordi gratisplanen hos Cloudflare kun har én regel. nginx har to moduler: limit_req begrænser antallet af forespørgsler pr. tidsenhed, og limit_conn begrænser antallet af samtidige forbindelser. Eksemplet her begrænser WooCommerce-søgning og login uden at røre almindelige sidevisninger:

# http-blokken
# Kun forespørgsler med ?s= får en nøgle. En tom nøgle tæller ikke med.
map $arg_s $soeg_noegle {
    ""      "";
    default $binary_remote_addr;
}
limit_req_zone $soeg_noegle        zone=soeg:10m  rate=2r/s;
limit_req_zone $binary_remote_addr zone=login:10m rate=10r/m;
limit_conn_zone $binary_remote_addr zone=forb:10m;
limit_req_status 429;
limit_conn_status 429;

# server-blokken
limit_conn forb 30;

location / {
    limit_req zone=soeg burst=10 nodelay;
    try_files $uri $uri/ /index.php?$args;
}

location = /wp-login.php {
    limit_req zone=login burst=5 nodelay;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_pass unix:/run/php/php-fpm.sock;
}
DirektivHvad det betyder
$binary_remote_addrKlientens IP-adresse i binær form. Efter realip-modulet er det kundens rigtige adresse
zone=soeg:10mDelt hukommelse til tællerne. På et 64-bit system fylder hver adresse 128 bytes, så 1 MB rummer omkring 8.000 adresser og 10 MB omkring 80.000
rate=2r/s og rate=10r/mTilladt gennemsnit pr. sekund eller pr. minut
burst=10Hvor mange forespørgsler ud over gennemsnittet der må komme i et ryk
nodelayForespørgsler inden for burst behandles med det samme i stedet for at blive forsinket
limit_conn forb 30Højst 30 samtidige forbindelser pr. IP. Med HTTP/2 tæller hver samtidig forespørgsel som en forbindelse
limit_req_status 429Afviste forespørgsler får 429 Too Many Requests i stedet for standardværdien 503

Stien til PHP-FPM-socket og fastcgi-linjerne skal passe til jeres server. Start forsigtigt: med limit_req_dry_run on; tæller nginx og logger, men afviser ikke. Variablen $limit_req_status får så værdien REJECTED_DRY_RUN for de forespørgsler, der ville være blevet afvist, og den kan skrives i loggen. Når tallene ser rigtige ud, slås prøvetilstanden fra. Tjek konfigurationen med nginx -t, og genindlæs med nginx -s reload.

Sådan ser et angreb ud i loggen

Det første spørgsmål under et nedbrud er, om det er et angreb, en kampagne eller en fejl. Svaret står i webserverens access-log. nginx skriver som standard i formatet combined, hvor felterne er klientens IP, tidspunkt, forespørgsel, statuskode, størrelse, referer og user agent:

203.0.113.45 - - [21/Oct/2026:14:03:11 +0200] "GET /?s=xq91&post_type=product HTTP/1.1" 200 51234 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"

Når loggen er delt op ved mellemrum, er IP-adressen felt 1, tidspunktet felt 4, stien felt 7 og statuskoden felt 9. Deles den ved anførselstegn, er user agent felt 6. Det er nok til at besvare de fire vigtigste spørgsmål med awk. Stien til loggen er typisk /var/log/nginx/access.log, men kan være en anden hos jeres hosting.

Hvilke IP-adresser sender mest?

awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

Hvilke stier bliver ramt? Query-delen skæres fra, så tusind forskellige søgeord tæller som én sti:

awk '{split($7, a, "?"); print a[1]}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

Hvilke user agents?

awk -F'"' '{print $6}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

Hvor mange forespørgsler pr. minut? Her ses, hvornår angrebet startede:

awk '{print substr($4, 2, 17)}' /var/log/nginx/access.log | uniq -c | tail -30

Sådan læser I svarene:

MønsterHvad det typisk er
Få IP-adresser med tusindvis af forespørgsler hverEt simpelt angreb eller en aggressiv crawler. Kan blokeres på IP
Tusindvis af IP-adresser med få forespørgsler hver, alle mod samme stiEt distribueret angreb på lag 7. Kræver rate limiting eller tjek på stien
Mange tilfældige søgeord på ?s=Angreb, der bevidst undgår cache
Den samme user agent på alle forespørgsler, fx et script-bibliotekAutomatiseret trafik, der kan blokeres på user agent
Mange forskellige IP-adresser, der følger en normal vej gennem shoppenSandsynligvis en kampagne eller et nyhedsbrev
Alle IP-adresser tilhører CloudflareRealip er ikke sat op. Ret det først, ellers kan I ikke se noget

Statuskoderne viser, om forsvaret virker. Mange 429 eller 503 betyder, at rate limiting afviser trafik. Mange 502 og 504 betyder, at PHP eller databasen ikke kan følge med:

awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn

nginx skriver også i fejlloggen, når limit_req eller limit_conn griber ind. Linjerne indeholder teksten limiting requests eller limiting connections:

grep -c 'limiting requests' /var/log/nginx/error.log

Mistænker I et protokolangreb, er det netværket og ikke loggen, der skal undersøges. ss viser forbindelser på Linux, og et stort antal halvåbne forbindelser på port 443 er tegn på et SYN-flood:

ss -s
ss -Htn state syn-recv '( sport = :443 )' | wc -l

Ligger serveren bag Cloudflare og er låst korrekt, bør der ikke komme et SYN-flood igennem. Gør der det, kender angriberen serverens IP-adresse, og så er det den, der skal skiftes.

En lille beredskabsplan

Når angrebet rammer, er der ikke tid til at finde ud af, hvem der har koden til DNS. Skriv derfor en kort plan på én side, og læg den et sted, der ikke ligger på den server, der kan gå ned.

Før angrebet

  • Navne og telefonnumre på hostingudbyder, CDN-udbyder, udvikler og den interne ansvarlige, og mindst to personer med adgang til DNS, Cloudflare og hosting.
  • Overvågning, der tjekker shoppen udefra og giver besked, når den svarer langsomt eller ikke svarer.
  • En statusside eller en fast besked, der kan lægges ud på sociale medier og i kundeservice. Statussiden skal ligge hos en anden udbyder end shoppen.
  • Nødreglerne fra afsnittet om opsætning, oprettet på forhånd og slået fra, så de kan slås til med ét klik.

Det skal I spørge hostingudbyderen om

  • Filtrerer I DDoS på netværksniveau, og er det inkluderet i vores aftale, eller koster det ekstra?
  • Hvor stort et angreb kan jeres filtrering tage, før I må gribe ind på anden måde?
  • Hvad gør I, hvis angrebet er større: blokerer I al trafik til vores IP-adresse for at beskytte resten af netværket, og hvor længe?
  • Er vi på delt hosting, og hvad sker der med vores site, hvis en anden kunde på samme server bliver angrebet?
  • Kan vi få en ny IP-adresse med kort varsel, hvis den nuværende er kendt?
  • Kan I begrænse adgangen til port 80 og 443 til vores CDN's IP-adresser i jeres firewall?
  • Har vi adgang til access-loggen i realtid, og hvor længe gemmes den?
  • Hvem ringer vi til uden for åbningstid, og hvor hurtigt svarer de?

Under angrebet

  1. Bekræft, at det er et angreb og ikke en fejl, fx ved at se på trafikken i CDN eller hos hostingen og køre kommandoerne fra afsnittet om loggen.
  2. Kontakt hostingudbyderen, og slå Under Attack Mode til, aktiver nødreglerne eller stram rate limiting.
  3. Sæt annoncer og planlagte nyhedsbreve på pause, så I ikke betaler for trafik til en shop, der ikke svarer.
  4. Giv kundeservice en kort tekst: shoppen er utilgængelig, ingen kundedata er berørt, og der arbejdes på det.
  5. Hold øje med login-forsøg og ændringer på serveren, fordi DDoS kan bruges som afledning.

Efter angrebet

  • Gem logfiler og noter, hvornår det startede og sluttede, og hvad der virkede. Kopiér loggen væk fra serveren, før den bliver roteret.
  • Slå Under Attack Mode og nødregler fra igen, og test betalingsflowet.
  • Ret de svage punkter, angrebet ramte, fx en søgeside uden rate limiting.
  • Anmeld det til politiet, hvis det har givet tab.

Vi har en side om, hvordan man laver en samlet kriseplan for cyberangreb, hvor DDoS er en af hændelserne.

Typiske fejl

De fejl, vi oftest ser, når sites bliver lagt ned af trafik:

  • CDN er slået til, men serveren tager stadig imod trafik direkte. Så hjælper filteret ikke, så snart angriberen finder IP-adressen. Test det med curl --resolve mod serverens adresse.
  • Serverens IP står i en gammel DNS-post til et testmiljø, en ftp-adgang eller mailserveren, eller i headeren på de mails, shoppen sender.
  • Alt er i cache, også kurven. Det giver en hurtig shop, men kunder kan se hinandens kurve. Cache skal sættes op med omtanke.
  • Rate limiting er så stram, at rigtige kunder bliver blokeret, fx når mange kunder sidder bag samme IP på en arbejdsplads, eller betalingsudbyderens besked tilbage til shoppen bliver blokeret.
  • Rate limiting på serveren uden realip. Alle forespørgsler ser ud til at komme fra få Cloudflare-adresser, og grænsen rammer alle kunder på én gang.
  • Realip stoler på alle. set_real_ip_from 0.0.0.0/0 betyder, at enhver kan vælge sin egen IP-adresse ved at sende headeren selv.
  • Ingen ved, hvem der har adgang til DNS. Den person, der oprettede Cloudflare-kontoen, er stoppet.
  • Under Attack Mode bliver glemt og står slået til i flere uger efter angrebet.
  • Ingen overvågning udefra. Man opdager, at shoppen er nede, når kunderne skriver.

Spørgsmål og svar

Kan et DDoS-angreb stjæle kundedata? Nej. Et DDoS-angreb overbelaster sitet, men giver ikke adgang til det. Hold dog øje med andre aktiviteter samtidig, fordi angreb kan bruges som afledning.

Skal vi anmelde et DDoS-angreb til Datatilsynet? Et rent DDoS-angreb, hvor ingen data er kommet i forkerte hænder, er ikke det samme som et databrud. Men er I i tvivl, så læs vores side om databrud og GDPR, og tal med jeres DPO.

Er gratis DDoS-beskyttelse god nok? For mange mindre webshops dækker en gratis CDN-plan meget, fordi filtreringen af selve angrebstrafikken på lag 3, 4 og 7 er inkluderet. Begrænsningen ligger i, hvor mange regler I kan lave til rate limiting og WAF, hvilke felter reglerne kan bruge, og hvor hurtigt I kan få hjælp. Med én regel til rate limiting, der kun kan se på stien, giver det mening at supplere med rate limiting i nginx.

Hjælper det at blokere hele lande? Det kan tage toppen af et angreb, der kommer fra få lande, men et botnet består typisk af enheder over hele verden, også i Danmark. En regel som (not ip.src.country in {"DK" "SE" "NO" "DE"}) med handlingen Managed Challenge er derfor mere sikker end Block, fordi danske kunder på rejse stadig kan komme ind.

Kan vi se, hvis vi er under angreb lige nu? Tegnene er, at sitet er langsomt eller nede, mens serveren arbejder på fuld kraft, og at trafikken i CDN eller hostingpanel er langt over det normale, ofte fra mange lande på én gang. I loggen ses det som et pludseligt spring i forespørgsler pr. minut og mange forespørgsler mod de samme få stier.

Hvad det betyder for en webshop

For de fleste webshops er DDoS ikke et spørgsmål om at blive hacket, men om at holde åben. Det gode ved det er, at det meste kan forberedes på en eftermiddag: et CDN foran shoppen, en server, der kun tager imod trafik fra CDN'et, en regel for rate limiting på søgning og login, cache, der ikke rører kurven, overvågning udefra og en plan på én side.

Det dårlige er, at det sjældent bliver gjort, før det er for sent. Og SAMSIK skriver, at de samme mål ofte bliver forsøgt ramt gentagne gange, så et angreb er ikke en garanti for, at det er overstået.

Vi kan gennemgå jeres opsætning, låse serveren til CDN'et og sætte overvågning og alarmer op, så I ved, når shoppen ikke svarer. Er I allerede ramt af et angreb, eller er der sket mere end overbelastning, så har vi en side om hjælp efter hackerangreb, hvor målet er at få jer kørende igen inden for 24 timer.

Kilder

EmneSikkerhed

Relaterede artikler om Sikkerhed

Læs også

01 Er min mail hacket? Tegnene og de første skridt for jeres firmamail Sikkerhed · 21 min 02 Flere konverteringer i Meta fra 12. november: hvad der ændrer sig, og hvad I skal tjekke Paid Ads · 7 min 03 Meta slår product browsing til i jeres annoncer den 28. oktober Paid Ads · 8 min