Socket
Book a DemoInstallSign in
Socket

@kdinisv/sql-scanner

Package Overview
Dependencies
Maintainers
1
Versions
12
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@kdinisv/sql-scanner

Smart SQL injection scanner with crawler and optional Playwright capture.

0.2.4
latest
Source
npmnpm
Version published
Weekly downloads
157
-81.79%
Maintainers
1
Weekly downloads
 
Created
Source

@kdinisv/sql-scanner

Лёгкий SDK для поиска SQL-инъекций в Node.js. Умеет точечно сканировать URL и выполнять «умное» сканирование с краулингом. Работает в ESM и CommonJS, типы включены. Поддерживает отчёты JSON/Markdown/CSV/JUnit и приоритизирует payload’ы (в т.ч. time/union PoC) по отпечатку СУБД.

— Node.js >= 18.17 — Типы: TypeScript – Опционально: Playwright для JS-страниц (захват сетевых запросов SPA)

Установка

npm i @kdinisv/sql-scanner
# (опционально) для SPA-страниц
npm i -D playwright

Быстрый старт (ESM)

import { SqlScanner } from "@kdinisv/sql-scanner";

const scanner = new SqlScanner();

const result = await scanner.scan({
  target: "https://example.com/search?q=test",
  method: "GET",
  enable: { query: true, error: true, boolean: true, time: false },
});

console.log(result.vulnerable, result.details);

Быстрый старт (CommonJS)

const { SqlScanner } = require("@kdinisv/sql-scanner");

(async () => {
  const scanner = new SqlScanner();
  const result = await scanner.scan({ target: "https://example.com?id=1" });
  console.log(result);
})();

«Умное» сканирование (краулер)

const smart = await scanner.smartScan({
  baseUrl: "https://example.com",
  maxDepth: 2,
  maxPages: 50,
  usePlaywright: true,
});
console.log(smart.crawledPages, smart.candidates.length, smart.sqli.length);

Краткое API

  • new SqlScanner(options?)

    • requestTimeoutMs?: number (по умолчанию 10000)
    • timeThresholdMs?: number для time-based (по умолчанию 2500)
    • headers?: Record<string,string>, cookies?: Record<string,string>
  • scan(input)

    • target: string, method?: "GET"|"POST"
    • jsonBody?: Record<string,unknown>
    • enable?: { query|path|form|json|header|cookie|error|boolean|time|union?: boolean }
    • payloads?: { error?: string[]; boolean?: { true:string; false:string; label?:string }[]; time?: { p:string; label?:string }[] }
    • onProgress?: (p: ScanProgress) => void
    • Возвращает: { vulnerable: boolean; details: Detail[] }
  • smartScan(options)

    • baseUrl: string, maxDepth?: number, maxPages?: number
    • sameOriginOnly?: boolean, usePlaywright?: boolean
    • crawlConcurrency?: number — параллельность HTML-краулинга (по умолчанию 4)
    • playwrightConcurrency?: number — число одновременных страниц Playwright (по умолчанию 2)
    • playwrightWaitMs?: number — ожидание XHR/fetch после загрузки, мс (по умолчанию 1000)
    • scanParallel?: number — параллельное сканирование кандидатов (по умолчанию 2)
    • techniques?: { error?: boolean; boolean?: boolean; time?: boolean }
    • onProgress?: (p: SmartScanProgress) => void
    • Возвращает: { crawledPages: number; candidates: DiscoveredTarget[]; sqli: ResultShape[] }

Возвращаемые данные

scan(input) → ResultShape

  • vulnerable: boolean — есть ли подтвержденные уязвимости среди проверок
  • details: Detail[] — записи по каждому проверенному «поинту/технике»
    • point: { kind: "query"|"path"|"form"|"json"|"header"|"cookie"; name: string; meta?: object }
    • technique: "error" | "boolean_truefalse" | "time"
    • payload: string — инъекция, использованная в проверке
    • vulnerable: boolean — результат конкретной проверки
    • responseMeta?: { status: number; elapsedMs?: number; len?: number; location?: string }
    • evidence?: string — краткая улика (фрагмент ошибки/метрика)
    • confirmations?: string[] — ярлыки подтверждений (например, "error_signature", а при error-based может добавляться отпечаток СУБД: "mysql"|"postgres"|"mssql"|"oracle"|"sqlite")
    • reproduce?: { curl: string[]; note?: string } — готовые примеры для воспроизведения (curl)
    • remediation?: string[] — краткие рекомендации по исправлению

Пример:

{
  "vulnerable": true,
  "details": [
    {
      "point": { "kind": "query", "name": "q" },
      "technique": "error",
      "payload": "' OR '1'='1",
      "vulnerable": true,
      "responseMeta": { "status": 200, "len": 12345, "elapsedMs": 120 },
      "evidence": "You have an error in your SQL syntax",
      "confirmations": ["error_signature"],
      "reproduce": {
        "curl": ["curl \"https://example.com/search?q=' OR '1'='1\""]
      },
      "remediation": [
        "Используйте параметризованные запросы/Prepared Statements",
        "Не конкатенируйте пользовательский ввод в SQL"
      ]
    }
  ]
}

Совет: фильтруйте details.filter(d => d.vulnerable) для списка подтвержденных находок.

smartScan(options) → SmartScanResult

  • crawledPages: number — сколько страниц обработано краулером
  • candidates: DiscoveredTarget[] — найденные цели для сканирования
    • { kind: "url-with-query"; url: string }
    • { kind: "form"; action: string; method: "GET"|"POST"; enctype?: string; fields: { name: string; value: string }[] }
    • { kind: "json-endpoint"; url: string; method: "GET"|"POST"|"PUT"|"PATCH"|"DELETE"; body?: any; headers?: Record<string,string> }
  • sqli: ResultShape[] — результаты сканирования для каждой из целей

Пример:

{
  "crawledPages": 12,
  "candidates": [
    { "kind": "url-with-query", "url": "https://site/search?q=" },
    {
      "kind": "form",
      "action": "https://site/login",
      "method": "POST",
      "fields": [{ "name": "email", "value": "" }]
    }
  ],
  "sqli": [
    {
      "vulnerable": false,
      "details": [
        {
          "point": { "kind": "query", "name": "q" },
          "technique": "boolean_truefalse",
          "payload": "...",
          "vulnerable": false
        }
      ]
    }
  ]
}

Тонкая настройка

  • Кастомные payload’ы для scan
await scanner.scan({
  target: "http://127.0.0.1:3000/rest/products/search?q=",
  enable: { query: true, error: true, boolean: true, time: false },
  payloads: {
    error: ["'", "' OR 1=1--", "' UNION SELECT 1--"],
    boolean: [{ true: "' OR 1=1--", false: "' OR 1=2--", label: "or_comment" }],
  },
});

– Предварительная авторизация (форма/JSON)

await scanner.scan({
  target: "https://site.local/products?id=1",
  method: "GET",
  auth: {
    url: "https://site.local/api/login",
    method: "POST",
    type: "form-urlencoded", // или "json"
    usernameField: "username",
    passwordField: "password",
    username: "admin",
    password: "secret",
    additionalFields: { remember: "1" },
    verifyUrl: "https://site.local/",
    success: { notContainsText: "Sign in" },
  },
  enable: { query: true, error: true, boolean: true },
});

Аналогично в smartScan:

await scanner.smartScan({
  baseUrl: "https://site.local",
  auth: {
    url: "https://site.local/api/login",
    method: "POST",
    type: "json",
    usernameField: "email",
    passwordField: "password",
    username: "admin@site.local",
    password: "secret",
    verifyUrl: "https://site.local/",
    success: { notContainsText: "Sign in" },
  },
});
  • Управление техниками в smartScan
await scanner.smartScan({
  baseUrl: "https://example.com",
  maxDepth: 2,
  maxPages: 50,
  techniques: { error: true, boolean: true, time: false },
});

Прогресс и ETA

  • Прогресс для точечного сканирования
await scanner.scan({
  target: "https://example.com/search?q=1",
  enable: { query: true, error: true, boolean: true, time: false },
  onProgress: (p) => {
    if (p.phase === "discover") {
      console.log(`points=${p.points}`);
    } else if (p.phase === "scan") {
      console.log(
        `checks ${p.processedChecks}/${p.plannedChecks}, eta=${p.etaMs}ms`
      );
    }
  },
});
  • Прогресс для умного сканирования (краулинг + скан)
await scanner.smartScan({
  baseUrl: "https://example.com",
  onProgress: (p) => {
    if (p.phase === "crawl") {
      console.log(`crawled ${p.crawledPages}/${p.maxPages}`);
    } else if (p.phase === "scan") {
      console.log(
        `scanned ${p.scanProcessed}/${p.scanTotal}, eta=${p.etaMs}ms`
      );
    }
  },
});

CLI (опционально)

Запуск без установки:

npx --package @kdinisv/sql-scanner sql-scan https://example.com

Глобально:

npm i -g @kdinisv/sql-scanner
sql-scan https://example.com

# отключить захват JS/SPA (без Playwright)
sql-scan https://example.com --no-js

# сохранить отчёт (Markdown/JSON/CSV/JUnit)
sql-scan https://example.com --report md --out report.md
sql-scan https://example.com --report json --out report.json
sql-scan https://example.com --report csv --out report.csv
sql-scan https://example.com --report junit --out report.xml

CLI показывает индикатор прогресса и оценку ETA в процессе.

.env-конфиг

CLI поддерживает конфигурацию через .env-файл (dotenv). Создайте .env в корне проекта (см. .env.example). Основные переменные:

  • SQL_SCANNER_REQUEST_TIMEOUT_MS, SQL_SCANNER_TIME_THRESHOLD_MS
  • SQL_SCANNER_PARALLEL, SQL_SCANNER_MAX_REQUESTS
  • SQL_SCANNER_USE_JS, SQL_SCANNER_MAX_DEPTH, SQL_SCANNER_MAX_PAGES, SQL_SCANNER_SAME_ORIGIN_ONLY
  • SQL_SCANNER_PLAYWRIGHT_HEADLESS (true|false). В CLI есть флаг --headed (делает headless=false)
  • SQL_SCANNER_TECHNIQUES=error,boolean,time
  • SQL_SCANNER_HEADERS / SQL_SCANNER_HEADERS_JSON (JSON строка)
  • SQL_SCANNER_COOKIES / SQL_SCANNER_COOKIES_JSON (JSON строка)
  • SQL_SCANNER_AUTH_JSON (JSON строка с параметрами авторизации)

Переменные окружения прокси HTTP_PROXY/HTTPS_PROXY/NO_PROXY также учитываются.

Тестовые эмуляторы СУБД (для разработки)

В репозитории есть лёгкие локальные HTTP-эмуляторы баз данных, которые имитируют поведение MySQL/PostgreSQL/MSSQL/Oracle/SQLite для техник:

  • error-based — возвращают характерные сигнатуры ошибок СУБД;
  • boolean-based — различающиеся ответы для «true/false» инъекций;
  • time-based — искусственная задержка при SLEEP/pg_sleep/WAITFOR/DBMS_LOCK.SLEEP;
  • union-based PoC — различия в ответах для ORDER BY ok/bad и UNION SELECT.

Они используются в автотестах и не требуют внешних контейнеров/стендов:

  • Код эмуляторов: tests/servers/dbEmulators.ts
  • Тест: tests/db-emulator.test.ts

Запуск тестов:

npm test -s

Сеть и прокси

  • Поддерживаются переменные окружения прокси:
    • HTTP_PROXY / HTTPS_PROXY — адрес прокси, например: http://127.0.0.1:3128 или с авторизацией http://user:pass@proxy.local:8080.
    • NO_PROXY — список исключений через запятую (если задан системно, будет учтён на стороне среды).
  • Для транзиентных ошибок на GET (502/503/504, сетевые таймауты) вшиты короткие ретраи с экспоненциальным backoff.

— Приоритет пейлоадов: если error-based детект дал отпечаток СУБД (MySQL/Postgres/MSSQL/Oracle/SQLite), time-based подбор сначала пробует соответствующие пейлоады (например, pg_sleep/WAITFOR/DBMS_LOCK.SLEEP), что ускоряет и повышает точность.

— Union-based PoC: реализованы безопасные пробы ORDER BY (сравнение ответов на валидный/заведомо «лишний» индекс) и базовые UNION SELECT пейлоады. При наличии отпечатка СУБД выбираются наиболее подходящие варианты.

Дополнительные примеры

1) Сканирование JSON API (POST)

const result = await scanner.scan({
  target: "https://api.site.local/search",
  method: "POST",
  jsonBody: { q: "test", page: 1 },
  enable: { json: true, error: true, boolean: true, time: false },
});

2) Сканирование формы

// target указывает на страницу с формой; сканер сам получит HTML и извлечёт поля
const res = await scanner.scan({
  target: "https://site.local/login",
  enable: { form: true, error: true, boolean: true, time: false, query: false },
});

3) Заголовки и куки (и инъекции в них)

const res = await scanner.scan({
  target: "https://site.local/profile?id=1",
  headers: { "X-Trace": "abc" },
  cookies: { session: "token" },
  enable: { header: true, cookie: true, error: true, boolean: true },
});

4) Time-based проверки

const res = await scanner.scan({
  target: "https://site.local/search?q=1",
  enable: { query: true, time: true },
  // Поднимите порог, если бэкенд медленный
  timeThresholdMs: 3000,
});

— Встроено статистическое подтверждение (p-value) для time-based: несколько парных замеров baseline/injected, расчёт p (односторонний тест). В evidence попадают p, z, средние времена. Для шумных систем можно повысить timeThresholdMs.

5) smartScan с/без JS

// Без JS (быстрее, только HTML)
await scanner.smartScan({
  baseUrl: "https://site.local",
  usePlaywright: false,
  crawlConcurrency: 6, // быстрее HTML-краулинг
});

// С JS (если установлен Playwright): захватывает запросы SPA
await scanner.smartScan({
  baseUrl: "https://site.local",
  usePlaywright: true,
  playwrightMaxPages: 4, // 0 или отрицательное — без ограничения
  playwrightConcurrency: 3, // несколько страниц параллельно
  playwrightWaitMs: 1200, // чуть дольше ждём XHR
  scanParallel: 3, // параллельно сканируем кандидатов
});

6) Постобработка результатов

const onlyVuln = result.details.filter((d) => d.vulnerable);
const byTechnique = onlyVuln.reduce(
  (acc, d) => {
    acc[d.technique] = (acc[d.technique] || 0) + 1;
    return acc;
  },
  /** @type {Record<string, number>} */ {}
);

— Готовые репорты: JSON/Markdown/CSV/JUnit

import {
  toJsonReport,
  toMarkdownReport,
  toCsvReport,
  toJUnitReport,
} from "@kdinisv/sql-scanner";

const json = toJsonReport(result);
const md = toMarkdownReport(result);
const csv = toCsvReport(result);
const junitXml = toJUnitReport(result);
// Сохраните в файл или отправьте в CI-артефакты

В отчётах теперь присутствуют примеры воспроизведения и советы по исправлению:

  • Markdown: внутри каждого найденного пункта добавляется раздел reproduce с curl ..., а также remediation — список рекомендаций.
  • CSV: дополнительные колонки reproduce_curl и remediation.
  • JUnit: в <failure> попадает тело с блоками curl: и fix:.

7) Управление нагрузкой

const scanner = new SqlScanner({ parallel: 4, maxRequests: 500 });
const res = await scanner.scan({ target: "https://site.local/?q=1" });

// Для smartScan скорость можно настраивать:
await scanner.smartScan({
  baseUrl: "https://site.local",
  crawlConcurrency: 4,
  playwrightConcurrency: 2,
  scanParallel: 2,
});

8) UNION/ORDER BY (PoC)

// Экспериментальная техника: сначала ORDER BY (ok vs bad), затем UNION
const res = await scanner.scan({
  target: "http://127.0.0.1:3000/search?q=1",
  enable: {
    query: true,
    union: true,
    error: false,
    boolean: false,
    time: false,
  },
});

const unionFindings = res.details.filter((d) => d.technique === "union");
// evidence включает orderby-sim=... и/или sim(base,union)=...

Примечание: это PoC с консервативными, безопасными пейлоадами. В бою комбинируйте с error/boolean/time для повышения уверенности.

Важно

Используйте сканер только на ресурсах, для которых у вас есть разрешение.

Keywords

security

FAQs

Package last updated on 29 Aug 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

About

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.

  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc

U.S. Patent No. 12,346,443 & 12,314,394. Other pending.