En scanner fortæller dig, at din webserver har 110 kritiske sårbarheder. Den har ingen. Næsten hver eneste falske positive i ekstern sårbarhedsscanning kan spores til den samme designbeslutning — og den samme beslutning får scannere til at overse rigtige huller den anden vej.

Det betyder mere, end det lyder, for begge fejlretninger har samme konsekvens: rapporten holder op med at blive læst. En side med kritiske fund, du ikke har, lærer folk at afvise værktøjet — og når det først er afvist, ryger det rigtige fund med.

Hvor falske positive faktisk kommer fra: tekstsøgning frem for matchning på identifikator

Sårbarhedsdatabaser kan spørges på to meget forskellige måder.

Den lette er fritekstsøgning. Bed om hver advarsel, hvis beskrivelse nævner nginx, og du får et stort resultatsæt i én forespørgsel. Det er enkelt at bygge, og det ser ud, som om det virker.

Det gør det ikke, for advarslers beskrivelser nævner produkter af mange grunde. Et resultatsæt for "nginx" indeholder huller i nginx selv, men også huller i tredjeparts-moduler til nginx, huller i helt andre produkter, der tilfældigvis kører bag nginx, og advarsler, hvis tekst siger noget i retning af "svarer til det tidligere nginx-problem". Tilskriver du kunden det hele, producerer du en side med kritiske fund, de ikke har.

Den rigtige fremgangsmåde bruger den strukturerede produktidentifikator, advarsler bærer — i den amerikanske nationale sårbarhedsdatabase (NVD) er det CPE, en formel notation, der navngiver leverandør, produkt og version, parret med udtrykkelige start- og slutgrænser i postens konfiguration. Et hul tilskrives nginx, kun når posten selv navngiver nginx i det strukturerede felt, ikke når prosaen tilfældigvis nævner det.

Leverandørhalvdelen betyder lige så meget som produkthalvdelen. Det er den detalje, der fanger dem, der er nået frem til CPE-matchning. Produktnavne er ikke entydige på tværs af leverandører: http_server tilhører Apache, Oracle og IBM. Matcher du kun på produktdelen, arkiverer du Oracle HTTP Servers versionsintervaller under Apaches httpd og melder sårbarheder, der hører til software, kunden slet ikke kører.

Den fejl, ingen taler om: falsk "ren"

Tekstsøgning har endnu en brist, og det er den farligere.

Den overser også sårbarheder. Nogle advarsler nævner aldrig det ramte produkt ved navn i beskrivelsen, fordi hullet sidder i en protokol eller en delt komponent, og teksten beskriver det på det niveau. HTTP/2-sårbarheden "Rapid Reset" er standardeksemplet: den rammer HTTP/2-implementeringerne i nginx, Apache og de fleste andre, og en nøgleordssøgning på "nginx" finder den ikke.

Så den samme fejlbehæftede teknik producerer både opfundne fund og manglende. En kunde kan se en ren rapport for en server med reelt udnyttelige huller — og en ren rapport er langt værre end en støjende, for den afslutter undersøgelsen. Ingen henter en ekstra vurdering, når de først har fået at vide, at alt er i orden.

Versionsmatchning, hvor de sidste fejl bor

Selv med korrekt produktidentifikation giver to versionsproblemer vildledende resultater.

Backports fra distributioner. Linux-distributioner lægger rutinemæssigt en sikkerhedsrettelse på en ældre version uden at ændre versionsnummeret — Debian og Ubuntu vedligeholder lappede builds af for eksempel 2.4.59, som indeholder rettelser udgivet opstrøms i senere versioner. En scanner, der sammenligner versionsnumre, ser et gammelt nummer og melder hullet. Softwaren er lappet. Det er en reel begrænsning ved enhver ekstern scanning, og det ærlige svar er at sige, at matchet er ubekræftet, i stedet for at fastslå eksponering.

Advarsler uden brugbare versionsgrænser. Nogle poster påstår at ramme hver eneste version nogensinde udgivet, som regel fordi ingen har udfyldt feltet ordentligt. At behandle det som en påstand betyder at markere hver eneste bruger af den software for altid. At behandle det som mangelfulde data betyder at springe det over — og bytte en smule dækning for en hel del præcision, hvilket er den rigtige handel, forudsat at rapporten siger, at posten blev sprunget over.

Problemet under det hele: dataene er tyndere, end de var

Korrekt matchning afhænger af, at de strukturerede felter er udfyldt, og siden begyndelsen af 2024 er de det ofte ikke. Den amerikanske nationale sårbarhedsdatabase, som står for berigelsen, kom voldsomt bagud med at tilføje CPE-data til nye poster og har ikke indhentet det fuldt ud. En post uden en struktureret produktidentifikator kan ikke matches korrekt af nogen.

De ærlige konsekvenser er værd at sige højt. En scanner, der kun læser den ene kilde, overser i stilhed nyere sårbarheder, hvis poster aldrig blev beriget. En scanner, der reagerer ved at falde tilbage til tekstsøgning, genindfører hvert eneste problem beskrevet ovenfor. Det forsvarlige svar er at læse mere end én kilde — CVE-programmets egne poster, økosystemernes advarselsdatabaser som OSV og GitHub Advisory Database, og i Europa ENISAs EU-sårbarhedsdatabase — og at sige tydeligt, hvilke sårbarheder der ikke kunne vurderes, fordi der ikke findes en brugbar identifikator.

Den version, du ikke kan se

Endnu en, som er særlig for ekstern scanning. Mange servere er sat op til ikke at afsløre deres version — server_tokens off i nginx og tilsvarende andre steder. Det er fornuftig hærdning.

Det betyder også, at en komponent uden version matcher nul advarsler og læses som ren. Det er problemet med det tavse grønne: scanneren har intet lært og har meldt succes.

Den rigtige adfærd er at melde komponenten som identificeret, men ubekræftet — og tælle den som ikke tjekket og ikke som godkendt. Melder din scanner en hærdet server som ren uden at nævne, at den ikke kunne fastslå en version, har du fundet noget, der er værd at spørge til.

Hvad man skal spørge en scanner-leverandør om

Fire spørgsmål, der skiller omhyggelige værktøjer fra hurtige:

  • Matcher I på strukturerede produktidentifikatorer, inklusive leverandøren — eller på advarslernes tekst?
  • Hvad melder I, når I ikke kan fastslå en version: ren eller ubekræftet?
  • Hvad sker der, når en datakilde er utilgængelig? Siger rapporten "ikke tjekket", eller viser den bare ingen fund?
  • Hvordan håndterer I backports fra distributioner, og siger fundet det?

Mønsteret bag alle fire er det samme: en god scanner skelner mellem "jeg tjekkede og fandt ingenting" og "jeg kunne ikke tjekke". Et værktøj, der klapper de to sammen til ét grønt resultat, kommer før eller siden til at berolige dig om noget, der ikke er sandt.

Hvorfor giver sårbarhedsscannere falske positive?

Sårbarhedsscannere giver oftest falske positive, fordi de søger i advarslernes tekst i stedet for at matche strukturerede produktidentifikatorer. En søgning på et produktnavn giver huller i produktet, men også huller i dets plugins, i helt andre produkter der blot nævner det, og i advarsler der refererer til det i forbifarten. At tilskrive kunden det hele producerer en side med kritiske fund, de ikke har. Korrekt matchning bruger i stedet de formelle leverandør- og produktfelter inde i hver advarselspost.

Kan en sårbarhedsscanner overse rigtige sårbarheder?

Ja, og en overset sårbarhed er den farligere af de to fejl. En scanner, der søger i advarslernes tekst, overser huller, hvis beskrivelser aldrig nævner det ramte produkt — almindeligt når sårbarheden sidder i en protokol eller en delt komponent, som med HTTP/2 Rapid Reset, der rammer nginx, uden at beskrivelsen bruger ordet. En ren rapport afslutter undersøgelsen, så et falsk rent resultat er værre end en støjende rapport: ingen henter en ekstra vurdering efter at have fået at vide, at alt er i orden.

Hvorfor melder min scanner en sårbarhed, min distribution allerede har lappet?

Fordi Linux-distributioner rutinemæssigt backporter sikkerhedsrettelser til en ældre version uden at ændre versionsnummeret, så et lappet Debian- eller Ubuntu-build stadig melder det gamle nummer. En scanner, der sammenligner versionsnumre, ser et gammelt nummer og melder hullet. Det er en reel begrænsning ved enhver ekstern scanning, og det ærlige svar er, at fundet siger, at matchet er ubekræftet og måske allerede lappet, i stedet for at fastslå at du er eksponeret.

Hvad bør en scanner gøre, når den ikke kan fastslå en version?

Melde komponenten som identificeret, men ubekræftet — og tælle den som ikke tjekket og ikke som godkendt. Mange servere er bevidst sat op til ikke at afsløre deres version, hvilket er fornuftig hærdning, men det betyder, at en komponent uden version matcher nul advarsler og læses som ren. Melder en scanner en hærdet server som ren uden at nævne, at den ikke kunne fastslå en version, præsenterer den mangel på information som et godt resultat.

Hvor VulnControl passer ind

VulnControl høster kun versionsintervaller fra poster, hvis strukturerede leverandør- og produktfelter matcher den software, den har identificeret — og begge fejlretninger beskrevet her er noget, den selv har gjort forkert én gang og rettet: en tidlig udgave gav 110 falske kritiske fund mod én sund nginx, og en senere meldte en server ren, mens en identisk markerede rigtige huller. Begge er nu dækket af tests, der kører ved hvert build. En komponent, hvis version ikke kan fastslås, meldes som ubekræftet, aldrig som ren. Den tekniske beskrivelse gennemgår matchningen i detaljer.