VirusTotal API Response JSON Format v3 dan Contoh Parsing

VirusTotal API v3 mengadopsi standar spesifikasi JSON:API secara penuh. Setiap respons sukses (status kode HTTP 200 OK) dibungkus dalam objek utama bernama data, yang memuat empat kunci hierarki primer: id (identifier objek), type (tipe entitas seperti file, url, domain, ip_address, atau analysis), links (tautan sumber daya), dan attributes (kontainer utama metadata hasil analisis keamanan).

Kunci paling krusial bagi analis SOC dan developer terletak pada attributes.last_analysis_stats yang menyediakan kalkulasi agregat deteksi vendor, serta attributes.last_analysis_results yang merinci vonis granular dari tiap-tiap mesin antivirus pihak ketiga.

Struktur Skema JSON VirusTotal API v3 (Contoh File Report)

Berikut adalah payload JSON nyata hasil kueri endpoint GET /api/v3/files/{hash} yang telah divalidasi sesuai spesifikasi produksi VirusTotal API v3:

{
  "data": {
    "id": "44d88612fea8a8f36de82e1278abb02f",
    "type": "file",
    "links": {
      "self": "https://www.virustotal.com/api/v3/files/44d88612fea8a8f36de82e1278abb02f"
    },
    "attributes": {
      "meaningful_name": "malware_sample.exe",
      "type_description": "Win32 EXE",
      "size": 68608,
      "md5": "44d88612fea8a8f36de82e1278abb02f",
      "sha1": "9292816912ec924513686fa3a48e2da3a2334ef5",
      "sha256": "275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f",
      "reputation": -42,
      "last_analysis_date": 1711929600,
      "times_submitted": 14,
      "last_analysis_stats": {
        "malicious": 58,
        "suspicious": 1,
        "undetected": 12,
        "harmless": 0,
        "timeout": 0,
        "confirmed-timeout": 0,
        "failure": 0,
        "type-unsupported": 2
      },
      "last_analysis_results": {
        "Kaspersky": {
          "category": "malicious",
          "result": "Trojan.Win32.Swizzor",
          "method": "blacklist",
          "engine_name": "Kaspersky",
          "engine_version": "21.0.1.45",
          "engine_update": "20260330"
        },
        "Microsoft": {
          "category": "malicious",
          "result": "Trojan:Win32/Wacatac.B!ml",
          "method": "blacklist",
          "engine_name": "Microsoft",
          "engine_version": "1.1.24030.1",
          "engine_update": "20260330"
        },
        "Google": {
          "category": "undetected",
          "result": null,
          "method": "blacklist",
          "engine_name": "Google Safe Browsing",
          "engine_version": "1.0",
          "engine_update": "20260330"
        }
      }
    }
  }
}

Hierarki dan Definisi Kunci Field JSON API v3

Memahami hierarki field sangat penting agar pipeline parser log otomatis di SIEM atau backend tidak mengalami galat KeyError atau membaca field yang salah interpretasi.

Path JSONTipe DataFungsi dan Keterangan
data.idStringIdentifier unik objek: MD5/SHA-256 untuk file, ID sandi base64 untuk URL, domain murni, atau alamat IPv4/IPv6.
data.typeStringMenentukan schema parser: file, url, domain, ip_address, atau analysis.
data.attributes.last_analysis_statsObjectKalkulator metrik total: merangkum jumlah engine pada kategori malicious, suspicious, undetected, dan harmless.
data.attributes.last_analysis_resultsObject (Map)Daftar objek asosiatif berindeks nama vendor (mis. Kaspersky, CrowdStrike, Sophos).
last_analysis_results.{vendor}.categoryStringStatus vonis vendor: bernilai malicious, suspicious, undetected, harmless, atau type-unsupported.
last_analysis_results.{vendor}.resultString | NullLabel deteksi ancaman/keluarga malware (contoh: Ransom:Win32/WannaCrypt). Bernilai null jika bersih/undetected.
data.attributes.reputationIntegerSkor reputasi crowdsourced dari komunitas VirusTotal (bisa bernilai negatif untuk sampel berbahaya).
data.attributes.last_analysis_dateInteger (Epoch)Timestamp waktu pemindaian terakhir dalam format detik Unix.

Format Payload URL Scan vs Analysis Queue Object

Saat mengirimkan URL baru atau file biner ke VirusTotal via HTTP POST, API tidak langsung mengembalikan hasil pemindaian akhir, melainkan objek tipe analysis yang berisi ID token antrean:

{
  "data": {
    "type": "analysis",
    "id": "dTFhMmM4MjY5NmIyODJhNGRmZjQ3MTAyMmFiNmExNzU6MTcxMTkyOTYwMA==",
    "links": {
      "self": "https://www.virustotal.com/api/v3/analyses/dTFhMmM4MjY5NmIyODJhNGRmZjQ3MTAyMmFiNmExNzU6MTcxMTkyOTYwMA=="
    }
  }
}

Status antrean tersebut harus dipantau secara polling pada endpoint GET /api/v3/analyses/{id} hingga field attributes.status beralih dari queued menjadi completed sebelum mengekstrak field stats.

Skrip Ekstraksi Data: Parsing JSON VirusTotal dengan Python

Gunakan implementasi Python berikut untuk membaca payload JSON VirusTotal secara aman tanpa memicu crash akibat key yang hilang (menggunakan pendekatan dict.get() defensif):

import requests

def parse_virustotal_report(resource_hash, api_key):
    url = f"https://www.virustotal.com/api/v3/files/{resource_hash}"
    headers = {
        "x-apikey": api_key,
        "Accept": "application/json"
    }
    
    response = requests.get(url, headers=headers)
    if response.status_code != 200:
        return {"error": f"HTTP {response.status_code}: {response.text}"}
        
    payload = response.json()
    attributes = payload.get("data", {}).get("attributes", {})
    stats = attributes.get("last_analysis_stats", {})
    results = attributes.get("last_analysis_results", {})
    
    # Ambil vendor yang mendeteksi malicious secara spesifik
    flagged_engines = []
    for engine, details in results.items():
        if details.get("category") == "malicious":
            flagged_engines.append({
                "engine": engine,
                "threat_label": details.get("result")
            })
            
    return {
        "sha256": attributes.get("sha256"),
        "file_size": attributes.get("size"),
        "positives": stats.get("malicious", 0),
        "total_engines": sum(stats.values()),
        "reputation": attributes.get("reputation", 0),
        "detections": flagged_engines
    }

# Eksekusi
# report = parse_virustotal_report("275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f", "YOUR_API_KEY")
# print(report)

Format Respons Galat (Error Schema)

Jika request gagal karena limitasi kuota (rate limit 4 requests/menit untuk API publik) atau kesalahan autentikasi API key, VirusTotal mengembalikan payload galat berskema berikut:

{
  "error": {
    "code": "QuotaExceededError",
    "message": "Quota exceeded for request: 4 per minute, you sent 5"
  }
}

Kode error umum yang wajib ditangani di layer aplikasi meliputi NotFoundError (HTTP 404 jika hash belum pernah terdaftar), AuthenticationRequiredError (HTTP 401 header x-apikey tidak valid), dan QuotaExceededError (HTTP 429 backoff throttling).