morganstanley/url-detector

GitHub: morganstanley/url-detector

基于Tree-sitter AST解析的源码扫描工具,精准检测隐藏在20多种编程语言中的硬编码URL,弥补传统SBOM工具无法追踪直接引用外部依赖的缺陷。

Stars: 7 | Forks: 2

# URL Detector ![Lifecycle 孵化中](https://img.shields.io/badge/Lifecycle-Incubating-yellow) [![npm](https://img.shields.io/npm/v/@morgan-stanley/url-detector)](https://www.npmjs.com/package/@morgan-stanley/url-detector) [![CI](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/bb089d34ef180041.svg)](https://github.com/morganstanley/url-detector/actions/workflows/continuous-integration.yml) [![OpenSSF 记分卡](https://api.securityscorecards.dev/projects/github.com/morganstanley/url-detector/badge)](https://securityscorecards.dev/viewer/?uri=github.com/morganstanley/url-detector) [![许可证](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) 一款 URL 检测工具,通过 Tree-sitter 解析器扫描文件,以在 20 多种编程语言中实现精准的 URL 发现。该工具不使用简单的正则表达式匹配,而是执行 AST(抽象语法树)解析,以精确定位字符串、注释及其他合适上下文中的 URL。 ## SBOM 缺口 软件物料清单 (SBOM) 的生成对于安全与合规性已变得至关重要,但传统的 SBOM 工具却遗漏了一大类外部依赖:直接嵌入在源代码中的 URL。 现代包管理器和依赖扫描器在追踪受管理的依赖项(npm 包、Maven 构件等)方面表现出色,但它们无法检测出以下遗留模式: ``` ``` ``` const API_ENDPOINT = "https://api.thirdparty.com/v1"; fetch("https://analytics.example.com/track", { ... }); ``` 这些 URL 代表了真实的外部依赖,可能会影响安全性、可用性以及合规性——但它们绝不会出现在任何由包元数据生成的 SBOM 中。URL Detector 填补了这一空白,它提供了全面的 URL 清单,是对传统依赖追踪工具的有力补充。 ## 功能特性 - **🌐 常见语言支持**:JavaScript、TypeScript、Java、C/C++、C#、HTML、CSS、Python、PHP、Ruby、Go、Scala、JSON、XML、TOML、Bash、Kotlin 等 - **🌳 基于 AST 的解析**:使用 Tree-sitter 进行准确的分词和上下文感知的 URL 检测 - **🚀 高性能**:具有可配置并发限制的并发文件处理 - **📊 多种输出格式**:Table、JSON 和 CSV 输出,带有可自定义的格式 - **🎯 高级过滤**:支持通配符的域名允许列表/阻止列表、协议过滤和正则表达式回退 - **📍 精确位置追踪**:为每个 URL 提供行号、列号和字符位置 - **🔍 上下文检测**:在字符串字面量、注释和合适的语言构造中查找 URL - **🛡️ 误报过滤**:自动排除常见的 schema 模式(如 //W3C//DTD、//EN 等) - **⚙️ 高度可配置**:丰富的 CLI 选项和编程式 API - **📦 零配置**:无需复杂配置即可轻松设置 ## 安装说明 为了抑制 tree-sitter 传递依赖发出的警告,所有这些命令都可以选择加上 `--loglevel=error` 标志来运行。 ### 全局安装(推荐) ``` npm install -g @morgan-stanley/url-detector ``` ### 本地安装 ``` npm install @morgan-stanley/url-detector ``` ### NPX 用法(无需安装) ``` npx @morgan-stanley/url-detector --scan "src/**/*.js" --format table ``` ## 快速入门 ### 命令行界面 ``` # 扫描当前目录中的所有文件 url-detector # 扫描特定文件/模式 url-detector --scan "src/**/*.{js,ts}" --format table # 排除目录并忽略域名 url-detector --scan "**/*" --exclude "**/node_modules" --ignore-domains "*example.com" # 将结果导出至 CSV url-detector --scan "src/**/*" --format csv --output urls.csv # 在 CI/CD 中运行 (如果发现 URLs 则失败) url-detector --scan "**/*.js" --fail-on-error --results-only ``` ### 编程式用法 ``` import { URLDetector, LanguageManager } from '@morgan-stanley/url-detector'; // Basic usage const detector = new URLDetector(); const sourceCode = ` const apiUrl = "https://api.example.com/v1/users"; // Documentation: https://docs.example.com `; const urls = await detector.detectURLs(sourceCode, 'javascript', 'app.js'); console.log(urls); // Advanced usage with custom options const detector = new URLDetector({ includeComments: true, ignoreDomains: ['*.example.com', 'localhost'], protocol: ['https'], unique: true, logger: new ConsoleLogger() }); // Custom language configurations const customLanguageManager = new LanguageManager(undefined, [ { name: 'mylang', module: 'tree-sitter-mylang', extensions: ['.ml'] } ]); ``` ## CLI 选项 | 选项 | 描述 | 默认值 | |--------|-------------|---------| | `-s, --scan ` | 要扫描的文件 Glob 模式 | `["**/*"]` | | `-e, --exclude ` | 要排除的文件 Glob 模式 | `[]` | | `-i, --ignore-domains ` | 要忽略的额外域名(支持通配符,始终包含 `www.w3.org`) | `[]` | | `--include-comments` | 同时扫描注释掉的行以查找 URL | `false` | | `--include-non-fqdn` | 包含非完全限定域名,如 "localhost" | `false` | | `-f, --format ` | 输出格式:`table`、`json` 或 `csv` | `"table"` | | `-o, --output ` | 输出文件路径(如未指定则为标准输出) | `null` | | `-q, --quiet` | 在静默模式下运行,无控制台输出 | `false` | | `--results-only` | 仅显示结果,抑制进度和信息消息 | `false` | | `--fail-on-error` | 如果找到任何 URL,则以非零代码退出 | `false` | | `--concurrency ` | 并发扫描的最大文件数 | `10` | | `--scan-file ` | 包含要扫描的 glob 模式的文件(每行一个) | `null` | | `--exclude-file ` | 包含要排除的 glob 模式的文件(每行一个) | `null` | ## 支持的语言 | 语言 | 扩展名 | Tree-sitter 解析器 | |----------|------------|-------------------| | JavaScript | `.js`, `.mjs` | [`tree-sitter-javascript`](https://npmjs.com/package/tree-sitter-javascript) | | TypeScript | `.ts`, `.tsx` | [`tree-sitter-typescript`](https://npmjs.com/package/tree-sitter-typescript) | | Java | `.java` | [`tree-sitter-java`](https://npmjs.com/package/tree-sitter-java) | | C | `.c`, `.h` | [`tree-sitter-c`](https://npmjs.com/package/tree-sitter-c) | | C++ | `.cpp`, `.cc`, `.cxx`, `.hpp`, `.hh`, `.hxx` | [`tree-sitter-cpp`](https://npmjs.com/package/tree-sitter-cpp) | | C# | `.cs` | [`tree-sitter-c-sharp`](https://npmjs.com/package/tree-sitter-c-sharp) | | Python | `.py`, `.pyw` | [`tree-sitter-python`](https://npmjs.com/package/tree-sitter-python) | | PHP | `.php`, `.phtml` | [`tree-sitter-php`](https://npmjs.com/package/tree-sitter-php) | | Ruby | `.rb`, `.rake`, `.gemspec` | [`tree-sitter-ruby`](https://npmjs.com/package/tree-sitter-ruby) | | Go | `.go` | [`tree-sitter-go`](https://npmjs.com/package/tree-sitter-go) | | Kotlin | `.kt`, `.kts` | [`@tree-sitter-grammars/tree-sitter-kotlin`](https://npmjs.com/package/@tree-sitter-grammars/tree-sitter-kotlin) | | Scala | `.scala`, `.sc` | [`tree-sitter-scala`](https://npmjs.com/package/tree-sitter-scala) | | HTML | `.html`, `.htm` | [`tree-sitter-html`](https://npmjs.com/package/tree-sitter-html) | | CSS | `.css` | [`tree-sitter-css`](https://npmjs.com/package/tree-sitter-css) | | JSON | `.json`, `.jsonc` | [`tree-sitter-json`](https://npmjs.com/package/tree-sitter-json) | | XML | `.xml`, `.xsd`, `.xsl`, `.xslt` | [`@tree-sitter-grammars/tree-sitter-xml`](https://npmjs.com/package/@tree-sitter-grammars/tree-sitter-xml) | | TOML | `.toml` | [`@tree-sitter-grammars/tree-sitter-toml`](https://npmjs.com/package/@tree-sitter-grammars/tree-sitter-toml) | | Bash | `.sh`, `.bash`, `.zsh`, `.fish` | [`tree-sitter-bash`](https://npmjs.com/package/tree-sitter-bash) | | YAML | `.yaml`, `.yml` | [`@tree-sitter-grammars/tree-sitter-yaml`](https://npmjs.com/package/@tree-sitter-grammars/tree-sitter-yaml) | ## 示例 ### 基本文件扫描 ``` # 扫描所有 JavaScript 和 TypeScript 文件 url-detector --scan "**/*.{js,ts}" --format table # 仅扫描源代码,排除 build artifacts url-detector --scan "src/**/*" --exclude "build/**" "dist/**" "**/node_modules" ``` ### 域名过滤 该工具会自动忽略代码中常见的无意义域名(例如 XML 命名空间中的 `www.w3.org`)。您可以添加要忽略的额外域名: ``` # 忽略所有 example.com 子域名 url-detector --ignore-domains "*.example.com" # 忽略多个域名模式 url-detector --ignore-domains "*.example.com" "localhost" "*.local" ``` ### 输出格式 ``` # 表格输出 (默认) url-detector --scan "src/**/*" --format table # 用于编程处理的 JSON 输出 url-detector --scan "src/**/*" --format json --output results.json # 用于电子表格分析的 CSV 输出 url-detector --scan "src/**/*" --format csv --output urls.csv ``` ### CI/CD 集成 ``` # 如果发现任何 URLs 则使构建失败 url-detector --scan "**/*" --exclude "**/node_modules" --fail-on-error # 用于 CI 日志的静默模式 url-detector --scan "src/**/*" --quiet --format json --output scan-results.json # 仅结果模式 (无进度消息) url-detector --scan "**/*" --results-only --format table ``` ## API 参考 ### URLDetector 类 ``` class URLDetector { constructor(options?: DetectorOptionsConfig, logger?: Logger); detectURLs(sourceCode: string, language: string, filePath?: string): Promise; process(): Promise; } ``` ### DetectorOptionsConfig 接口 ``` interface DetectorOptionsConfig { // File scanning options scan?: string[]; // Glob patterns for files to scan (default: ["**/*"]) exclude?: string[]; // Glob patterns to exclude (default: []) // Filtering options ignoreDomains?: string[]; // Additional domains to ignore (default: [], always includes `www.w3.org`) includeComments?: boolean; // Include URLs from comments (default: false) includeNonFqdn?: boolean; // Include non-FQDN domains like "localhost" (default: false) // Output options format?: 'table' | 'json' | 'csv'; // Output format (default: "table") output?: string | null; // Output file path (default: null) // Control options resultsOnly?: boolean; // Results only mode (default: false) failOnError?: boolean; // Exit with error if URLs found (default: false) // Performance options concurrency?: number; // Max concurrent files (default: 10) // Advanced options (programmatic only) fallbackRegex?: boolean; // Use regex fallback when tree-sitter fails (default: true) context?: number; // Lines of context to include (default: 0) maxDepth?: number; // Max directory depth (default: Infinity) quiet?: boolean; // Suppress informational output (default: false) } ``` ### URLMatch 结构 ``` interface URLMatch { url: string; // The detected URL start: number; // Start character position end: number; // End character position line: number; // Line number (1-based) column: number; // Column number (1-based) sourceType: 'string' | 'comment' | 'unknown'; // Context type context?: string[]; // Surrounding lines (if requested) } ``` ### 语言自定义 ``` import { LanguageManager, LanguageConfig } from '@morgan-stanley/url-detector'; // Add custom language support const customLanguages: LanguageConfig[] = [ { name: 'mylang', module: 'tree-sitter-mylang', extensions: ['.ml', '.mylang'], filenames: ['Mylangfile'] } ]; const languageManager = new LanguageManager(undefined, customLanguages); ``` ## 工作原理 1. **语言检测**:根据文件扩展名或文件名自动检测编程语言 2. **AST 解析**:使用 Tree-sitter 将源代码解析为抽象语法树 3. **节点遍历**:递归遍历 AST 以查找字符串字面量和注释节点 4. **URL 提取**:对相关节点的内容应用 URL 正则表达式模式 5. **上下文分析**:判断 URL 是位于字符串、注释还是其他上下文中 6. **过滤**:应用域名过滤器和其他条件 7. **位置追踪**:为每个 URL 计算精确的行/列位置 8. **回退支持**:对不支持的语言回退到正则表达式扫描 ## 性能表现 - **并发处理**:同时处理多个文件(可配置并发数) - **内存高效**:流式传输大文件并进行增量处理 - **快速解析**:Tree-sitter 提供高性能解析 - **智能缓存**:在可能的情况下重用解析器实例 ## 运行测试 ``` # 运行所有测试 npm test # 以 watch 模式运行测试 npm run test:watch # 带 coverage 运行 npm test -- --coverage ``` ## 开发说明 ### 项目结构 ``` src/ ├── index.ts # Main library entry point ├── cli.ts # Command-line interface ├── urlDetector.ts # Core URL detection logic ├── languageManager.ts # Language/parser management ├── urlFilter.ts # URL filtering and validation ├── outputFormatter.ts # Output formatting (table/json/csv) ├── options.ts # Configuration options └── logger.ts # Logging interfaces tests/ ├── urlDetector.test.ts ├── languageManager.test.ts └── integration.test.ts ``` ### 本地开发设置 ``` # 克隆仓库 git clone https://github.com/morgan-stanley/url-detector.git cd url-detector # 安装依赖 npm install ``` ### 构建 ``` # 将 TypeScript 构建为 JavaScript npm run build # 构建并监听更改 npm run dev # 清理 build artifacts npm run clean ``` ### 代码检查 ``` # 检查代码风格 npm run lint # 修复可自动修复的问题 npm run lint:fix ``` ### 创建独立可执行文件 本项目支持使用 [pkg](https://github.com/yao-pkg/pkg) 创建用于分发的独立可执行文件: ``` # 为所有平台创建可执行文件 npm run pkg:all # 创建特定平台的可执行文件 npm run pkg:linux # Creates url-detector-linux npm run pkg:macos # Creates url-detector-macos npm run pkg:win # Creates url-detector-win.exe ``` 这些可执行文件通过仅包含特定平台的原生依赖来优化大小。每个二进制文件包含: - 编译后的 TypeScript 代码 - Node.js 运行时 - 仅包含目标平台的 Tree-sitter 预构建版本 **注意**:在创建可执行文件之前,您必须运行 `npm run build`,以确保最新的 TypeScript 更改已被编译。 ## 许可证 Apache License 2.0 - 详见 [LICENSE](LICENSE) 文件。
标签:AST解析, CMS安全, GNU通用公共许可证, GPT, IP 地址批量处理, JavaScript, MITM代理, Node.js, SBOM, Tree-sitter, URL检测, 云安全监控, 依赖扫描, 实时处理, 文本扫描, 暗色界面, 模型提供商, 源代码分析, 漏洞管理, 硬件无关, 自动化攻击, 跌倒检测, 软件物料清单, 静态分析