Atathakr/maritime-osint
GitHub: Atathakr/maritime-osint
开源海事威胁情报平台,整合多源制裁筛查与 AIS 行为分析,专门用于识别规避制裁的影子船队。
Stars: 0 | Forks: 0
# 海事 OSINT — 制裁与影子船队情报




## 项目简介
影子船队 —— 那些故意隐瞒身份、所有权或行踪以逃避制裁的船只 —— 自 2022 年以来规模大幅增长。大多数开源工具要么只处理制裁筛查,要么只处理 AIS 跟踪,两者是割裂的。本平台将两者结合到一个面向分析师的界面中。
您加载一个船舶标识符(IMO 编号、MMSI 或名称),平台将返回:
- 该船只是否出现在 OFAC SDN、OpenSanctions、EU、UN 或其他名单上
- 根据 13 个行为和结构指标得出的综合风险评分(0–100)
- AIS 行为信号:黑暗期、船对船过驳、徘徊、速度异常
- 针对约 30 个受制裁或高风险码头停靠记录
- 船旗国风险等级和频繁换旗历史
- PSC 滞留记录(Paris MOU + Tokyo MOU)
- 针对制裁数据库的所有权链筛查
这是一个研究和分类工具。它不能替代专业的合规分析。所有信号应由合格的分析师进行解读。
## 功能特性
### 制裁筛查
| 能力 | 详情 |
|---|---|
| OFAC SDN | 美国财政部特别指定国民名单中的船舶条目 |
| OpenSanctions | 综合多司法管辖区名单:EU、UN SC、UK HMT、澳大利亚、加拿大、日本及其他 |
| 统一规范注册表 | 使用 IMO > MMSI > 名称+船旗哈希优先级,对列表中的船只进行去重 |
| 摄入后调和 | 两层合并:IMO 冲突扫描 + MMSI 到 IMO 升级 |
| 搜索 | IMO 编号、MMSI 或带有匹配置信度标签的部分船名 |
### 实时 AIS 跟踪
| 能力 | 详情 |
|---|---|
| 实时数据流 | 连接到 aisstream.io 的 WebSocket(支持免费层级) |
| 历史数据 | NOAA Marine Cadastre 月度 AIS CSV 摄入 |
| 船舶名册 | 每个 MMSI 一行,包含最后已知位置 |
| 航迹历史 | 每艘船 72 小时的航迹点轨迹(可配置至 168 小时) |
| 实时地图 | Leaflet 1.9.4,综合风险着色,船舶航迹 |
### 行为分析 —— 影子船队框架
该平台实施了用于影子船队风险评估的 31 项指标框架的一个子集。指标分为六类。
| 状态 | 数量 |
|---|---|
| 完全实施并评分 | 13 |
| 部分(已检测,未完全评分) | 1 |
| 尚未实施 | 10 |
| 开源数据无法实现 | 7 |
**已实施的指标:**
| 代码 | 名称 | 类别 |
|---|---|---|
| IND1 | AIS 黑暗期(应答器间隔 ≥ 2 小时) | AIS / 应答器 |
| IND2 | 速度异常 / AIS 欺骗代理(SOG > 50 节) | AIS / 应答器 |
| IND7 | 公海船对船过驳 | 移动 / 行为 |
| IND8 | 9 个指定高风险区域的 STS 过驳 | 移动 / 行为 |
| IND9 | 徘徊 / 异常的开放水域锚泊 | 移动 / 行为 |
| IND10 | 异常速度剖面 | 移动 / 行为 |
| IND15 | 频繁换旗(多次更改船旗) | 所有权 / 身份 |
| IND16 | 船名差异(AIS 与规范名对比) | 所有权 / 身份 |
| IND17 | 高风险 / 方便旗船旗国 | 所有权 / 身份 |
| IND21 | 所有权链制裁匹配 | 所有权 / 身份 |
| IND23 | 船龄(≥ 15 年为高风险) | 物理 / 运营 |
| IND29 | 停靠受制裁 / 高风险港口 | 港口 / 地理 |
| IND31 | PSC 滞留记录(Paris MOU / Tokyo MOU) | 港口 / 地理 |
### 风险评分
非受制裁船只获得 0 到 99 的综合评分。任何制裁名单上的船只总是获得 100 分。
```
risk_score = min(
min(dp_count × 10, 40) -- IND1 AIS dark periods
+ min(sts_count × 15, 45) -- IND7 STS transfers
+ min(sts_zone_count × 5, 10) -- IND8 STS in high-risk zones
+ flag_tier × 7 -- IND17 flag risk tier (max 21)
+ min(hop_count × 8, 16) -- IND15 flag hopping
+ min(spoof_count × 8, 24) -- IND10 speed anomalies
+ min(port_count × 20, 40) -- IND29 sanctioned port calls
+ min(loiter_count × 5, 15) -- IND9 loitering
+ max(0, min((age − 15) × 3, 15)) -- IND23 vessel age
+ min(owner_hits × 20, 40) -- IND21 ownership chain
+ min(psc_count × 10, 20), -- IND31 PSC detentions
99 -- hard ceiling for non-sanctioned
)
```
**船旗风险等级 (IND17):**
| 等级 | 分数 | 示例 |
|---|---|---|
| 3 — 高风险 / 受制裁 | 21 分 | 伊朗、俄罗斯、朝鲜、叙利亚、喀麦隆、坦桑尼亚、科摩罗 |
| 2 — 影子船队注册地 | 14 分 | 巴拿马、帕劳、多哥、加蓬、柬埔寨、塞拉利昂 |
| 1 — 主流开放式注册地 | 7 分 | 马绍尔群岛、利比里亚、巴哈马、伯利兹 |
| 0 — 标准 | 0 分 | 欧盟成员国、英国、美国、挪威、日本等 |
## 数据来源
| 来源 | 类型 | 许可 / 条款 | URL |
|---|---|---|---|
| OFAC SDN | 制裁名单 (XML) | 美国公共领域 | https://www.treasury.gov/ofac/downloads/sdn.xml |
| OpenSanctions | 综合制裁 (JSON) | CC BY-SA 4.0 | https://opensanctions.org |
| aisstream.io | 实时 AIS (WebSocket) | 提供免费层级 | https://aisstream.io |
| NOAA Marine Cadastre | 历史 AIS (CSV) | 美国公共领域 | https://marinecadastre.gov |
| Paris MOU | PSC 滞留 (CSV) | 公开 | https://www.parismou.org |
| Tokyo MOU | PSC 滞留 (CSV) | 公开 | https://www.tokyo-mou.org |
所有数据源均为公开可用。无需商业订阅。
## 快速开始(本地)
**要求:** Python 3.11 或更高版本,Git
```
git clone https://github.com/Atathakr/maritime-osint.git
cd maritime-osint
python -m venv .venv
# Linux / macOS
source .venv/bin/activate
# Windows
.venv\Scripts\activate
pip install -r requirements.txt
cp .env.example .env
# 编辑 .env — 本地开发所有字段可选
# 添加 AISSTREAM_API_KEY 以使用实时 AIS(在 aisstream.io 免费)
python app.py
```
打开 http://localhost:5000。
**初始数据加载(在浏览器中):**
1. 点击 **Fetch OFAC** —— 下载并解析 OFAC SDN XML(约 5–15 秒)
2. 点击 **Fetch OpenSanctions** —— 流式传输综合 JSON(约 30–90 秒)
3. 点击 **Reconcile** —— 合并重复的船舶记录
4. 可选:点击 **Start AIS** 以获取实时数据流(需要 API 密钥)
完成步骤 1–3 后,制裁筛查即可完全正常工作。AIS 行为分析在位置数据流动时激活。
## 环境变量
| 变量 | 必需 | 描述 |
|---|---|---|
| `DATABASE_URL` | 否 | PostgreSQL 连接字符串。省略以使用 SQLite。 |
| `APP_PASSWORD` | 否 | 仪表板登录页面的密码。留空以禁用身份验证。 |
| `SECRET_KEY` | 否 | Flask 会话密钥。如果未设置,将在启动时自动生成。 |
| `AISSTREAM_API_KEY` | 否 | aisstream.io 的 API 密钥。在 aisstream.io 免费注册。 |
## 部署(Railway)
1. Fork 本仓库。
2. 创建一个 Railway 项目并连接您的 fork。
3. 添加 **PostgreSQL 插件** —— Railway 会自动设置 `DATABASE_URL`。
4. 在 Railway 环境变量中设置 `APP_PASSWORD` 和 `AISSTREAM_API_KEY`。
5. 部署。`/health` 端点确认就绪状态。
`Procfile` 中 120 秒的 Gunicorn 超时是 OpenSanctions 流式摄入所必需的。
**自托管:** 任何运行 Python 和 Gunicorn 的平台均可。在生产环境中为 PostgreSQL 设置 `DATABASE_URL`,或留空以使用 SQLite。
## 架构概览
```
app.py Flask routes and auth middleware
├── ingest.py OFAC SDN + OpenSanctions + PSC CSV ingest
├── screening.py Unified vessel search and risk scoring engine
├── reconcile.py Two-tier canonical vessel deduplication
├── db.py Database abstraction layer (SQLite / PostgreSQL)
├── ais_listener.py aisstream.io WebSocket consumer (background thread)
├── dark_periods.py IND1 — AIS transponder gap detector
├── sts_detection.py IND7/8 — ship-to-ship proximity detector
├── loitering.py IND9 — open-water loitering detector
├── spoofing.py IND10 — speed anomaly detector
├── ports.py IND29 — sanctioned port call detector
├── noaa_ingest.py Historical AIS CSV ingest (NOAA Marine Cadastre)
├── normalize.py Flag normalisation, dataset labels, canonical IDs
├── risk_config.py Scoring weights, thresholds, flag tier registry
├── schemas.py Pydantic data models for all request/response types
└── map_data.py Geospatial data preparation for Leaflet frontend
```
## API 参考(部分端点)
如果设置了 `APP_PASSWORD`,则所有端点都需要身份验证。
| 方法 | 端点 | 描述 |
|---|---|---|
| POST | `/api/screen` | 按 IMO、MMSI 或名称筛查船只 |
| GET | `/api/screen/` | 特定船只的完整风险概况 |
| GET | `/api/sanctions` | 浏览带筛选功能的制裁条目 |
| POST | `/api/ingest/ofac` | 触发 OFAC SDN 摄入 |
| POST | `/api/ingest/opensanctions` | 触发 OpenSanctions 摄入 |
| POST | `/api/ingest/psc/` | 摄入 PSC 滞留 CSV |
| POST | `/api/reconcile` | 运行规范性去重 |
| POST | `/api/ais/start` | 启动 AIS WebSocket 监听器 |
| GET | `/api/ais/status` | AIS 监听器统计信息 |
| GET | `/api/ais/vessels` | AIS 船舶名册 |
| GET | `/api/ais/vessels//track` | 历史船舶航迹 |
| POST | `/api/dark-periods/detect` | 运行黑暗期检测 |
| POST | `/api/sts/detect` | 运行 STS 邻近检测 |
| POST | `/api/ais/detect-loitering` | 运行徘徊检测 |
| POST | `/api/ports/detect-calls` | 运行受制裁港口停靠检测 |
| POST | `/api/ais/detect-anomalies` | 运行速度异常检测 |
| GET | `/api/map/vessels` | 船舶位置 + 地图用的综合风险 |
完整的请求/响应模式在 `schemas.py` 中。
## 限制
31 项影子船队指标中有七项需要商业数据:
| 指标 | 为何不可行 |
|---|---|
| IND5 — 禁用 LRIT | 需要 LRIT 接收器网络订阅 |
| IND13 — 航次与货物不符 | 需要货物舱单 / 提单 |
| IND14 — VHF 通讯静默 | 需要海岸无线电监测 |
| IND22 — 伪造文件 | 需要文件验证访问权限 |
| IND24 — 物理改装 | 需要卫星图像 |
| IND25 — 吃水异常 | AIS 吃水是自我报告的,不具强制性 |
| IND28 — 货物不一致 | 需要海关 / 提单数据 |
速度异常检测器 (IND10) 是一个欺骗*代理* —— SOG > 50 节是一个保守的阈值。真正的 GNSS 欺骗检测需要与卫星接收器进行交叉参考。
AIS 覆盖盲区(非故意黑屏)存在于陆地接收器密度有限的地区。
## 贡献
有关开发设置、代码风格以及如何向框架添加新指标,请参阅 [CONTRIBUTING.md](CONTRIBUTING.md)。
## 安全
有关漏洞报告政策,请参阅 [SECURITY.md](SECURITY.md)。
## 许可证
本项目根据 [MIT 许可证](LICENSE) 授权。
数据许可证单独适用:
- OpenSanctions 数据:[CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)
- OFAC SDN 和 NOAA AIS 数据:美国政府公共领域
标签:AIS追踪, Flask, OFAC筛查, Python, 制裁合规, 地缘政治, 尽职调查, 影子舰队检测, 无后门, 测试用例, 海事分析, 自动识别系统, 船舶监控, 逆向工具, 金融犯罪