Dataförgiftning och bakdörrar
Kunna förklara hur träningsdata kan manipuleras och hur man upptäcker det.
Förkunskaper
Intuition
Dataförgiftning är att manipulera träningsdatan så att modellen lär sig något angriparen vill.
| Angrepp | Mål | Syns i utvärderingen? |
|---|---|---|
| Tillgänglighetsangrepp | försämra modellen generellt | ja |
| Riktat angrepp | få fel svar på specifika indata | knappt |
| Bakdörr | normalt beteende, men fel vid en trigger | nej |
Bakdörren är den obehagliga. Modellen beter sig helt normalt — utom när ett visst mönster förekommer i indata, och då gör den något annat.
Ett klassiskt exempel: en bildklassificerare där en liten gul fyrkant i hörnet gör att allt klassas som «hastighetsbegränsning 80». På alla vanliga bilder fungerar modellen perfekt. Testmängden visar ingenting.
Varför det är relevant nu: moderna modeller tränas på webbskrapad data som vem som helst kan bidra till. Carlini m.fl. (2023) visade att det är praktiskt genomförbart att förgifta en liten men tillräcklig andel av flera kända webbkorpusar — bland annat genom att köpa utgångna domäner som ingår i dem.
Formellt
Angreppsytan i en modern pipeline:
| Yta | Hur |
|---|---|
| Webbkorpus | publicera text som skrapas; köpa utgångna domäner |
| Crowdsourcad märkning | felmärka systematiskt |
| Användargenererad data | om systemet tränar på egen trafik |
| RLHF-preferenser | manipulera rangordningar |
| Förtränade vikter | en modell från en okänd källa kan innehålla en bakdörr |
| Beroenden | ett bibliotek i kedjan |
Den näst sista är den mest underskattade: att ladda ner en modell från en publik hubb är att lita på den som laddade upp den. Kontrollera signaturer och använd safetensors — pickle-baserade format kan dessutom köra kod vid inläsning, vilket är ett helt annat och mer omedelbart problem.
Hur lite som krävs. Forskningen pekar mot att en förvånansvärt liten andel förgiftade exempel räcker för en riktad bakdörr — ofta bråkdelar av en procent, och i vissa uppställningar ett fast antal exempel snarare än en andel. Det betyder att «vi har miljarder dokument, några dåliga spelar ingen roll» inte är ett giltigt argument.
Motmedel, och vad de faktiskt klarar:
| Motmedel | Klarar | Klarar inte |
|---|---|---|
| Proveniens och signering | okända källor | en förgiftad men signerad källa |
| Deduplicering | upprepade injektioner | enstaka exempel |
| Aktiveringsklustring | bakdörrar med tydlig signatur | subtila triggers |
| Spektral signaturanalys | utstickare i representationsrummet | små andelar |
| Finjustering på ren data | många bakdörrar | ihärdiga |
| Beskärning av oanvända neuroner | vissa bakdörrar | |
| Triggersökning | kända mönstertyper | okända |
Den ärliga sammanfattningen är att ingen metod ger garantier. Försvaret bygger på lager: känd proveniens, filtrering, avvikelsedetektering och utvärdering som aktivt letar efter avvikande beteende.
Vad man gör i praktiken:
- Vet varifrån datan kommer. Logga källa per dokument.
- Signera och verifiera modellvikter och dataset.
- Träna inte på egen produktionstrafik utan granskning.
- Utvärdera på hållna, betrodda testmängder som aldrig varit i kontakt med pipelinen.
- Leta aktivt efter bakdörrar i modeller från tredje part innan de sätts i drift.
Punkt 3 är särskilt relevant för system som samlar in användarinteraktioner: en feedbackloop som tränar på det användarna skickar in är en öppen inbjudan.
Kod
import numpy as np, torch
from collections import Counter
# Aktiveringsklustring: förgiftade exempel bildar ofta ett eget kluster
def aktiveringsklustring(modell, dataloader, lager, n_kluster=2):
from sklearn.cluster import KMeans
from sklearn.decomposition import PCA
lagrat = []
h = lager.register_forward_hook(lambda m, i, o: lagrat.append(o.detach().flatten(1).cpu()))
etiketter = []
with torch.no_grad():
for x, y in dataloader:
modell(x); etiketter.append(y)
h.remove()
A = torch.cat(lagrat).numpy()
y = torch.cat(etiketter).numpy()
misstankta = {}
for klass in np.unique(y):
mask = y == klass
if mask.sum() < 20:
continue
Z = PCA(n_components=10).fit_transform(A[mask])
k = KMeans(n_clusters=n_kluster, n_init=10, random_state=0).fit(Z)
andelar = np.bincount(k.labels_, minlength=n_kluster) / mask.sum()
if andelar.min() < 0.15: # ett litet, tydligt avskilt kluster
misstankta[int(klass)] = round(float(andelar.min()), 4)
return misstankta
# {3: 0.042} ← 4 % av klass 3 ligger i ett eget kluster: undersök dem
# Triggertest: mät om ett mönster systematiskt ändrar klassificeringen
def triggertest(modell, bilder, trigger_fn, n=200):
modell.eval()
with torch.no_grad():
fore = modell(bilder[:n]).argmax(1)
efter = modell(torch.stack([trigger_fn(b) for b in bilder[:n]])).argmax(1)
andrade = (fore != efter)
mal = Counter(int(k) for k in efter[andrade])
dominerande = mal.most_common(1)[0] if mal else (None, 0)
return {"andel_andrade": round(float(andrade.float().mean()), 3),
"dominerande_mal": dominerande[0],
"andel_till_det_malet": round(dominerande[1] / max(int(andrade.sum()), 1), 3)}
# Hög andel ändrade OCH en dominerande målklass = stark indikation på bakdörr
def gul_fyrkant(bild, storlek=4):
b = bild.clone()
b[:, -storlek:, -storlek:] = torch.tensor([1.0, 1.0, 0.0])[:, None, None]
return b
# Proveniens: logga källa per dokument och gör den granskningsbar
def korpus_med_proveniens(dokument):
import hashlib
return [{"text": d["text"],
"kalla": d["kalla"],
"hamtad": d["hamtad"],
"sha256": hashlib.sha256(d["text"].encode()).hexdigest()[:16],
"betrodd": d["kalla"] in BETRODDA_KALLOR}
for d in dokument]
def andel_obetrott(korpus):
n = sum(1 for d in korpus if not d["betrodd"])
return {"obetrodda": n, "av": len(korpus), "andel": round(n / max(len(korpus), 1), 4)}
# Ladda modeller säkert
from safetensors.torch import load_file
vikter = load_file("modell.safetensors") # kan per konstruktion inte köra kod
# torch.load("modell.pt") ← kör pickle; aldrig från en okänd källa
Behärskning innebär
- Skiljer olika angreppstyper mot träningsdata
- Förklarar hur bakdörrar fungerar
- Beskriver realistiska motmedel
Logga in för att göra övningarna och bygga upp din behärskning.
Källor
- arXiv — Poisoning Web-Scale Training Datasets is Practical — arXiv (öppen åtkomst; licens per artikel)
- arXiv — BadNets: Identifying Vulnerabilities in the Machine Learning Model Supply Chain — arXiv (öppen åtkomst; licens per artikel)
- OWASP Top 10 for LLM Applications — CC BY-SA 4.0