Gutem/malshare-sdk

GitHub: Gutem/malshare-sdk

MalShare API 的跨平台 JavaScript/TypeScript 客户端,方便开发者与安全研究人员检索、下载和管理恶意软件样本。

Stars: 0 | Forks: 0

# MalShare SDK 针对 [MalShare](https://malshare.com) API 的 JavaScript/TypeScript 客户端 —— 一个拥有 **超过 100 万个样本** 的免费恶意软件样本存储库。适用于 **Bun**、**Node.js**、**Deno** 和 **Cloudflare Workers**。零依赖。 [![npm version](https://img.shields.io/npm/v/malshare-sdk)](https://www.npmjs.com/package/malshare-sdk) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) [![Bun compatible](https://img.shields.io/badge/Bun-%3E%3D1.0.0-orange)](https://bun.sh) [![Tests](https://img.shields.io/badge/tests-48%20pass-green)] [![Zero deps](https://img.shields.io/badge/dependencies-0-brightgreen)] ## 快速开始 ``` bun add malshare-sdk # or: npm install malshare-sdk ``` 在 [malshare.com/register.php](https://malshare.com/register.php) 获取免费 API key。免费账户每天可获得 **2,000 次 API 调用**。 ``` export MALSHARE_KEY=your-key-here ``` ``` import { MalShare } from 'malshare-sdk'; const ms = new MalShare(process.env.MALSHARE_KEY); // Latest sample hashes (24h) const hashes = await ms.listSamples(); console.log(`${hashes.length} samples`); // File metadata const info = await ms.details('46faab8ab153...'); // → { MD5, SHA1, SHA256, F_TYPE: 'PE32 executable', F_SIZE: 123456, ... } // Download a sample (live malware! handle with care) const bytes = await ms.download('46faab8ab153...'); await Bun.write('/tmp/malware.bin', bytes); ``` ## CLI 用法 ``` # 全局安装 bun install -g malshare-sdk # 列出今日样本 malshare list # 样本详情 malshare info 46faab8ab153fae6e80e7cca38eab363075bb524edd79e42269217a083628f09 # 下载到文件 malshare save 46faab8ab153... ./malware.zip # 配额检查 malshare quota # → 每日限额: 2000 # → 剩余: 1523 # 按文件类型搜索 malshare type "PE32 executable" ``` ## API 参考 ### 构造函数 ``` new MalShare(apiKey, config?) ``` | 参数 | 类型 | 默认值 | 描述 | |-------|------|---------|-------------| | `apiKey` | `string` | *必填* | 来自 malshare.com/register.php 的 API key | | `config.baseUrl` | `string` | `https://malshare.com/api.php` | API endpoint(支持镜像) | | `config.timeoutMs` | `number` | `60000` | 请求超时时间 (AbortController) | | `config.fetch` | `function` | `globalThis.fetch` | 自定义 fetch (CF Workers, 代理等) | ### 样本列表(5 个方法) | 方法 | 返回值 | 描述 | |--------|---------|-------------| | `listSamples()` | `string[]` | 过去 24 小时内的 SHA256 哈希值 | | `listSamplesRaw()` | `string` | 同上,原始文本(每行一个) | | `listSources()` | `object[]` | 样本来源及其数量 `{source, count}` | | `listFileNames()` | `string[]` | 原始文件名 | | `listTypes()` | `object[]` | 文件类型及其数量 `{type, count}` | ### 样本信息与搜索(4 个方法) | 方法 | 返回值 | 描述 | |--------|---------|-------------| | `details(hash)` | `FileDetails \| null` | 完整元数据:MD5, SHA1, SHA256, 类型, 大小, 名称, 来源, 首次/最后出现时间 | | `hashLookup(hashes)` | `FileDetails[]` | 通过 POST 进行批量查询(最多约 100 个哈希值) | | `search(query)` | `string \| object` | 按哈希值、来源或文件名搜索 | | `searchByType(type)` | `string[]` | 过去 24 小时内按文件类型搜索哈希值 | ### 下载与上传(5 个方法) | 方法 | 返回值 | 描述 | |--------|---------|-------------| | `download(hash)` | `Uint8Array` | 原始样本字节 ⚠️ 活体恶意软件 | | `downloadTo(hash, path)` | `{path, size}` | 下载并保存到磁盘 | | `upload(file, name?)` | `UploadResult` | 上传样本(临时增加配额) | | `downloadUrl(url, recursive?)` | `DownloadUrlResult` | 提交 URL 供 MalShare 抓取并添加 | | `downloadUrlStatus(guid)` | `DownloadUrlStatus` | 检查 URL 下载任务进度 | ### 配额(1 个方法) | 方法 | 返回值 | 描述 | |--------|---------|-------------| | `getQuota()` | `QuotaInfo` | `{limit, remaining}` | ### 类型定义 ``` interface FileDetails { MD5: string; // 32-char hex SHA1: string; // 40-char hex SHA256: string; // 64-char hex F_TYPE: string; // 'PE32 executable', 'ELF 64-bit', 'PDF document'... F_SIZE: number; // bytes F_NAME?: string; // original filename SOURCES: string[]; // ['US', 'DE', 'JP', ...] FIRST_SEEN?: string; // ISO timestamp LAST_SEEN?: string; } interface QuotaInfo { limit: number; // allocated per day (default: 2000) remaining: number; // left today } interface UploadResult { status: 'OK' | 'ERROR'; guid?: string; // upload tracking GUID error?: string; } interface DownloadUrlResult { status: 'OK' | 'ERROR'; guid?: string; // download task GUID error?: string; } interface DownloadUrlStatus { status: 'missing' | 'pending' | 'processing' | 'finished'; guid?: string; } ``` ## 使用模式 ### 按类型批量下载 ``` const ms = new MalShare(process.env.MALSHARE_KEY); // Get all PE32 samples from today const peHashes = await ms.searchByType('PE32 executable'); console.log(`${peHashes.length} PE32 samples today`); // Download first 10 (be careful!) for (const hash of peHashes.slice(0, 10)) { const details = await ms.details(hash); const bytes = await ms.download(hash); await Bun.write(`./samples/${hash}.bin`, bytes); console.log(`Downloaded: ${details.F_NAME || hash} (${details.F_SIZE} bytes)`); } ``` ### 每日配额监控 ``` const ms = new MalShare(process.env.MALSHARE_KEY); // Check before heavy operations const { limit, remaining } = await ms.getQuota(); if (remaining < 100) { console.warn(`Low quota: ${remaining}/${limit} — reset at midnight UTC`); } const used = (1 - remaining / limit) * 100; console.log(`Quota: ${remaining}/${limit} (${used.toFixed(1)}% used)`); ``` ### 批量哈希查询 ``` const ms = new MalShare(process.env.MALSHARE_KEY); // Look up up to 100 hashes at once const hashes = ['abc123...', 'def456...', /* ... up to ~100 */]; const results = await ms.hashLookup(hashes); for (const r of results) { console.log(`${r.SHA256?.substring(0, 12)} | ${r.F_TYPE} | ${r.F_NAME}`); } ``` ### 提交 URL 进行抓取 ``` const ms = new MalShare(process.env.MALSHARE_KEY); // Submit a URL for MalShare to download const { guid } = await ms.downloadUrl('http://evil.com/malware.exe'); // Poll until finished let status = await ms.downloadUrlStatus(guid); while (status.status === 'pending' || status.status === 'processing') { await new Promise(r => setTimeout(r, 5000)); status = await ms.downloadUrlStatus(guid); } console.log('Task finished:', status.status); ``` ### Cloudflare Workers ``` import { MalShare } from 'malshare-sdk'; export default { async scheduled(event, env) { const ms = new MalShare(env.MALSHARE_KEY, { fetch: globalThis.fetch, // Workers-native fetch }); const hashes = await ms.listSamples(); console.log(`${hashes.length} new samples today`); } }; ``` ## 错误处理 所有方法在遇到 HTTP 错误 (4xx/5xx)、网络故障和超时时都会抛出异常。 ``` try { const info = await ms.details(hash); } catch (err) { if (err.message.includes('404')) { // Sample not found } else if (err.message.includes('429')) { // Rate limited — back off await new Promise(r => setTimeout(r, 60000)); } else if (err.name === 'AbortError') { // Timeout — retry with longer timeout } } ``` 对于未知的哈希值,`details()` 返回 `null`(不抛出异常)。 对于空响应,`listSamples()` 返回 `[]`。 对于未知类型,`searchByType()` 返回 `[]`。 ## 速率限制与合理使用 - 免费账户:**每天 2,000 次 API 调用**(UTC 午夜重置) - 上传样本会**临时增加**您的配额 - MalShare 是一个开源项目 —— 请尊重并合理使用 - 遵循:在收到 429 响应时处理 `Retry-After` header - 建议:每秒 1-2 个请求 ## 平台兼容性 | 平台 | 支持情况 | 备注 | |----------|---------|-------| | **Bun** | ✅ 完全支持 | `bun add malshare-sdk` | | **Node.js** | ✅ 完全支持 | `>=18.0.0` (全局 fetch) | | **Deno** | ✅ 完全支持 | `import { MalShare } from 'npm:malshare-sdk'` | | **Cloudflare Workers** | ✅ | 自定义 `fetch`,无 `downloadTo()` | | **Browser** | ✅ | `window.fetch`,无 `downloadTo()` | | **Bun compile** | ✅ | 使用 `bun build --compile` 生成单一二进制文件 | ## 安全性 - 样本以原始字节存储 —— 由您选择存储容器 - 密码保护的 zip 约定:`infected` (MalwareBazaar 标准) - 下载期间无网络请求(此 SDK 绝不会执行二进制文件) - API key:仅存储在环境变量中,切勿提交到代码库 ## 架构 ``` ┌──────────────────────────────────────────────┐ │ MalShare API │ │ malshare.com/api.php │ └──────────────────────────────────────────────┘ ▲ │ fetch() + AbortController ┌────────────────────┴─────────────────────────┐ │ MalShare class │ │ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │ │ │ Listing │ │ Info │ │ Download │ │ │ │ list*() │ │ details()│ │ download() │ │ │ │ │ │ hashLook │ │ downloadTo() │ │ │ │ │ │ search() │ │ upload() │ │ │ └──────────┘ └──────────┘ └──────────────┘ │ │ ┌──────────────────────────────────────┐ │ │ │ _request() — core │ │ │ │ URL params → fetch → parse → return │ │ │ └──────────────────────────────────────┘ │ └──────────────────────────────────────────────┘ ``` | 组件 | 职责 | |-----------|---------------| | `_request()` | 构建 URL,使用 AbortController 发起 fetch,解析响应 | | `MalShare` 类 | 公共 API 接口 —— 全部 14 个方法都委托给 `_request()` | | CLI (`cli.js`) | 轻量级封装:解析参数 → 调用 SDK → 格式化输出 | **设计决策**:参见 [ADR-001](docs/adr/001-architecture.md) (TBD)。 ## 测试 ``` # 单元测试(mock fetch,无需 API key) bun test # 集成测试(真实 API 调用) MALSHARE_KEY=your-key bun test tests/malshare.int.js ``` | 测试套件 | 测试数 | 覆盖范围 | |-------|-------|----------| | 单元测试 | 48 | 所有 14 个公共方法,错误边界,回归测试 | | 集成测试 | 14 | 真实 API:列表,详情,搜索,下载,配额 | | URL 构建 | 10 | 所有操作 + 参数组合 | ## 许可证 MIT © [gutem](https://github.com/gutem) MalShare 是由 [@mal_share](https://twitter.com/mal_share) 提供的免费社区服务。
标签:API客户端, CMS安全, DAST, JavaScript, MITM代理, TypeScript, 威胁情报, 安全插件, 开发者工具, 恶意软件分析, 数据可视化, 程序员工具, 自定义脚本