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

[](https://www.npmjs.com/package/@morgan-stanley/url-detector)
[](https://github.com/morganstanley/url-detector/actions/workflows/continuous-integration.yml)
[](https://securityscorecards.dev/viewer/?uri=github.com/morganstanley/url-detector)
[](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检测, 云安全监控, 依赖扫描, 实时处理, 文本扫描, 暗色界面, 模型提供商, 源代码分析, 漏洞管理, 硬件无关, 自动化攻击, 跌倒检测, 软件物料清单, 静态分析