Data-exfiltratie via vectordatabases
Technieken voor data-exfiltratie uit vectordatabases: embedding-inversie om documenten te reconstrueren, enumeratie-aanvallen en op overeenkomst gebaseerd dataharvesten.
Data-exfiltratie uit vectordatabases is een risico dat veel organisaties onderschatten. De gangbare aanname is dat embeddings ondoorzichtige numerieke representaties zijn waaruit de originele content niet kan worden hersteld. Onderzoek heeft aangetoond dat deze aanname onjuist is: embeddings kunnen worden geïnverteerd om betekenisvolle tekst terug te halen, en vectordatabases kunnen systematisch worden bevraagd om opgeslagen content op schaal te extraheren.
Embedding-inversie
Embedding-inversie is het proces waarbij de originele invoertekst wordt gereconstrueerd uit de bijbehorende embeddingvector. Hoewel perfecte reconstructie over het algemeen niet mogelijk is, levert gedeeltelijke reconstructie vaak genoeg informatie op om bruikbaar te zijn voor een aanvaller.
Hoe inversie werkt
Embeddingmodellen worden getraind om tekst zo naar vectoren te mappen dat vergelijkbare teksten vergelijkbare vectoren opleveren. Inversiemodellen worden getraind op de omgekeerde mapping: voorspel, gegeven een vector, de tekst die deze heeft geproduceerd.
# Conceptuele inversie-aanval
# Stap 1: Train een inversiemodel op bekende tekst-embedding-paren
inversion_model = train_inversion_model(
texts=known_texts,
embeddings=[embedding_model.encode(t) for t in known_texts]
)
# Stap 2: Pas het inversiemodel toe op de doel-embeddings
target_embedding = stolen_from_vector_db # Verkregen via een query of directe toegang
recovered_text = inversion_model.decode(target_embedding)Kwaliteit van de inversie
De kwaliteit van de inversie hangt af van verschillende factoren:
- Dimensionaliteit van de embedding — Hoger-dimensionale embeddings (1536 voor OpenAI, 768 voor veel open-source modellen) bevatten meer informatie en zijn gevoeliger voor inversie
- Domeinspecificiteit — Embeddings van domeinspecifieke tekst (medische dossiers, juridische documenten) kunnen nauwkeuriger worden geïnverteerd wanneer het inversiemodel is getraind op vergelijkbare domeindata
- Beschikbaarheid van het model — Als de aanvaller toegang heeft tot hetzelfde embeddingmodel, kan hij naar believen trainingsparen voor het inversiemodel genereren
- Tekstlengte — Kortere teksten zijn vollediger te herstellen dan langere teksten, omdat de embedding daarvan een groter deel van de informatie vastlegt
Onderzoek heeft herstelpercentages aangetoond die variëren van gedeeltelijk (kernzinnen en entiteiten) tot bijna volledig (reconstructie van hele zinnen), afhankelijk van deze factoren.
Inversie in de praktijk
Een aanvaller met query-toegang tot een vectordatabase kan op verschillende manieren inversie uitvoeren:
# Methode 1: Directe vectortoegang
# Als de API de vectorwaarden samen met de resultaten teruggeeft
results = index.query(vector=probe, top_k=100, include_values=True)
for match in results.matches:
recovered = inversion_model.decode(match.values)
print(f"ID: {match.id}, Recovered: {recovered}")
# Methode 2: Inversie met hulp van metadata
# Metadata bevat vaak de originele tekst of een samenvatting
results = index.query(vector=probe, top_k=100, include_metadata=True)
for match in results.matches:
# Veel RAG-systemen slaan de originele chunk-tekst op in de metadata
if "text" in match.metadata:
print(f"Original text: {match.metadata['text']}")Enumeratie-aanvallen
Enumeratie-aanvallen extraheren systematisch alle of de meeste vectoren uit een database door een reeks queries uit te voeren die zo zijn ontworpen dat ze de embeddingruimte afdekken.
Uitputtende query-enumeratie
De eenvoudigste enumeratie-aanpak bevraagt de database met uiteenlopende probe-vectoren om zoveel mogelijk unieke resultaten op te halen:
# Genereer uiteenlopende probe-vectoren om de embeddingruimte af te dekken
retrieved_ids = set()
all_results = []
# Willekeurig probing
for i in range(10000):
probe = np.random.randn(1536)
probe = probe / np.linalg.norm(probe)
results = index.query(vector=probe.tolist(), top_k=100)
for match in results.matches:
if match.id not in retrieved_ids:
retrieved_ids.add(match.id)
all_results.append(match)
print(f"Retrieved {len(retrieved_ids)} unique vectors")Iteratieve enumeratie met uitsluiting
Een efficiëntere aanpak gebruikt de queryresultaten om volgende queries weg te sturen van reeds opgehaalde vectoren:
# Begin met een willekeurige probe
retrieved = []
for iteration in range(1000):
if not retrieved:
probe = np.random.randn(1536).tolist()
else:
# Genereer een probe die ver van de al opgehaalde vectoren ligt
# door in de richting tegengesteld aan het zwaartepunt van de opgehaalde vectoren te bewegen
centroid = np.mean([r['vector'] for r in retrieved], axis=0)
probe = -centroid + np.random.randn(1536) * 0.1
probe = (probe / np.linalg.norm(probe)).tolist()
results = index.query(vector=probe, top_k=100, include_values=True)
for match in results.matches:
if match.id not in {r['id'] for r in retrieved}:
retrieved.append({
'id': match.id,
'vector': match.values,
'metadata': match.metadata
})Indexstatistieken voor het inschatten van de scope
Voordat de aanvaller gaat enumereren, kan hij de omvang van de database inschatten:
stats = index.describe_index_stats()
total_vectors = stats.total_vector_count
namespaces = stats.namespaces
print(f"Total vectors: {total_vectors}")
print(f"Namespaces: {list(namespaces.keys())}")Op overeenkomst gebaseerd dataharvesten
Op overeenkomst gebaseerd harvesten gebruikt domeinkennis om semantisch gerelateerde content te extraheren, met de focus op waardevolle data in plaats van uitputtende enumeratie.
Gerichte extractie per onderwerp
Een aanvaller die geïnteresseerd is in specifieke onderwerpen, genereert queries die zo zijn ontworpen dat ze gerelateerde content ophalen:
# Extraheer alle content die met een specifiek onderwerp te maken heeft
seed_queries = [
"quarterly revenue and financial projections",
"executive compensation and stock options",
"merger and acquisition targets",
"pending litigation and legal risks",
"customer data breach incidents"
]
harvested = {}
for query_text in seed_queries:
query_embedding = embedding_model.encode(query_text)
results = index.query(
vector=query_embedding.tolist(),
top_k=50,
include_metadata=True
)
harvested[query_text] = [m.metadata.get('text', '') for m in results.matches]Sneeuwbalharvesten
Begin bij de eerste resultaten en gebruik de opgehaalde content om gerichtere queries te genereren:
# Sneeuwbal: gebruik opgehaalde content om meer gerelateerde content te vinden
initial_query = "employee salary information"
queue = [initial_query]
all_harvested = set()
while queue:
query_text = queue.pop(0)
query_embedding = embedding_model.encode(query_text)
results = index.query(vector=query_embedding.tolist(), top_k=20)
for match in results.matches:
if match.id not in all_harvested:
all_harvested.add(match.id)
text = match.metadata.get('text', '')
# Haal kernzinnen uit de opgehaalde tekst om als nieuwe queries te gebruiken
new_queries = extract_key_phrases(text)
queue.extend(new_queries[:3]) # Beperk de vertakkingHarvesten over namespaces heen
Als de aanvaller ontdekt dat data uit meerdere contexten in verschillende namespaces is opgeslagen, kan hij over namespaces heen harvesten:
# Harvest hetzelfde onderwerp over alle namespaces heen
for namespace in discovered_namespaces:
results = index.query(
vector=query_embedding.tolist(),
top_k=50,
namespace=namespace,
include_metadata=True
)
print(f"Namespace {namespace}: {len(results.matches)} results")Detectie en mitigatie
Exfiltratie uit een vectordatabase kan worden gedetecteerd via:
- Monitoring van queryvolume — Enumeratie-aanvallen vereisen veel queries; geef een alert bij ongebruikelijke querysnelheden
- Analyse van querydiversiteit — Willekeurig probing levert atypische querypatronen op vergeleken met legitieme applicatie-queries
- Bijhouden van resultaatdekking — Monitor welk percentage van de opgeslagen vectoren in queryresultaten is teruggegeven
- Rate limiting — Beperk het aantal queries per API-sleutel per tijdvenster
Mitigatiebenaderingen:
- Sla de originele tekst niet op in metadata — Sla alleen een document-ID op en haal de tekst op uit een afzonderlijk systeem met toegangscontrole
- Geef geen vectorwaarden terug — Configureer de API zo dat alleen ID's en scores worden teruggegeven, niet de embeddingvectoren zelf
- Implementeer query-auditing — Log alle queries met voldoende detail om het datatoegangspatroon van een aanvaller te kunnen reconstrueren
- Scheid toegangsniveaus — Gebruik verschillende API-sleutels met verschillende permissies voor verschillende afnemers
Verwante onderwerpen
- Inversion Attacks — Technische details van embedding-inversie
- Access Control — Gaten in de toegangscontrole die exfiltratie mogelijk maken
- Membership Inference — Bepalen of specifieke data in de database bestaat