VirusTotal이 무료 API를 제공 — 파일 및 URL을 70개 이상의 안티바이러스 엔진으로 스캔
Source: Dev.to
VirusTotal은 파일과 URL을 동시에 70개 이상의 안티바이러스 엔진으로 스캔합니다. API는 하루 최대 500회 요청까지 무료입니다.
한 번의 스캔. 70개의 판정. 무료.
이야기
친구가 GitHub에서 도구를 다운로드했습니다. 백신 프로그램은 깨끗하다고 표시했지만, 한 엔진만으로는 충분하지 않다는 불안감이 있었습니다.
그들은 파일을 직접 VirusTotal에 업로드했습니다. 세 개의 엔진이 트로이목마로 표시했습니다. “깨끗한” 바이너리는 실제로 그들의 특정 백신이 탐지하지 못한 악성코드였습니다.
이제 그들은 모든 다운로드에 대해 이 검사를 자동화했습니다. 방법은 다음과 같습니다.
무료 API 키 받기
- 회원가입하기
- 프로필 → API 키 로 이동
- 키 복사 (무료 티어: 하루 500 조회, 분당 4 요청)
URL 스캔
import requests
import time
API_KEY = "your-api-key-here"
headers = {"x-apikey": API_KEY}
# Submit URL for scanning
url_to_scan = "https://example.com/suspicious-download"
response = requests.post(
"https://www.virustotal.com/api/v3/urls",
headers=headers,
data={"url": url_to_scan},
)
analysis_id = response.json()["data"]["id"]
print(f"Scan submitted: {analysis_id}")
# Wait for results
time.sleep(15)
# Get results
result = requests.get(
f"https://www.virustotal.com/api/v3/analyses/{analysis_id}",
headers=headers,
).json()
stats = result["data"]["attributes"]["stats"]
print(f"Malicious: {stats['malicious']}")
print(f"Suspicious: {stats['suspicious']}")
print(f"Clean: {stats['undetected']}")
print(f"Timeout: {stats['timeout']}")
파일 해시 확인
파일을 업로드하지 마세요—해시만 확인하면 됩니다. 더 빠르고 개인적입니다.
import hashlib
import requests
API_KEY = "your-api-key-here"
headers = {"x-apikey": API_KEY}
def check_file(filepath):
"""Check if a file is known malware by its SHA‑256 hash."""
# Calculate hash
sha256 = hashlib.sha256()
with open(filepath, "rb") as f:
for chunk in iter(lambda: f.read(8192), b""):
sha256.update(chunk)
file_hash = sha256.hexdigest()
# Query VirusTotal
response = requests.get(
f"https://www.virustotal.com/api/v3/files/{file_hash}",
headers=headers,
)
if response.status_code == 200:
attrs = response.json()["data"]["attributes"]
stats = attrs["last_analysis_stats"]
print(f"File: {filepath}")
print(f"SHA‑256: {file_hash}")
print(f"Detection: {stats['malicious']}/{sum(stats.values())} engines")
print(f"First seen: {attrs.get('first_submission_date', 'Unknown')}")
if stats["malicious"] > 0:
print("⚠ MALWARE DETECTED!")
# Show which engines flagged it
for engine, result in attrs["last_analysis_results"].items():
if result["category"] == "malicious":
print(f" └─ {engine}: {result['result']}")
else:
print("✓ File appears clean")
elif response.status_code == 404:
print("File not in VirusTotal database (never scanned)")
# Example usage
check_file("suspicious_file.exe")
도메인 스캔
도메인이 악성코드와 연관되어 있는지 확인합니다.
import requests
API_KEY = "your-api-key-here"
headers = {"x-apikey": API_KEY}
def check_domain(domain):
"""Check domain reputation on VirusTotal."""
response = requests.get(
f"https://www.virustotal.com/api/v3/domains/{domain}",
headers=headers,
)
if response.status_code == 200:
attrs = response.json()["data"]["attributes"]
stats = attrs.get("last_analysis_stats", {})
print(f"Domain: {domain}")
print(f"Malicious: {stats.get('malicious', 0)}")
print(f"Suspicious: {stats.get('suspicious', 0)}")
print(f"Clean: {stats.get('undetected', 0)}")
# WHOIS data
print(f"Registrar: {attrs.get('registrar', 'Unknown')}")
print(f"Created: {attrs.get('creation_date', 'Unknown')}")
else:
print(f"Could not retrieve data for {domain}")
# Example usage
check_domain("example.com")
배치 스캐너 — 여러 IOC 확인
import base64
import time
import requests
API_KEY = "your-api-key-here"
headers = {"x-apikey": API_KEY}
def batch_scan(iocs, ioc_type="url"):
"""Scan multiple indicators of compromise."""
results = []
for ioc in iocs:
if ioc_type == "url":
# URL ID is the base64url‑encoded URL (without padding)
url_id = base64.urlsafe_b64encode(ioc.encode()).decode().strip("=")
r = requests.get(
f"https://www.virustotal.com/api/v3/urls/{url_id}",
headers=headers,
)
elif ioc_type == "hash":
r = requests.get(
f"https://www.virustotal.com/api/v3/files/{ioc}",
headers=headers,
)
elif ioc_type == "ip":
r = requests.get(
f"https://www.virustotal.com/api/v3/ip_addresses/{ioc}",
headers=headers,
)
else:
print(f"Unsupported IOC type: {ioc_type}")
continue
if r.status_code == 200:
stats = r.json()["data"]["attributes"].get("last_analysis_stats", {})
mal = stats.get("malicious", 0)
status = "⚠ THREAT" if mal > 0 else "✓ Clean"
results.append({"ioc": ioc, "malicious": mal, "status": status})
else:
results.append({"ioc": ioc, "malicious": 0, "status": "? Not found"})
time.sleep(15) # Respect free‑tier rate limit
return results
# Example usage
iocs = [
"https://malicious.example.com",
"d41d8cd98f00b204e9800998ecf8427e", # example hash
"8.8.8.8",
]
for r in batch_scan(iocs, ioc_type="url"):
print(f"{r['status']}: {r['ioc']} (malicious engines: {r['malicious']})")
print(f"| {r['ioc']} | {r['malicious']} detections")
의심스러운 IP 확인
batch_scan(["8.8.8.8", "1.1.1.1"], ioc_type="ip")
구축할 수 있는 것
- Download scanner – 파일을 열기 전에 자동으로 모든 파일을 검사합니다
- Email security gateway – 첨부 파일과 링크를 스캔합니다
- Incident response tool – 위협 보고서에서 IOCs를 대량 검사합니다
- Browser extension backend – 악성 URL에 대해 사용자에게 경고합니다
- CI/CD security check – 배포 전에 빌드 아티팩트를 스캔합니다
무료 티어 제한
| 기능 | 무료 | 프리미엄 |
|---|---|---|
| 일일 조회 수 | 500 | 30,000+ |
| 분당 요청 수 | 4 | 720 |
| 파일 업로드 크기 | 32 MB | 650 MB |
| 헌팅 규칙 | 없음 | 있음 |
일일 500회 조회는 개인 보안 도구와 소규모 프로젝트에 충분히 관대합니다.
보안 도구를 만들고 있나요?
더 많은 무료 API 튜토리얼 및 개발자 도구는 제 GitHub에서 확인하세요.
