Guide complet de l'API VirusTotal v3 : scripts Python pour analyser hashes, URLs et IPs, automatisation SOC avec rate limiting, enrichissement d'alertes SIEM et intégration SOAR.
Chaque jour, les équipes SOC reçoivent des centaines d'alertes impliquant des hashes de fichiers suspects, des adresses IP inconnues ou des domaines potentiellement malveillants. Sans automatisation, l'analyste passe un temps précieux à copier-coller ces indicateurs dans des interfaces web, un par un. VirusTotal, avec ses 70+ moteurs antivirus et ses 800+ millions de fichiers analysés, est devenu un standard de facto pour l'enrichissement des indicateurs de compromission (IOC). Son API v3 transforme ce travail manuel en pipeline automatisé : un hash arrive dans votre SIEM, une requête part vers VirusTotal, le résultat revient en JSON structuré, et le ticket d'incident est enrichi en quelques secondes. Ce guide vous donne les clés concrètes : architecture de l'API v3, scripts Python opérationnels pour analyser des hashes, soumettre des fichiers, traiter des listes d'URLs en masse, gérer le rate limiting, et intégrer VirusTotal dans vos workflows SOAR. Vous repartirez avec du code que vous pouvez déployer dès aujourd'hui.
VirusTotal : le moteur d'intelligence sur les menaces le plus utilisé au monde
VirusTotal a été fondé en 2004 par Hispasec Sistemas, avant d'être acquis par Google en 2012, puis intégré à Chronicle (la division cybersécurité d'Alphabet) en 2018. Cette généalogie explique la solidité de l'infrastructure et la richesse des données disponibles. La plateforme agrège aujourd'hui plus de 70 moteurs antivirus commerciaux (Kaspersky, Sophos, CrowdStrike, ESET, Bitdefender, Microsoft Defender...), des outils de sandbox comportementaux, et des sources de threat intelligence tierces.
Les chiffres parlent d'eux-mêmes : plus de 800 millions de fichiers uniques dans la base, plusieurs millions de nouvelles soumissions quotidiennes, et une couverture qui s'étend bien au-delà des simples fichiers -- URLs, domaines, adresses IP, et même certificats TLS sont analysables. Pour un analyste SOC, VirusTotal est souvent le premier réflexe face à un fichier inconnu ou une IP suspecte observée dans les logs.
Dans un contexte où les campagnes de phishing utilisent des domaines fraîchement enregistrés et où les malwares polymorphiques changent de hash à chaque variante, la valeur de VirusTotal réside moins dans la détection unitaire que dans l'agrégation : si 15 moteurs sur 70 détectent un fichier, la confiance dans la malveillance est élevée. Si aucun ne détecte mais que l'analyse comportementale en sandbox signale des comportements suspects (connexions C2, modification de clés de registre, injection de processus), le fichier mérite une investigation approfondie.
L'API VirusTotal est ce qui permet de passer de l'usage manuel à l'industrialisation. Plutôt que d'ouvrir un navigateur et de coller un hash, votre script Python interroge l'API, parse le JSON retourné, et prend une décision automatique basée sur des seuils configurables. Cette capacité est au coeur des architectures SOC modernes, des plateformes SOAR, et des pipelines d'enrichissement d'alertes. L'intégration avec des SIEM comme Splunk, Elastic Security ou Wazuh SIEM/XDR est aujourd'hui un prérequis pour toute équipe de sécurité qui veut réduire son MTTR (Mean Time To Respond).
Au-delà des SOC, VirusTotal est utilisé lors de tests de pentest pour vérifier si les outils offensifs sont détectés par les antivirus, par les équipes de threat hunting pour rechercher des fichiers liés à un groupe APT, ou encore par les développeurs d'antivirus pour améliorer leurs signatures. La richesse des métadonnées retournées -- date de première/dernière soumission, liste des noms de fichiers associés, relations avec d'autres IOC -- en fait un outil d'investigation complet.
API v3 vs v2 : ce qui a changé et pourquoi migrer
VirusTotal a maintenu deux versions de son API en parallèle pendant plusieurs années, mais l'API v2 est désormais dépréciée et ne reçoit plus de mises à jour. Si votre organisation utilise encore des scripts basés sur l'endpoint https://www.virustotal.com/vtapi/v2/, la migration vers la v3 est urgente -- non seulement pour bénéficier des nouvelles fonctionnalités, mais aussi parce que la v2 manque de nombreux attributs désormais essentiels.
La différence architecturale fondamentale est le passage à un modèle REST unifié basé sur des ressources typées. En v2, chaque type d'objet (fichier, URL, domaine) avait ses propres endpoints avec des paramètres différents et des formats de réponse hétérogènes. En v3, tout objet est une ressource identifiable par un type et un ID, et les endpoints suivent une convention cohérente : GET /api/v3/{type}/{id} pour lire une ressource, POST /api/v3/{type} pour en créer une. Cette cohérence simplifie considérablement le code.
Le format de réponse JSON a également été normalisé. En v3, chaque réponse suit la structure suivante :
{
"data": {
"id": "...",
"type": "file",
"attributes": {
"last_analysis_stats": {
"malicious": 15,
"suspicious": 3,
"harmless": 0,
"undetected": 52,
"timeout": 1
}
},
"relationships": {}
}
}
Cette structure data / attributes / relationships est inspirée de la spécification JSON:API et facilite le parsing. Les statistiques d'analyse (last_analysis_stats) sont toujours au même endroit, quelle que soit la ressource interrogée. Les relations permettent de naviguer entre ressources liées : depuis un fichier, accéder aux URLs qui l'ont distributé, aux domaines contactés lors de l'exécution en sandbox, aux fichiers parents ou enfants.
Parmi les nouveautés majeures de la v3 : les graphes de relations (VirusTotal Graph), les commentaires et votes de la communauté, les collections d'IOC, et l'accès programmatique aux résultats de sandbox (comportements, captures réseau PCAP, captures d'écran d'exécution). Ces fonctionnalités sont accessibles via l'API v3 mais inexistantes en v2. Pour les équipes qui font du threat hunting ou de l'analyse de malware avancée, c'est une différence considérable.
Un autre changement important concerne l'identification des ressources. En v2, les URLs étaient passées directement en paramètre. En v3, une URL doit d'abord être encodée en base64 URL-safe (sans padding) pour former son identifiant. Cette nuance est source d'erreurs lors de la migration -- nous verrons dans les scripts comment la gérer proprement.
Authentification et limites selon votre abonnement
L'accès à l'API VirusTotal se fait via une clé API transmise dans l'en-tête HTTP x-apikey. Contrairement à l'ancienne v2 qui utilisait un paramètre GET, la v3 exige systématiquement cet en-tête. L'absence ou l'invalidité de la clé retourne une erreur 401 Unauthorized.
Pour obtenir votre clé API, créez un compte sur virustotal.com (gratuit), puis accédez à votre profil utilisateur. La clé est disponible dans la section "API key". Chaque compte dispose d'une clé unique de 64 caractères hexadécimaux. Ne la partagez jamais : elle est liée à votre compte et toute utilisation abusive vous sera imputée.
Les limites de l'API publique gratuite sont :
- 4 requêtes par minute (rate limit strict, au-delà : erreur 429)
- 500 requêtes par jour (quota journalier)
- Taille maximale de fichier : 32 Mo pour la soumission
- Pas d'accès aux résultats de sandbox avancés ni aux graphes de relations complexes
Les abonnements Premium (VirusTotal Intelligence, Enterprise) lèvent ces contraintes : des milliers de requêtes par minute, accès YARA rétroactif sur toute la base, Private Scanning (les fichiers soumis ne sont pas partagés), téléchargement de fichiers malveillants, et accès complet aux captures PCAP et comportements sandbox.
Bonnes pratiques de stockage de la clé API : ne jamais écrire la clé en dur dans le code source. Utilisez des variables d'environnement :
# Dans votre shell ou fichier .env
export VT_API_KEY="votre_cle_api_ici"
# Dans Python
import os
api_key = os.environ.get("VT_API_KEY")
if not api_key:
raise ValueError("VT_API_KEY non definie dans l environnement")
Pour les déploiements en production (scripts cron, conteneurs Docker, pipelines CI/CD), stockez la clé dans un gestionnaire de secrets : HashiCorp Vault, AWS Secrets Manager, ou les secrets Kubernetes. Un fichier .env sur le serveur est acceptable en environnement de développement, mais veillez à ce qu'il ne soit jamais commité dans Git (ajoutez .env à votre .gitignore).
Si vous devez partager des scripts avec votre équipe, utilisez des variables de substitution et documentez clairement quelle variable doit être définie. Un script qui échoue avec un message d'erreur explicite ("VT_API_KEY non définie") est bien plus sûr qu'un script avec la clé en dur que quelqu'un copierait dans un dépôt public par inadvertance.
Endpoints principaux de l'API v3 : référence pratique
L'API v3 de VirusTotal expose une dizaine d'endpoints principaux. Voici ceux que vous utiliserez le plus fréquemment en contexte SOC, avec leurs paramètres et la structure des réponses.
GET /api/v3/files/{id} -- Rapport sur un fichier par son hash. L'identifiant {id} peut être un MD5, SHA1 ou SHA256 (VirusTotal normalise automatiquement). C'est l'endpoint le plus utilisé : vous fournissez le hash d'un fichier suspect extrait des logs de votre EDR ou de votre SIEM, et vous obtenez le verdict de 70+ moteurs ainsi que les métadonnées du fichier (taille, type, noms associés, première soumission).
POST /api/v3/files -- Soumettre un fichier à l'analyse. Le fichier est envoyé en multipart/form-data. VirusTotal retourne un objet d'analyse avec un ID unique. Vous pouvez ensuite interroger GET /api/v3/analyses/{id} pour récupérer le statut (queued, in-progress, completed) jusqu'à ce que l'analyse soit terminée. Pour les fichiers de plus de 32 Mo, un endpoint spécifique fournit une URL de téléchargement avec upload direct.
GET /api/v3/urls/{id} -- Rapport sur une URL. L'identifiant est la représentation base64 URL-safe (sans padding) de l'URL normalisée. En Python : import base64; url_id = base64.urlsafe_b64encode(url.encode()).decode().strip("="). La réponse inclut les verdicts antivirus, les métadonnées HTTP (code de statut, headers), et la catégorisation de l'URL.
POST /api/v3/urls -- Soumettre une URL pour analyse. Envoyez l'URL en form-data avec le champ url. VirusTotal retourne un ID d'analyse que vous pouvez suivre avec l'endpoint /analyses/{id}.
GET /api/v3/domains/{domain} -- Rapport sur un domaine. Retourne les résultats des moteurs de catégorisation, les enregistrements DNS historiques, les certificats TLS associés, les relations avec des fichiers et URLs malveillants connus. Très utile pour évaluer rapidement si un domaine apparaissant dans vos logs est connu comme malveillant.
GET /api/v3/ip_addresses/{ip} -- Rapport sur une adresse IP. Structure similaire aux domaines : verdicts, whois, ASN, country, et relations avec des indicateurs malveillants. Pour une adresse IP IPv6, passez l'adresse telle quelle (pas d'encodage particulier requis).
GET /api/v3/analyses/{id} -- Statut et résultat d'une analyse en cours. L'attribut status peut valoir queued, in-progress ou completed. Une fois l'état completed atteint, les attributs stats et results contiennent les verdicts de chaque moteur.
Tous ces endpoints acceptent le paramètre query ?relationships={type} pour inclure des relations dans la réponse, et certains supportent la pagination via ?cursor= et ?limit= pour les collections. L'en-tête de réponse X-RateLimit-Remaining indique le nombre de requêtes restantes dans la fenêtre courante -- pensez à le lire pour adapter dynamiquement votre throttling.
Script Python -- analyse d'un hash de fichier
Voici un script Python complet et annoté pour interroger le rapport d'un fichier à partir de son hash SHA256. Ce script gère les erreurs API, affiche un résumé lisible, et peut être intégré directement dans un pipeline d'enrichissement d'alertes.
#!/usr/bin/env python3
# vt_hash_lookup.py : Interroge VirusTotal pour un hash de fichier.
# Usage : python3 vt_hash_lookup.py SHA256_HASH
import os
import sys
import requests
import time
VT_API_URL = "https://www.virustotal.com/api/v3"
API_KEY = os.environ.get("VT_API_KEY")
if not API_KEY:
print("[ERREUR] Variable VT_API_KEY non definie.", file=sys.stderr)
sys.exit(1)
def get_file_report(file_hash):
headers = {"x-apikey": API_KEY}
url = f"{VT_API_URL}/files/{file_hash}"
try:
response = requests.get(url, headers=headers, timeout=30)
except requests.exceptions.ConnectionError as e:
print(f"[ERREUR] Connexion impossible : {e}", file=sys.stderr)
sys.exit(1)
if response.status_code == 404:
print(f"[INFO] Hash inconnu de VirusTotal (jamais soumis).")
return {}
if response.status_code == 429:
print("[WARN] Rate limit. Pause 15s...")
time.sleep(15)
return get_file_report(file_hash)
if response.status_code == 401:
print("[ERREUR] Cle API invalide.", file=sys.stderr)
sys.exit(1)
response.raise_for_status()
return response.json()
def afficher_rapport(data, file_hash):
if not data:
return
attrs = data.get("data", {}).get("attributes", {})
stats = attrs.get("last_analysis_stats", {})
malicious = stats.get("malicious", 0)
suspicious = stats.get("suspicious", 0)
harmless = stats.get("harmless", 0)
undetected = stats.get("undetected", 0)
total = sum(stats.values())
print(f"=== Rapport VirusTotal : {file_hash} ===")
print(f" Malveillant : {malicious}/{total}")
print(f" Suspect : {suspicious}/{total}")
print(f" Inoffensif : {harmless}/{total}")
print(f" Non detecte : {undetected}/{total}")
if malicious >= 5:
verdict = "MALVEILLANT -- escalade recommandee"
elif malicious > 0 or suspicious >= 3:
verdict = "SUSPECT -- investigation manuelle requise"
else:
verdict = "PROPRE (selon les moteurs disponibles)"
print(f" Verdict : {verdict}")
names = attrs.get("meaningful_name", attrs.get("names", ["inconnu"]))
if isinstance(names, list):
names = names[0] if names else "inconnu"
print(f" Nom fichier : {names}")
print(f" Type MIME : {attrs.get('type_description', 'inconnu')}")
print(f" Taille : {attrs.get('size', 0)} octets")
first_seen = attrs.get("first_submission_date", 0)
if first_seen:
from datetime import datetime
print(f" 1ere soumission : {datetime.utcfromtimestamp(first_seen).strftime('%Y-%m-%d %H:%M UTC')}")
if __name__ == "__main__":
if len(sys.argv) < 2:
print(f"Usage : {sys.argv[0]} <hash>")
sys.exit(1)
file_hash = sys.argv[1].strip().lower()
data = get_file_report(file_hash)
afficher_rapport(data, file_hash)
Quelques points importants sur ce script : le retry automatique sur le code 429 avec un sleep de 15 secondes évite les interruptions lors d'utilisations répétées. La logique de verdict avec un seuil à 5 moteurs est configurable selon votre contexte -- certains SOC préfèrent agir dès 1 moteur (zero-trust), d'autres fixent le seuil à 10 pour réduire les faux positifs. Adaptez ce paramètre à votre politique de sécurité. La gestion du code 404 est essentielle : un hash inconnu de VirusTotal n'est pas forcément inoffensif -- ce peut être un malware très récent ou custom qui n'a jamais été soumis.
Script Python -- soumission d'un fichier et attente du résultat
Lorsque vous disposez d'un fichier suspect et pas seulement de son hash, vous pouvez le soumettre directement à VirusTotal pour qu'il soit analysé. Le processus est asynchrone : la soumission retourne un ID d'analyse, et vous devez poller l'endpoint /analyses/{id} jusqu'à ce que le statut passe à completed.
#!/usr/bin/env python3
# vt_submit_file.py : Soumet un fichier a VirusTotal et attend le resultat.
# Usage : python3 vt_submit_file.py CHEMIN_FICHIER
# ATTENTION : Ne soumettez jamais de documents internes sensibles !
import os
import sys
import time
import requests
VT_API_URL = "https://www.virustotal.com/api/v3"
API_KEY = os.environ.get("VT_API_KEY")
POLL_INTERVAL = 20 # secondes entre deux verifications
MAX_WAIT = 300 # attente maximale (5 minutes)
def submit_file(filepath):
headers = {"x-apikey": API_KEY}
with open(filepath, "rb") as f:
files = {"file": (os.path.basename(filepath), f, "application/octet-stream")}
response = requests.post(f"{VT_API_URL}/files", headers=headers,
files=files, timeout=120)
response.raise_for_status()
analysis_id = response.json()["data"]["id"]
print(f"[OK] Soumis. ID analyse : {analysis_id}")
return analysis_id
def poll_analysis(analysis_id):
headers = {"x-apikey": API_KEY}
url = f"{VT_API_URL}/analyses/{analysis_id}"
elapsed = 0
while elapsed < MAX_WAIT:
response = requests.get(url, headers=headers, timeout=30)
response.raise_for_status()
data = response.json()
status = data.get("data", {}).get("attributes", {}).get("status", "unknown")
print(f" [{elapsed}s] Statut : {status}")
if status == "completed":
return data
time.sleep(POLL_INTERVAL)
elapsed += POLL_INTERVAL
print("[WARN] Delai max atteint.")
return {}
if __name__ == "__main__":
if len(sys.argv) < 2:
print(f"Usage : {sys.argv[0]} <chemin_fichier>")
sys.exit(1)
filepath = sys.argv[1]
if not os.path.isfile(filepath):
print(f"[ERREUR] Fichier introuvable : {filepath}", file=sys.stderr)
sys.exit(1)
analysis_id = submit_file(filepath)
result = poll_analysis(analysis_id)
if result:
stats = result.get("data", {}).get("attributes", {}).get("stats", {})
print(f"=== Resultat final ===")
for k in ("malicious", "suspicious", "harmless", "undetected"):
print(f" {k:12} : {stats.get(k, 0)}")
La soumission utilise multipart/form-data avec le fichier en tant que champ file. Le timeout de 120 secondes sur la soumission est nécessaire pour les fichiers volumineux. Le polling toutes les 20 secondes est raisonnable pour l'API publique -- l'analyse d'un fichier prend généralement entre 30 secondes et 3 minutes selon la charge de la plateforme et le type de fichier. Les exécutables PE (Windows) passent souvent par une sandbox comportementale qui allonge le temps d'analyse. La limite de 5 minutes (MAX_WAIT) est configurable ; en cas de dépassement, relancez manuellement avec l'ID conservé.
Script Python -- analyse d'URLs en masse avec rate limiting intelligent
Le cas d'usage le plus fréquent en SOC est l'analyse d'une liste d'IOC provenant d'un flux de threat intelligence ou d'une alerte SIEM. Voici un script qui gère une liste d'URLs avec backoff exponentiel, cache des résultats, et export JSON.
#!/usr/bin/env python3
# vt_bulk_urls.py : Analyse une liste d'URLs via VirusTotal API v3.
# Usage : python3 vt_bulk_urls.py urls.txt resultats.json
import os
import sys
import json
import base64
import time
import requests
from datetime import datetime
VT_API_URL = "https://www.virustotal.com/api/v3"
API_KEY = os.environ.get("VT_API_KEY")
RATE_LIMIT_DELAY = 16 # secondes (API publique : max 4 req/min)
def encode_url(url):
return base64.urlsafe_b64encode(url.encode()).decode().rstrip("=")
def get_url_report(url, cache, max_retries=3):
url_id = encode_url(url.strip())
if url_id in cache:
print(f" [CACHE] {url}")
return cache[url_id]
headers = {"x-apikey": API_KEY}
endpoint = f"{VT_API_URL}/urls/{url_id}"
for attempt in range(max_retries):
try:
response = requests.get(endpoint, headers=headers, timeout=30)
if response.status_code == 429:
wait = RATE_LIMIT_DELAY * (2 ** attempt)
print(f" [429] Pause {wait}s (tentative {attempt+1})")
time.sleep(wait)
continue
if response.status_code == 404:
result = {"url": url, "status": "unknown", "malicious": 0, "total": 0}
cache[url_id] = result
return result
response.raise_for_status()
data = response.json()
attrs = data.get("data", {}).get("attributes", {})
stats = attrs.get("last_analysis_stats", {})
result = {
"url": url,
"status": "analysed",
"malicious": stats.get("malicious", 0),
"suspicious": stats.get("suspicious", 0),
"harmless": stats.get("harmless", 0),
"undetected": stats.get("undetected", 0),
"total": sum(stats.values()),
"categories": attrs.get("categories", {}),
"last_analysis_date": attrs.get("last_analysis_date", 0),
}
cache[url_id] = result
return result
except requests.exceptions.RequestException as e:
print(f" [ERREUR] {url} : {e}")
time.sleep(RATE_LIMIT_DELAY)
return {"url": url, "status": "error", "malicious": 0, "total": 0}
if __name__ == "__main__":
if len(sys.argv) < 3:
print(f"Usage : {sys.argv[0]} <urls.txt> <output.json>")
sys.exit(1)
with open(sys.argv[1]) as f:
urls = [l.strip() for l in f if l.strip() and not l.startswith("#")]
print(f"[INFO] {len(urls)} URLs a analyser (delai : {RATE_LIMIT_DELAY}s/requete)")
cache, results = {}, []
for i, url in enumerate(urls, 1):
print(f"[{i}/{len(urls)}] {url}")
result = get_url_report(url, cache)
results.append(result)
if result.get("malicious", 0) >= 3:
print(f" *** ALERTE : {result['malicious']} moteurs positifs ***")
time.sleep(RATE_LIMIT_DELAY)
with open(sys.argv[2], "w") as f:
json.dump({
"generated_at": datetime.utcnow().isoformat() + "Z",
"total_urls": len(results),
"malicious_urls": sum(1 for r in results if r.get("malicious", 0) >= 3),
"results": results
}, f, indent=2, ensure_ascii=False)
mal = sum(1 for r in results if r.get("malicious", 0) >= 3)
print(f"[OK] {mal}/{len(results)} URLs malveillantes -- resultats dans {sys.argv[2]}")
Le cache en mémoire évite de requêter deux fois la même URL dans une même session, ce qui est courant lorsque plusieurs alertes référencent le même domaine. Pour un cache persistant entre exécutions (cas des scripts cron quotidiens), sérialisez le cache dans un fichier JSON ou une base Redis. Le délai de 16 secondes entre requêtes garantit de rester sous la limite de 4 req/min de l'API publique. Avec l'API Premium, vous pouvez réduire ce délai à 0.1 seconde selon votre quota contractuel.
Enrichissement automatisé des alertes SOC
L'intégration de VirusTotal dans le workflow SOC prend tout son sens lorsqu'elle est automatisée de bout en bout. Le scénario typique : votre SIEM détecte un événement suspect (exécution d'un processus avec un hash inconnu, connexion vers une IP rare, accès à un domaine jamais vu), et déclenche automatiquement un enrichissement VirusTotal avant même qu'un analyste ouvre le ticket.
Voici le pipeline recommandé :
- Extraction des IOC : le SIEM extrait le hash, l'IP ou le domaine de l'alerte via des règles de parsing (regex, champs structurés des logs EDR).
- Appel VirusTotal : un worker (script Python, fonction Lambda, ou playbook SOAR) interroge l'API v3 avec l'IOC extrait.
- Décision automatique basée sur un seuil : si le nombre de moteurs détectant l'IOC comme malveillant est supérieur à 5, le ticket passe automatiquement en priorité haute et l'analyste est notifié. Entre 1 et 5, le ticket est marqué "à investiguer". En dessous : enrichissement informatif sans changement de priorité.
- Injection du résultat dans le ticket : les métadonnées VirusTotal (stats de détection, nom du fichier, date de première soumission) sont ajoutées en commentaire structuré dans le système de ticketing (Jira, ServiceNow, TheHive).
- Corrélation avec d'autres sources : le pipeline peut enchaîner avec d'autres APIs de threat intelligence (Shodan pour les IPs, WHOIS pour les domaines, MalwareBazaar pour les hashes) pour enrichir davantage le contexte.
L'intégration avec les plateformes SOAR est particulièrement puissante. TheHive / Cortex dispose d'un analyzer VirusTotal natif : configurez-le avec votre clé API dans l'interface Cortex, et il sera disponible comme action dans tous vos playbooks TheHive. L'analyste peut lancer l'analyse d'un observable (hash, IP, domaine) en un clic, et le rapport structuré est injecté directement dans le case. Shuffle SOAR propose une app VirusTotal dans son marketplace : vous glissez-déposez les blocs "Get file report" ou "Scan URL" dans vos workflows visuels, sans écrire de code.
Pour Wazuh SIEM/XDR, l'intégration passe par les active responses et les custom integrations. Wazuh peut appeler un script Python lors du déclenchement d'une règle et injecter le résultat comme champ supplémentaire dans l'alerte Elasticsearch, visible directement dans le dashboard Kibana/OpenSearch.
Un point critique souvent négligé est la gestion de la charge. En cas de pic d'alertes (incident majeur, campagne de malware en cours), votre pipeline peut générer des centaines de requêtes en quelques minutes et dépasser les quotas VirusTotal. Mettez en place une file d'attente (Redis Queue, Celery, ou simplement un fichier FIFO) avec des workers qui consomment à un rythme respectant le rate limit. Priorisez les requêtes selon la criticité de l'alerte source : un hash signalé par l'EDR sur un serveur de production passe avant une URL extraite d'un log web.
Confidentialité et précautions essentielles avant soumission
VirusTotal est un service public, et cette caractéristique a des implications sérieuses en matière de confidentialité que beaucoup d'équipes ignorent jusqu'à ce qu'un incident se produise. Voici les règles absolues à respecter.
Règle n°1 : ne jamais soumettre de fichiers contenant des données sensibles. Tout fichier soumis à VirusTotal est partagé avec les partenaires antivirus de la plateforme et peut potentiellement être téléchargé par n'importe quel abonné Premium. Si vous soumettez un document Word contenant des données client, des contrats, des informations RH ou des configurations système avec des mots de passe, ces données deviennent accessibles à des tiers. Des incidents réels ont impliqué des organisations qui soumettaient leurs propres documents internes, révélant leurs données à des concurrents ou acteurs malveillants.
Règle n°2 : pour les données sensibles, soumettez uniquement le hash, pas le fichier. Le hash SHA256 d'un fichier ne révèle rien de son contenu. Calculez le hash localement (sha256sum fichier.exe sous Linux, Get-FileHash sous PowerShell), et interrogez uniquement le hash via GET /api/v3/files/{sha256}. Vous obtenez le verdict sans exposer les données.
Règle n°3 : l'abonnement Enterprise avec Private Scanning est obligatoire si vous devez soumettre des fichiers en environnement réglementé. Le Private Scanning garantit que les fichiers soumis ne sont pas partagés avec les partenaires et ne sont pas visibles dans les recherches publiques. C'est la seule option acceptable pour les environnements soumis au RGPD, HIPAA, ou aux réglementations sectorielles (finance, défense). Les scanners de Nessus et Greenbone proposent une logique similaire pour les rapports de vulnérabilités -- les données sensibles ne quittent jamais votre périmètre.
Règle n°4 : attention aux hash connus. Si vous soumettez le hash d'un fichier légitime et connu (par exemple, un binaire Windows standard), votre requête sera corrélée à votre compte API. Des acteurs malveillants sophistiqués ont déjà utilisé VirusTotal pour détecter si leurs outils étaient soumis à l'analyse. Ce scénario est rare mais documenté dans les rapports de threat intelligence.
Pour les environnements industriels ou OT (Operational Technology), la prudence est maximale : les firmwares de contrôleurs industriels, les configurations de PLC ou les captures réseau SCADA ne doivent jamais être soumis à VirusTotal. Les implications opérationnelles et sécuritaires d'une fuite de ces données dépassent largement la valeur du verdict antivirus.
Alternatives à VirusTotal : quand utiliser quoi
VirusTotal est l'outil de référence, mais il n'est pas toujours le meilleur choix selon le contexte. Voici les principales alternatives et leurs cas d'usage spécifiques.
MalwareBazaar (abuse.ch) est une base de données publique de malwares maintenue par la communauté de sécurité. Son API est gratuite, sans limite de requêtes (usage raisonnable), et spécialisée dans les hashes de malwares connus avec leurs tags (famille de malware, type, campagne associée). Utilisez MalwareBazaar pour télécharger des samples à analyser en lab, ou pour vérifier rapidement si un hash appartient à une famille connue. L'endpoint POST https://mb-api.abuse.ch/api/v1/ avec le paramètre query=get_info et le hash retourne les informations de la famille en JSON. Combinée avec VirusTotal, elle enrichit le contexte avec des informations de campagne.
Hybrid Analysis propose une sandbox gratuite avec des quotas généreux et des rapports comportementaux détaillés. Contrairement à VirusTotal qui agrège des résultats statiques de nombreux moteurs, Hybrid Analysis exécute réellement le fichier dans une VM Windows ou Linux et capture tous les comportements : appels système, connexions réseau, modifications du registre, injection de processus. Son API v2 est accessible gratuitement avec un compte et permet de soumettre des fichiers et de récupérer les rapports comportementaux en JSON. Utilisez Hybrid Analysis quand la détection statique VirusTotal est ambiguë et que vous avez besoin d'une analyse dynamique.
ANY.RUN est un service de sandbox interactif qui permet d'observer l'exécution d'un malware en temps réel dans un navigateur, en interagissant avec la VM (cliquer, remplir des formulaires, attendre un timer). Son API est disponible dans les plans payants. C'est l'outil de choix pour les analyses complexes de malwares multi-étapes qui nécessitent une interaction utilisateur (macros Office qui attendent un clic, droppers en plusieurs phases).
Intezer Analyze se distingue par son approche de "Code DNA" : au lieu de comparer les signatures, Intezer analyse les fragments de code réutilisés entre malwares pour identifier la famille et les outils de l'attaquant. Très efficace pour les malwares polymorphiques qui changent de hash à chaque compilation mais réutilisent des bibliothèques ou des fonctions connues. Son API REST est disponible avec un abonnement.
Quand utiliser quoi :
- Hash connu, vérification rapide : VirusTotal d'abord, MalwareBazaar en complément pour la famille du malware
- Fichier inconnu, pas de données sensibles : soumettre à VirusTotal et Hybrid Analysis en parallèle
- Analyse comportementale approfondie : ANY.RUN pour les malwares interactifs, Hybrid Analysis pour le batch automatisé
- Attribution et threat hunting : Intezer pour la génétique du code, VirusTotal Intelligence pour la recherche YARA rétroactive
- Données sensibles ou environnement réglementé : VirusTotal Enterprise Private Scanning uniquement, ou sandbox on-premise (Cuckoo Sandbox, CAPE)
À retenir
- L'API VirusTotal v3 utilise un format JSON unifié (
data/attributes/relationships) et requiert l'en-tête HTTPx-apikey-- stocker la clé uniquement en variable d'environnement, jamais en dur dans le code source. - L'API publique est limitée à 4 req/min et 500 req/jour -- implémenter un délai de 16 secondes entre requêtes et un backoff exponentiel sur les erreurs 429 pour éviter les interruptions de pipeline.
- Ne jamais soumettre de fichiers contenant des données sensibles -- soumettre uniquement le hash SHA256 pour les environnements réglementés, ou utiliser le Private Scanning Enterprise.
- Un seuil de 5 moteurs détectant un IOC comme malveillant est une bonne valeur de départ pour l'escalade automatique en SOC, mais doit être calibré selon votre contexte (taux de faux positifs, criticité des assets surveillés).
- VirusTotal est complémentaire, pas suffisant seul : combinez avec MalwareBazaar (familles de malwares), Hybrid Analysis (analyse comportementale dynamique), et des sources de threat intelligence structurées pour un enrichissement complet.
Questions fréquentes sur VirusTotal API
Quelle est la différence entre l'API publique et l'API Premium de VirusTotal ?
L'API publique est gratuite et limitée à 4 requêtes par minute et 500 par jour. Elle donne accès aux rapports d'analyse statique (verdicts antivirus, métadonnées de base) mais pas aux résultats de sandbox comportementaux complets ni aux graphes de relations avancés. L'API Premium (VirusTotal Intelligence) lève ces limites avec des quotas contractuels allant jusqu'à plusieurs milliers de requêtes par minute, ajoute l'accès YARA rétroactif sur toute la base, le Private Scanning (fichiers non partagés), le téléchargement de samples, et les captures PCAP des analyses sandbox. Pour un SOC traitant plus de 500 alertes par jour, l'abonnement Premium est rapidement justifié par le gain de productivité et la profondeur d'analyse.
Comment gérer le rate limiting de VirusTotal dans un script Python sans bloquer le pipeline ?
La bonne approche est d'implémenter un délai fixe de 16 secondes entre chaque requête (légèrement supérieur au minimum imposé par la limite de 4 req/min) et un backoff exponentiel en cas de réponse 429 : au premier retry, attendez 16 secondes ; au deuxième, 32 secondes ; au troisième, 64 secondes. Pour les pipelines à fort volume, utilisez une architecture asynchrone avec une file d'attente (Celery + Redis) où un worker dédié consomme les requêtes à un rythme contrôlé, sans bloquer les processus métier en aval. Lisez aussi l'en-tête X-RateLimit-Remaining retourné par l'API pour ajuster dynamiquement le délai entre requêtes.
Un hash inconnu de VirusTotal (réponse 404) signifie-t-il que le fichier est inoffensif ?
Non, absolument pas. Un hash inconnu de VirusTotal peut indiquer un malware très récent (zero-day ou campagne ciblée débutant), un outil custom développé spécifiquement pour attaquer votre organisation, ou simplement un fichier légitime jamais soumis à la plateforme. Dans un contexte SOC, un hash inconnu doit déclencher une investigation complémentaire : analyse comportementale en sandbox (Hybrid Analysis, ANY.RUN), examen des métadonnées du fichier (date de création, chemin d'exécution, processus parent), et corrélation avec d'autres IOC de l'alerte. Ne jamais considérer "inconnu de VirusTotal" comme synonyme de "sûr".
Comment intégrer VirusTotal dans un workflow TheHive/Cortex ?
Cortex, le moteur d'analyse de TheHive, dispose d'un analyzer VirusTotal v3 natif dans son catalogue. Depuis l'interface Cortex, accédez à "Analyzers", recherchez "VirusTotal", et configurez l'analyzer avec votre clé API dans le champ key et les paramètres optionnels (seuil de détection pour le verdict, proxy si nécessaire). Une fois activé, les observables de type "hash", "ip", "domain" et "url" dans un case TheHive peuvent être enrichis en un clic via ce analyzer. Le rapport JSON structuré est automatiquement rattaché à l'observable. Pour l'automatisation complète, configurez un responder ou un playbook TheHive qui déclenche l'analyzer automatiquement lors de la création d'un observable.
Besoin d'automatiser votre analyse de menaces ?
Ayi NEDJIMI accompagne les équipes SOC dans l'automatisation de l'enrichissement des alertes, l'intégration de VirusTotal et d'autres sources de threat intelligence dans vos pipelines SIEM/SOAR, et la réduction du temps de réponse aux incidents.
Demander un devis gratuitÀ propos de l'auteur
Ayi NEDJIMI
Auditeur Senior Cybersécurité & Consultant IA
Expert Judiciaire — Cour d'Appel de Paris
Habilitation Confidentiel Défense
ayi@ayinedjimi-consultants.fr
Ayi NEDJIMI est un vétéran de la cybersécurité avec plus de 25 ans d'expérience sur des missions critiques. Ancien développeur Microsoft à Redmond sur le module GINA (Windows NT4) et co-auteur de la version française du guide de sécurité Windows NT4 pour la NSA.
À la tête d'Ayi NEDJIMI Consultants, il réalise des audits Lead Auditor ISO 42001 et ISO 27001, des pentests d'infrastructures critiques, du forensics et des missions de conformité NIS2 / AI Act.
Conférencier international (Europe & US), il a formé plus de 10 000 professionnels.
Domaines d'expertise
Ressources & Outils de l'auteur
Articles connexes
Comparatif EDR 2026 : CrowdStrike vs SentinelOne vs Microsoft Defender
Comparatif complet des trois principaux EDR en 2026 : CrowdStrike Falcon, SentinelOne Singularity et Microsoft Defender for Endpoint. Performances, prix, intégration SIEM et recommandations par profil.
Prometheus et Alertmanager 2026 : Monitoring et Alerting Sécurité
Guide complet pour déployer Prometheus et Alertmanager dans un contexte de sécurité : exporters, règles d'alerte critiques, intégration Slack/PagerDuty et dashboards Grafana.
Canary Tokens : Guide Complet des Pièges Numériques pour Détecter les Intrusions
Guide complet Canary Tokens 2026 : types de tokens (URL, Word, AWS, DNS, SSH, kubeconfig), création sur canarytokens.org, stratégies de déploiement dans les partages réseau et postes, self-hosting Docker et intégration SIEM Wazuh.
Un projet cybersécurité ? Parlons-en.
Pentest, conformité NIS 2, ISO 27001, audit IA, RSSI externalisé… nos experts répondent sous 24h pour évaluer votre besoin et vous proposer un accompagnement sur mesure.
Commentaires
Aucun commentaire pour le moment. Soyez le premier à commenter !
Laisser un commentaire