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
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:
| Type | Lag | Hvad der rammes | Måles i | Hvem kan stoppe det |
|---|---|---|---|---|
| Volumenangreb | 3 og 4 | Internetforbindelsen til serveren | Bit pr. sekund | Kun et netværk, der er større end angrebet |
| Protokolangreb | 3 og 4 | Firewalls, load balancere og serverens forbindelsestabel | Pakker pr. sekund | Netværksfilter hos CDN eller hosting |
| Applikationsangreb | 7 | Selve webshoppen | Forespørgsler pr. sekund | CDN-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år | Hvad skete der | Kilde |
|---|---|---|
| Efteråret 2024 | Kraftige DDoS-angreb mod finanssektoren. Nordeas netbank var periodisk påvirket i 25 dage | SAMSIK, Cybertruslen mod Danmark 2025 |
| Marts 2025 | En gruppe, der angiveligt støtter Hamas, angreb danske myndigheders hjemmesider | SAMSIK, Cybertruslen mod Danmark 2025 |
| 12.-13. november 2025 | Flere kommuner, bl.a. Gentofte, Rødovre, Ishøj og Tårnby, og senere Transportministeriet, borger.dk og Terma blev ramt. Gruppen NoName057(16) tog ansvaret | The Local Denmark og The Record |
| 17. november 2025 | Dagen før kommunal- og regionsrådsvalget var hjemmesider for flere partier kortvarigt nede. Valget blev ikke påvirket | The 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"
donetime_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ærdi | Betydning |
|---|---|
HIT | Svaret kom fra Cloudflares cache. Serveren blev ikke ramt |
MISS | Svaret kunne caches, men lå der ikke, så serveren blev ramt |
EXPIRED | Kopien i cache var for gammel, så serveren blev ramt |
BYPASS | Svaret måtte ikke caches, fx fordi serveren sendte en cookie |
DYNAMIC | Forespø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.phpi 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.
| Lag | Hvad det gør | Hvem leverer det |
|---|---|---|
| CDN og DDoS-filter | Opsuger trafikken i et stort netværk, før den når serveren | Fx Cloudflare. Hostingudbydere har ofte deres egen |
| WAF (web application firewall) | Blokerer kendte angrebsmønstre og mistænkelig trafik | CDN-udbyderen eller hostingen |
| Rate limiting | Begrænser, hvor mange forespørgsler én IP-adresse må sende til fx søgning og login | CDN, WAF eller webserveren |
| Skjult og låst server-IP | Sørger for, at angriberen ikke kan gå uden om filteret | Jer eller jeres udvikler |
| Cache | Serverer de sider, der kan caches, uden at ramme databasen | CDN, hosting og shopsystemet |
| Aftale med hosting | Afklarer, hvad der sker, når I bliver ramt | Hostingudbyderen |
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:
- 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.
- 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.
- 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.
- Overvej at få en ny IP-adresse til serveren, hvis den gamle har været offentligt kendt i længere tid.
- Opret regler i WAF og rate limiting for de tunge sider, fx søgning og login. Eksempler følger herunder.
- Sørg for, at statiske filer og de sider, der kan caches, faktisk bliver det. Tjek, at kurv, checkout og min side aldrig caches.
- 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:
| Free | Pro | Business | |
|---|---|---|---|
| Antal regler | 1 | 2 | 5 |
| Felter i udtrykket | Sti og verificerede robotter | Også host, URI og query | Også metode, IP og user agent |
| Tælleperiode | 10 sekunder | Op til 1 minut | Op til 10 minutter |
| Blokeringstid | 10 sekunder | Op til 1 time | Op til 1 døgn |
| Tæller pr. | IP-adresse | IP-adresse | IP-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 numberedDerefter 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/nullAuthenticated 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;
}| Direktiv | Hvad det betyder |
|---|---|
$binary_remote_addr | Klientens IP-adresse i binær form. Efter realip-modulet er det kundens rigtige adresse |
zone=soeg:10m | Delt 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/m | Tilladt gennemsnit pr. sekund eller pr. minut |
burst=10 | Hvor mange forespørgsler ud over gennemsnittet der må komme i et ryk |
nodelay | Forespørgsler inden for burst behandles med det samme i stedet for at blive forsinket |
limit_conn forb 30 | Højst 30 samtidige forbindelser pr. IP. Med HTTP/2 tæller hver samtidig forespørgsel som en forbindelse |
limit_req_status 429 | Afviste 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 -20Hvilke 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 -20Hvilke user agents?
awk -F'"' '{print $6}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20Hvor 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 -30Sådan læser I svarene:
| Mønster | Hvad det typisk er |
|---|---|
| Få IP-adresser med tusindvis af forespørgsler hver | Et simpelt angreb eller en aggressiv crawler. Kan blokeres på IP |
| Tusindvis af IP-adresser med få forespørgsler hver, alle mod samme sti | Et 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-bibliotek | Automatiseret trafik, der kan blokeres på user agent |
| Mange forskellige IP-adresser, der følger en normal vej gennem shoppen | Sandsynligvis en kampagne eller et nyhedsbrev |
| Alle IP-adresser tilhører Cloudflare | Realip 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 -rnnginx 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.logMistæ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 -lLigger 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
- 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.
- Kontakt hostingudbyderen, og slå Under Attack Mode til, aktiver nødreglerne eller stram rate limiting.
- Sæt annoncer og planlagte nyhedsbreve på pause, så I ikke betaler for trafik til en shop, der ikke svarer.
- Giv kundeservice en kort tekst: shoppen er utilgængelig, ingen kundedata er berørt, og der arbejdes på det.
- 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 --resolvemod 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/0betyder, 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
- Styrelsen for Samfundssikkerhed: Cybertruslen mod Danmark 2025
- SAMSIK: Truslen fra destruktive cyberangreb hæves til høj (24. september 2026)
- The Record: Pro-Russian group claims hits on Danish party websites
- The Local Denmark: Danish government and defence websites hit by cyberattack (13. november 2025)
- Cloudflare: About DDoS protection
- Cloudflare: DDoS managed rulesets
- Cloudflare: Under Attack mode
- Cloudflare: Custom rules
- Cloudflare: Rate limiting rules
- Cloudflare: Rules language, felter
- Cloudflare: Rules language, operatorer
- Cloudflare: Cache rules
- Cloudflare: Default cache behavior
- Cloudflare: Cloudflare cache responses
- Cloudflare: IP-adresser og beskyttelse af serveren
- Cloudflare: Authenticated Origin Pulls
- Cloudflare: Restoring original visitor IPs
- nginx: ngx_http_limit_req_module
- nginx: ngx_http_limit_conn_module
- nginx: ngx_http_realip_module
- nginx: ngx_http_log_module
- WooCommerce: Configuring caching plugins
- ss(8)
- ufw(8)
Relaterede artikler om Sikkerhed
Læs også
01 Er min mail hacket? Tegnene og de første skridt for jeres firmamail 02 Flere konverteringer i Meta fra 12. november: hvad der ændrer sig, og hvad I skal tjekke 03 Meta slår product browsing til i jeres annoncer den 28. oktober
