JacobJandon/Sicry
GitHub: JacobJandon/Sicry
Sicry 是一个单文件 Python 库,为 AI Agent 提供 Tor/暗网访问能力,整合了 18 个搜索引擎和 LLM 驱动的 OSINT 分析流水线。
Stars: 0 | Forks: 0
# SICRY™ — 面向 AI Agent 的 Tor/Onion 网络接入层
[](https://github.com/JacobJandon/Sicry/blob/main/LICENSE)
[](https://github.com/JacobJandon/Sicry/actions/workflows/ci.yml)
**作者 JacobJandon** · [github.com/JacobJandon/Sicry](https://github.com/JacobJandon/Sicry)
单个 Python 文件。放入任何项目中,您的 AI agent 即可获得对 Tor/.onion 暗网的完全访问权限——与 agent 访问常规互联网时使用的同样简洁的工具接口,现在专用于隐藏服务。
内置 Robin 的完整搜索引擎目录(18 个引擎)和 OSINT 流水线。无需安装 Robin。无额外进程。除 `.env` 文件外无需其他配置。
```
pip install requests[socks] beautifulsoup4 python-dotenv stem
apt install tor && tor &
cp .env.example .env # add one API key (or use Ollama — no key needed)
python sicry.py check # → CONNECTED via Tor | exit IP: 185.220.101.5
```
## 目录
1. [SICRY™ 的功能](#what-sicry-does)
2. [安装](#installation)
3. [快速入门](#quickstart)
4. [全部九个函数](#all-nine-functions)
5. [工具模式 (Anthropic / OpenAI / Gemini)](#tool-schemas)
6. [框架集成](#framework-integration)
7. [CLI 参考](#cli-reference)
8. [完整 OSINT 流水线](#the-full-osint-pipeline)
9. [分析模式](#analysis-modes)
10. [18 个搜索引擎](#18-search-engines)
11. [环境变量](#environment-variables)
12. [Tor 设置](#tor-setup)
13. [故障排除](#troubleshooting)
14. [致谢](#credits)
## SICRY™ 的功能
SICRY™ 为 AI agent 提供了确切的 6 个工具——与它们在 clearnet(明网)上已经掌握的 6 个工具相同,只是现在通过 Tor 运行:
| SICRY™ 工具 | Clearnet 等效工具 | 功能描述 |
|---|---|---|
| `sicry_check_tor` | 健康检查 | 验证 Tor 是否处于活动状态,获取出口 IP |
| `sicry_renew_identity` | 重置会话 | 轮换电路,获取新的出口节点 |
| `sicry_fetch` | `fetch_url()` / `browser_read_page()` | 通过 Tor 读取任何 URL 或 `.onion` |
| `sicry_search` | `web_search()` / `brave_search()` | 查询 18 个暗网搜索引擎 |
| `sicry_ask` | `analyze()` / `summarize()` | 基于原始内容的 LLM OSINT 报告 |
| `sicry_check_engines` | ping / 健康检查 | 所有 18 个引擎的延迟 + 状态 |
外加三个质量提升辅助工具(Robin 模式,可直接调用):
| 辅助函数 | 功能描述 |
|---|---|
| `refine_query(query)` | LLM:自然语言 → ≤5 个词的暗网查询 |
| `filter_results(query, results)` | LLM:从所有原始结果中筛选出前 20 个最相关的 |
| `scrape_all(urls)` | 并发批量抓取 → `{url: "title - text"}` 字典 |
## 安装
### 系统要求
- Python 3.10+
- 本地运行 Tor daemon
- pip 包(见下文)
### 1. 安装 Tor
**Linux (Debian/Ubuntu):**
```
apt install tor
tor &
```
**macOS:**
```
brew install tor
tor &
```
**自定义 DataDirectory(推荐用于 `renew_identity`):**
```
cat > /tmp/sicry_tor.conf << 'EOF'
SocksPort 9050
ControlPort 9051
CookieAuthentication 1
DataDirectory /tmp/tor_data
EOF
tor -f /tmp/sicry_tor.conf &
```
使用自定义配置时,在 `.env` 中设置 `TOR_DATA_DIR=/tmp/tor_data`。
### 2. 安装 Python 依赖
```
pip install -r requirements.txt
```
或手动安装:
```
pip install requests[socks] beautifulsoup4 python-dotenv stem
# 可选 —— 仅在使用 MCP server 时需要
pip install mcp
# 可选 —— 仅在使用 OpenAI/Anthropic/Gemini LLM 后端时需要
pip install openai # for OpenAI
pip install anthropic # for Anthropic/Claude
pip install google-generativeai # for Gemini
```
### 3. 配置 `.env`
```
cp .env.example .env
```
最小配置 —— 选择一个 LLM:
```
# 无密钥选项(本地推理):
LLM_PROVIDER=ollama
OLLAMA_MODEL=llama3.2
# OpenAI:
LLM_PROVIDER=openai
OPENAI_API_KEY=sk-...
# Anthropic:
LLM_PROVIDER=anthropic
ANTHROPIC_API_KEY=sk-ant-...
# Gemini:
LLM_PROVIDER=gemini
GEMINI_API_KEY=AIza...
```
## 快速入门
```
# 验证 Tor 是否正在运行
python sicry.py check
# → 已通过 Tor 连接 | 出口 IP: 185.220.101.5 | 错误: None
# 搜索暗网
python sicry.py search "ransomware data leak" --max 10
# 获取 .onion 页面
python sicry.py fetch http://juhanurmihxlp77nkq76byazcldy2hlmovfu2epvl5ankdibsot4csyd.onion
# 为您的框架打印工具 schemas
python sicry.py tools # Anthropic format (default)
python sicry.py tools --format openai # OpenAI format
python sicry.py tools --format gemini # Gemini format
# 轮换 Tor 身份
python sicry.py renew
# 启动 MCP server (用于 Claude Desktop / Cursor / Zed)
python sicry.py serve
```
在 Python 中:
```
import sicry
# 验证 Tor
print(sicry.check_tor())
# → {"tor_active": True, "exit_ip": "185.220.101.5", "error": None}
# 搜索
results = sicry.search("credential dump")
# → [{"title": "...", "url": "http://...onion/...", "engine": "Ahmia"}, ...]
# 获取
page = sicry.fetch("http://juhanurmihxlp77nkq76byazcldy2hlmovfu2epvl5ankdibsot4csyd.onion")
# → {"url": "...", "is_onion": True, "status": 200, "title": "Ahmia", "text": "...", "links": [...]}
```
## 全部九个函数
### `check_tor() → dict`
验证 Tor 是否正在运行以及机器是否通过 Tor 出口节点进行路由。
```
r = sicry.check_tor()
# {"tor_active": True, "exit_ip": "185.220.101.5", "error": None}
# {"tor_active": False, "exit_ip": None, "error": "connection refused"}
```
**首先调用此函数。** 如果 Tor 宕机,所有其他网络函数将静默失败。
### `renew_identity() → dict`
轮换 Tor 电路 —— 获取新的出口节点和全新的身份。
```
r = sicry.renew_identity()
# {"success": True, "error": None}
```
按顺序尝试认证:
1. `TOR_CONTROL_PASSWORD` 环境变量(如果您在 torrc 中设置了 `HashedControlPassword`)
2. 来自 `TOR_DATA_DIR` 环境变量的 Cookie 文件
3. 常见系统路径中的 Cookie 文件(`/tmp/tor_data`, `/var/lib/tor`, `~/.tor`, `/run/tor`)
4. 空字符串 / null 认证(完全没有密码的 Tor)
使用 SICRY™ 推荐的 torrc(cookie 认证)可**开箱即用**。请参阅 [Tor 设置](#tor-setup)。
### `fetch(url) → dict`
通过 Tor 获取任何 URL —— 适用于 clearnet 和 `.onion` 隐藏服务。
```
r = sicry.fetch("http://somemarket.onion/listings")
# {
# "url": "http://somemarket.onion/listings",
# "is_onion": True,
# "status": 200,
# "title": "Market Listings",
# "text": "Plain text, HTML stripped, up to 8000 chars",
# "links": [{"text": "Link label", "href": "http://..."}, ...], # up to 80 links
# "error": None
# }
```
- 没有 `http://` / `https://` 的 URL 会自动添加 `http://` 前缀。
- `text` 经过 HTML 去除、空白折叠处理,并截断至 `MAX_CONTENT_CHARS`(默认 8000)。
- 始终返回字典 —— 永不抛出异常。
### `search(query, engines=None, max_results=20, max_workers=8) → list[dict]`
同时搜索 18 个暗网搜索引擎。
```
# 并行使用所有 18 个引擎
results = sicry.search("leaked database credentials")
# [{"title": "...", "url": "http://...onion/...", "engine": "Ahmia"}, ...]
# 仅指定引擎
results = sicry.search("ransomware", engines=["Ahmia", "Tor66", "Ahmia-clearnet"])
# 更多结果
results = sicry.search("bitcoin mixer", max_results=50)
```
- 结果在所有引擎之间按 URL 去重。
- `engines` 不区分大小写。未知的引擎名称将被静默跳过。
- 始终返回列表 —— 永不抛出异常。
### `scrape_all(urls, max_workers=5) → dict`
并发批量抓取多个页面,并返回准备好供 LLM 使用的 `{url: content}`。
```
pages = sicry.scrape_all(search_results[:10])
# {
# "http://site1.onion/page": "Page Title - full page text...(truncated)",
# "http://site2.onion/page": "Page Title - full page text",
# ...
# }
combined = "\n\n".join(pages.values())
```
- 输入是 `search()` 的原始输出 —— `{"title", "url"}` 字典列表。
- 内容限制为每页 2000 个字符,并带有 `...(truncated)` 标记。
- 使用 Robin 的模式:`"title - text"` 格式为 LLM 提供上下文。
- 失败的页面将被静默丢弃(仅返回可访问的页面)。
### `refine_query(query, provider=None) → str`
LLM 将自然语言查询细化为 ≤5 个聚焦的词汇,用于暗网搜索引擎。
```
q = sicry.refine_query("I want to find ransomware groups that targeted hospitals in 2026")
# → "hospital ransomware 2026 leak"
q = sicry.refine_query("has acme.com appeared in any data breaches")
# → "acme.com breach credentials"
```
- 如果未设置 LLM 密钥,则回退到原始查询。**永不抛出异常**。
- 这是一个 Robin 模式 —— 暗网索引对短关键词的响应远优于自然语言。
- 在 `search()` 之前使用可显著提高结果质量。
### `filter_results(query, results, provider=None) → list[dict]`
LLM 过滤搜索结果列表,仅保留前 20 个最相关的结果。
```
best = sicry.filter_results("hospital ransomware 2026", raw_results)
# 返回最多 20 个结果,由 LLM 根据相关性筛选
```
- 如果未设置 LLM 密钥,则回退到 `results[:20]`。**永不抛出异常**。
- 如果 LLM 对大型负载进行限流,会自动使用截断的标题重试。
- 在 `search()` 之后使用,以在抓取前减少噪音。
### `ask(content, query="", mode="threat_intel", custom_instructions="", provider=None) → str`
使用 LLM 分析暗网内容并返回结构化的 OSINT 报告。
```
report = sicry.ask(
content="\n\n".join(pages.values()),
query="hospital ransomware groups",
mode="ransomware",
)
print(report) # Structured report: indicators, TTPs, threat actor profile, next steps
```
**模式:**
| 模式 | 别名 | 侧重点 |
|---|---|---|
| `threat_intel` | *(默认)* | 通用 OSINT —— 工件、洞察、后续步骤 |
| `ransomware` | `ransomware_malware` | 恶意软件/C2/MITRE TTPs、受害组织、检测 |
| `personal_identity` | | PII/泄露暴露、严重程度、保护措施 |
| `corporate` | `corporate_espionage` | 泄露的凭据/代码/文档、IR 步骤 |
```
# 为任何模式添加自定义重点
report = sicry.ask(
content,
mode="threat_intel",
custom_instructions="Focus on cryptocurrency wallets and mixer services",
)
```
- 如果未设置 LLM 密钥,则返回 `[SICRY™: ...]` 错误字符串 —— **永不抛出异常**。
- 内容在发送给 LLM 之前会被截断至 `MAX_CONTENT_CHARS`(默认 8000)。
### `check_search_engines(max_workers=8) → list[dict]`
通过 Tor ping 所有 18 个引擎,并返回每个引擎的状态和延迟。
```
results = sicry.check_search_engines()
# [
# {"name": "Ahmia", "status": "up", "latency_ms": 1240, "error": None},
# {"name": "Kaizer", "status": "down", "latency_ms": None, "error": "timeout"},
# ...
# ]
live = [r for r in results if r["status"] == "up"]
print(f"{len(live)}/18 engines alive")
fastest = min(live, key=lambda x: x["latency_ms"])
print(f"Fastest: {fastest['name']} ({fastest['latency_ms']}ms)")
```
- 结果保持原始引擎顺序。
- 在 `search()` 之前使用,以避免在失效引擎上浪费时间。
## 工具模式
SICRY™ 以每个主要框架的原生格式公开所有 6 个工具。三种格式始终保持同步。
```
import sicry
sicry.TOOLS # Anthropic / Claude format (input_schema)
sicry.TOOLS_OPENAI # OpenAI function-calling format (type: "function")
sicry.TOOLS_GEMINI # Google Gemini function declarations
```
打印其中任何一个:
```
python sicry.py tools # Anthropic (default)
python sicry.py tools --format openai
python sicry.py tools --format gemini
```
公开的工具:
| 工具名称 | 必需参数 | 可选参数 |
|---|---|---|
| `sicry_check_tor` | *(无)* | |
| `sicry_renew_identity` | *(无)* | |
| `sicry_fetch` | `url` | |
| `sicry_search` | `query` | `max_results` (int), `engines` (list) |
| `sicry_ask` | `content` | `query`, `mode`, `custom_instructions` |
| `sicry_check_engines` | *(无)* | `max_workers` (int) |
## 框架集成
### dispatcher
所有框架共享一个 dispatcher —— 使用工具名称和输入字典调用它:
```
result = sicry.dispatch(tool_name, tool_input)
# 返回: dict | list | str (与工具文档中记录的返回类型一致)
# 抛出: ValueError if tool_name is unknown
```
### Anthropic / Claude
```
import anthropic, sicry, json
client = anthropic.Anthropic()
messages = [{"role": "user", "content": "Search dark web for recent credential leaks from banks"}]
while True:
resp = client.messages.create(
model="claude-opus-4-6",
max_tokens=4096,
system="You are a dark-web OSINT analyst. Always verify Tor before searching.",
tools=sicry.TOOLS, # <- Anthropic format
messages=messages,
)
if resp.stop_reason != "tool_use":
print(next(b.text for b in resp.content if hasattr(b, "text")))
break
tool_results = []
for block in resp.content:
if block.type == "tool_use":
result = sicry.dispatch(block.name, block.input)
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": json.dumps(result, default=str),
})
messages.append({"role": "assistant", "content": resp.content})
messages.append({"role": "user", "content": tool_results})
```
### OpenAI / GPT
```
from openai import OpenAI
import sicry, json
client = OpenAI()
messages = [
{"role": "system", "content": "You are a dark-web OSINT analyst."},
{"role": "user", "content": "Has acme.com appeared in any dark web leaks?"},
]
while True:
resp = client.chat.completions.create(
model="gpt-4o",
tools=sicry.TOOLS_OPENAI, # <- OpenAI format
messages=messages,
)
msg = resp.choices[0].message
messages.append(msg)
if not msg.tool_calls:
print(msg.content)
break
for call in msg.tool_calls:
result = sicry.dispatch(
call.function.name,
json.loads(call.function.arguments),
)
messages.append({
"role": "tool",
"tool_call_id": call.id,
"content": json.dumps(result, default=str),
})
```
### Google Gemini
```
import google.generativeai as genai
import sicry, json
genai.configure(api_key="YOUR_GEMINI_API_KEY")
model = genai.GenerativeModel(
"gemini-2.5-flash",
tools=[{"function_declarations": sicry.TOOLS_GEMINI}], # <- Gemini format
system_instruction="You are a dark-web OSINT analyst.",
)
chat = model.start_chat()
resp = chat.send_message("Find mentions of acme.com on dark web forums")
while True:
fn_calls = [p.function_call for p in resp.parts
if hasattr(p, "function_call") and p.function_call.name]
if not fn_calls:
for part in resp.parts:
if hasattr(part, "text"):
print(part.text)
break
tool_responses = []
for fn_call in fn_calls:
result = sicry.dispatch(fn_call.name, dict(fn_call.args))
tool_responses.append(
genai.protos.Part(
function_response=genai.protos.FunctionResponse(
name=fn_call.name,
response={"result": json.dumps(result, default=str)},
)
)
)
resp = chat.send_message(tool_responses)
```
### LangChain
```
from langchain.tools import StructuredTool
from langchain.agents import initialize_agent, AgentType
from langchain_openai import ChatOpenAI
import sicry
tools = [
StructuredTool.from_function(name="sicry_check_tor",
func=sicry.check_tor,
description="Verify Tor is active. Call before any dark web operation."),
StructuredTool.from_function(name="sicry_renew_identity",
func=sicry.renew_identity,
description="Rotate Tor circuit — new exit node and identity."),
StructuredTool.from_function(name="sicry_fetch",
func=sicry.fetch,
description="Fetch any URL or .onion hidden service via Tor."),
StructuredTool.from_function(name="sicry_search",
func=lambda query, max_results=20: sicry.search(query, max_results=max_results),
description="Search 18 dark web engines. Returns title/url/engine list."),
StructuredTool.from_function(name="sicry_ask",
func=sicry.ask,
description="Analyse dark web content. mode: threat_intel|ransomware|personal_identity|corporate"),
StructuredTool.from_function(name="sicry_check_engines",
func=sicry.check_search_engines,
description="Ping all 18 search engines. Returns status + latency per engine."),
]
agent = initialize_agent(
tools,
ChatOpenAI(model="gpt-4o"),
agent=AgentType.OPENAI_FUNCTIONS,
verbose=True,
)
agent.run("Search the dark web for ransomware activity targeting the healthcare sector")
```
### CrewAI
```
from crewai import Agent, Task, Crew
from langchain.tools import StructuredTool
import sicry
sicry_tools = [
StructuredTool.from_function(name="sicry_check_tor",
func=sicry.check_tor,
description="Verify Tor is active."),
StructuredTool.from_function(name="sicry_search",
func=lambda query: sicry.search(query, max_results=20),
description="Search 18 dark web engines."),
StructuredTool.from_function(name="sicry_fetch",
func=sicry.fetch,
description="Fetch any .onion URL via Tor."),
StructuredTool.from_function(name="sicry_ask",
func=sicry.ask,
description="LLM OSINT analysis. mode: threat_intel|ransomware|personal_identity|corporate"),
StructuredTool.from_function(name="sicry_check_engines",
func=sicry.check_search_engines,
description="Ping all 18 search engines. Returns status + latency."),
]
analyst = Agent(
role="Dark Web OSINT Analyst",
goal="Investigate dark web threats and produce structured intelligence reports",
backstory="Expert in dark web monitoring and threat intelligence",
tools=sicry_tools,
verbose=True,
)
task = Task(
description="Search for ransomware groups targeting hospitals. Fetch top results and produce an intelligence report.",
expected_output="Structured OSINT report with threat actors, TTPs, indicators, and next steps.",
agent=analyst,
)
Crew(agents=[analyst], tasks=[task]).kickoff()
```
### MCP (Claude Desktop / Cursor / Zed)
启动服务器:
```
python sicry.py serve
```
添加到 `~/.config/claude/claude_desktop_config.json`:
```
{
"mcpServers": {
"sicry": {
"command": "python",
"args": ["/absolute/path/to/sicry.py", "serve"]
}
}
}
```
Cursor (`settings.json`):
```
"mcp.servers": {
"sicry": {
"command": "python /absolute/path/to/sicry.py serve"
}
}
```
这 6 个 SICRY™ 工具通过 FastMCP 自动注册。需要:`pip install mcp`
### OpenClaw
```
mkdir -p ~/.openclaw/workspace/skills/sicry
cp sicry.py openclaw_skill/SKILL.md ~/.openclaw/workspace/skills/sicry/
```
## CLI 参考
```
python sicry.py [options]
```
| 命令 | 选项 | 描述 |
|---|---|---|
| `check` | | 验证 Tor 是否正在运行,显示出口 IP |
| `renew` | | 轮换 Tor 电路 |
| `search ` | `--max N` (默认 10), `--engine NAME` (可重复) | 搜索暗网 |
| `fetch ` | | 通过 Tor 获取 URL,打印文本 |
| `tools` | `--format anthropic\|openai\|gemini` | 以 JSON 打印工具模式 |
| `serve` | | 启动 MCP 服务器 |
**示例:**
```
python sicry.py check
python sicry.py renew
python sicry.py search "ransomware healthcare" --max 15
python sicry.py search "bitcoin mixer" --engine Ahmia --engine Tor66
python sicry.py fetch http://juhanurmihxlp77nkq76byazcldy2hlmovfu2epvl5ankdibsot4csyd.onion
python sicry.py tools --format openai | python -m json.tool
python sicry.py serve
```
## 完整 OSINT 流水线
这是推荐的工作流程。每一步都应用了 Robin 模式,该模式对结果质量有显著的提升作用:
```
import sicry
# 步骤 1:验证 Tor
status = sicry.check_tor()
if not status["tor_active"]:
raise RuntimeError(f"Tor not active: {status['error']}")
print(f"Tor active. Exit IP: {status['exit_ip']}")
# 步骤 2:健康检查引擎(跳过已失效的)
engine_status = sicry.check_search_engines()
live = [e for e in engine_status if e["status"] == "up"]
live_names = [e["name"] for e in live]
print(f"{len(live)}/18 engines alive: {', '.join(live_names[:5])}...")
# 步骤 3:优化查询(Robin 质量模式)
raw_query = "ransomware groups targeting hospital systems 2026"
query = sicry.refine_query(raw_query)
print(f"Refined: '{raw_query}' -> '{query}'")
# 步骤 4:搜索(仅并行查询存活的引擎)
raw_results = sicry.search(
query,
engines=live_names, # skip engines we know are down
max_results=50,
)
print(f"{len(raw_results)} raw results")
# 步骤 5:筛选出最佳的 20 个(Robin 质量模式)
best = sicry.filter_results(query, raw_results)
print(f"Filtered to {len(best)} most relevant")
# 步骤 6:并发批量抓取
pages = sicry.scrape_all(best[:10], max_workers=5)
print(f"Scraped {len(pages)} pages")
# 步骤 7:OSINT 分析
combined = "\n\n".join(f"[{url}]\n{text}" for url, text in pages.items())
report = sicry.ask(
combined,
query=query,
mode="ransomware",
custom_instructions="Focus on victim organisations and ransom demands.",
)
print(report)
# 步骤 8:完成后轮换身份
sicry.renew_identity()
```
## 分析模式
所有四种模式都会生成结构化的分节报告。传入原始 `.onion` 文本或 `scrape_all()` 输出。
### `threat_intel` (默认)
通用暗网 OSINT。最适合初步调查。
输出部分:输入查询 · 来源链接 · 调查工件 · 关键洞察 · 后续步骤
```
report = sicry.ask(content, query="acme.com breach", mode="threat_intel")
```
### `ransomware`
别名:`ransomware_malware`
恶意软件情报。提取 C2 域名、文件哈希、MITRE ATT&CK TTPs、受害行业。
输出部分:输入查询 · 来源链接 · 恶意软件/勒索软件指标 · 威胁行为者画像 · 关键洞察 · 后续步骤
```
report = sicry.ask(content, query="LockBit hospital", mode="ransomware")
```
### `personal_identity`
PII 泄露分析。揭示 SSN、电子邮件、护照数据、泄露来源、风险严重程度。
输出部分:输入查询 · 来源链接 · 泄露的 PII 工件 · 泄露/市场来源 · 泄露风险评估 · 关键洞察 · 后续步骤
```
report = sicry.ask(content, query="john.doe@email.com", mode="personal_identity")
```
### `corporate`
别名:`corporate_espionage`
企业威胁情报。检测泄露的凭据、源代码、内部文档。
输出部分:输入查询 · 来源链接 · 泄露的企业工件 · 威胁行为者/经纪人活动 · 业务影响评估 · 关键洞察 · 后续步骤
```
report = sicry.ask(content, query="acme.com corporate leak", mode="corporate")
```
## 18 个搜索引擎
Robin 的完整目录加上两个验证过的额外引擎。全部由 `search()` 同时查询。
| 引擎 | 类型 | 备注 |
|---|---|---|
| **Ahmia** | `.onion` 索引 | 最可靠,最大的索引 |
| **OnionLand** | `.onion` 索引 | |
| **Torgle** | `.onion` 索引 | |
| **Amnesia** | `.onion 索引 | |
| **Kaizer** | `.onion` 索引 | |
| **Anima** | `.onion` 索引 | |
| **Tornado** | `.onion` 索引 | |
| **TorNet** | `.onion` 索引 | |
| **Torland** | `.onion` 索引 | |
| **FindTor** | `.onion` 索引 | |
| **Excavator** | `.onion` 索引 | |
| **Onionway** | `.onion` 索引 | |
| **Tor66** | `.onion` 索引 | 良好的论坛覆盖率 |
| **OSS** | `.onion` 索引 | |
| **Torgol** | `.onion` 索引 | |
| **TheDeepSearches** | `.onion` 索引 | |
| **DuckDuckGo-Tor** | `.onion` (DDG) | PGP 验证地址 |
| **Ahmia-clearnet** | clearnet HTTPS | Ahmia 的 clearnet 镜像 —— 始终可达 |
在大量运行之前使用 `check_search_engines()` 查看哪些引擎存活。
使用 `engines=["Ahmia", "Ahmia-clearnet"]` 获得快速可靠的结果,或者省略 `engines` 以获得最大覆盖率。
## 环境变量
将 `.env.example` 复制到 `.env`。所有变量都是可选的 —— 仅配置您需要的内容。
| 变量 | 默认值 | 描述 |
|---|---|---|
| `TOR_SOCKS_HOST` | `127.0.0.1` | Tor SOCKS5 代理主机 |
| `TOR_SOCKS_PORT` | `9050` | Tor SOCKS5 代理端口 |
| `TOR_CONTROL_HOST` | `127.0.0.1` | Tor 控制端口主机 |
| `TOR_CONTROL_PORT` | `9051` | Tor 控制端口 |
| `TOR_CONTROL_PASSWORD` | *(未设置)* | HashedControlPassword 的密码 |
| `TOR_DATA_DIR` | *(未设置)* | Tor DataDirectory 路径 —— 用于查找 `renew_identity` 的 cookie 文件 |
| `TOR_TIMEOUT` | `45` | 单次请求超时(秒) |
| `LLM_PROVIDER` | *(未设置)* | `openai` / `anthropic` / `gemini` / `ollama` / `llamacpp` |
| `OPENAI_API_KEY` | *(未设置)* | OpenAI API key |
| `OPENAI_MODEL` | `gpt-4o` | OpenAI 模型 |
| `ANTHROPIC_API_KEY` | *(未设置)* | Anthropic API key |
| `ANTHROPIC_MODEL` | `claude-opus-4-6` | Anthropic 模型 |
| `GEMINI_API_KEY` | *(未设置)* | Google Gemini API key |
| `GEMINI_MODEL` | `gemini-2.5-flash` | Gemini 模型 |
| `OLLAMA_BASE_URL` | `http://127.0.0.1:11434` | Ollama API base URL |
| `OLLAMA_MODEL` | `llama3.2` | Ollama 模型名称 |
| `LLAMACPP_BASE_URL` | `http://127.0.0.1:8080` | llama.cpp 服务器 base URL |
| `SICRY_MAX_CHARS` | `8000` | 传递给 LLM 的最大内容字符数 |
**`TOR_DATA_DIR` 是最重要的 Tor 变量。** 将其设置为 Tor 的 `DataDirectory` 路径,以便 `renew_identity()` 能够找到用于认证的 cookie 文件。
## Tor 设置
### 默认系统 Tor
如果您运行了 `apt install tor && tor &`,搜索、获取和 check_tor 将立即工作。控制端口默认可能未启用。
检查控制端口是否打开:
```
ss -tlnp | grep 9051
```
如果没有显示,请启用它:
```
echo "ControlPort 9051" >> /etc/tor/torrc
echo "CookieAuthentication 1" >> /etc/tor/torrc
systemctl restart tor
```
### SICRY™ 推荐的 torrc
用于开发 —— 一切都在 `/tmp` 中,无需更改系统:
```
SocksPort 9050
ControlPort 9051
CookieAuthentication 1
DataDirectory /tmp/tor_data
```
```
tor -f /tmp/sicry_tor.conf &
```
然后在 `.env` 中:
```
TOR_DATA_DIR=/tmp/tor_data
```
### 使用密码代替 cookie
```
# 生成哈希密码
tor --hash-password "mypassword"
# -> 16:...hash...
# 添加到 torrc
HashedControlPassword 16:...hash...
# 在 .env 中
TOR_CONTROL_PASSWORD=mypassword
```
### `renew_identity()` 认证工作原理
SICRY™ 按顺序尝试 4 种认证策略,直到有一种成功:
1. **`TOR_CONTROL_PASSWORD`** —— 使用环境变量作为字符串密码
2. **来自 `TOR_DATA_DIR` 的 Cookie 文件** —— 将 `$TOR_DATA_DIR/control_auth_cookie` 作为原始字节读取
3. **来自常见系统路径的 Cookie** —— 自动发现 `/tmp/tor_data`, `/var/lib/tor`, `~/.tor`, `/run/tor`
4. **Null/空认证** —— 用于完全没有设置控制密码的 Tor
如果全部四种都失败,则返回 `{"success": False, "error": "..."}` 及其有用的消息。**永不抛出异常。**
## 故障排除
**`tor_active: False`**
```
# Tor 是否正在运行?
pgrep tor || tor &
# SOCKS 端口是否开放?
ss -tlnp | grep 9050
```
**`renew_identity()` 返回 `success: False`**
```
# 控制端口是否开放?
ss -tlnp | grep 9051
# cookie 文件是否存在?
ls /tmp/tor_data/control_auth_cookie # custom torrc
ls /var/lib/tor/control_auth_cookie # system Tor
# 在 .env 中设置 TOR_DATA_DIR=/path/to/DataDirectory
```
**`.onion` 获取返回 `status: 0`**
隐藏服务已关闭或 Tor 速度慢。尝试 `search()` 中的另一个 URL,或先调用 `check_search_engines()` 确认 Tor 可达。
**搜索返回 0 个结果**
暗网索引经常宕机。运行 `check_search_engines()` 查找活跃的引擎,然后显式传递它们:`search(query, engines=["Ahmia", "Ahmia-clearnet"])`。
**`[SICRY™: OPENAI_API_KEY not set...]`**
设置 `LLM_PROVIDER=ollama` 以使用无密钥的本地推理,或将相关密钥添加到 `.env`。`search()`, `fetch()`, `check_tor()`, `renew_identity()`, `scrape_all()`, 和 `check_search_engines()` 都可以在没有任何 LLM 密钥的情况下工作。
**搜索缓慢**
Tor 具有可变的延迟。使用 `check_search_engines()` 找到最快的活跃引擎。`engines=["Ahmia", "Ahmia-clearnet"]` 是最快且可靠的配置。
**日志噪音 / stem DEBUG 输出**
SICRY™ 在导入时完全抑制 urllib3 和所有 stem 子记录器(`stem`, `stem.control`, `stem.response`, `stem.socket`, `stem.connection`, `stem.util`),将其设置为 CRITICAL 级别,使用 NullHandler 和 `propagate=False`。如果您仍然看到调试输出,请确保在配置任何根日志处理程序之前导入 `sicry`。
## 致谢
- 搜索引擎列表和 OSINT 提示词来自 [@apurvsinghgautam](https://github.com/apurvsinghgautam) 的 [Robin](https://github.com/apurvsinghgautam/robin) —— MIT 许可证
- 额外验证过的 `.onion` 地址来自 [dark.fail](https://dark.fail) (PGP 验证)
- Tor: [torproject.org](https://www.torproject.org/)
## 许可证
MIT License — Copyright (c) 2026 JacobJandon
完整文本见 [LICENSE](LICENSE)。
请负责任且合法地使用。
标签:AI风险缓解, Claude, CVE检测, DLL 劫持, ESC4, Gemini, LLM集成, MCP服务器, Onion路由, OpenAI, OSINT, Petitpotam, Robin OSINT, SOCKS5, Splunk, Tor网络, Web爬虫, 内存规避, 匿名代理, 单文件组件, 大语言模型, 威胁情报, 开发者工具, 搜索聚合器, 暗网访问, 网络安全, 网络隐私, 逆向工具, 隐私保护