EnGRADE — 钓鱼防范意识培训
一个面向工程学生的交互式钓鱼防范培训平台——测验、视频培训和动手操作的“邮件威胁检查器”,全部在 AWS 上以无服务器方式运行。
旨在让钓鱼防御更实用、可衡量、更易于教学。
## 目录
- [关于项目](#about-the-project)
- [功能特性](#features)
- [技术栈](#tech-stack)
- [仓库结构](#repository-structure)
- [邮件样本库](#email-sample-library)
- [DynamoDB 架构](#dynamodb-schema)
- [快速启动(本地)](#quick-start-local)
- [Docker Compose](#docker-compose-recommended-for-local-dev)
- [Make 命令目标](#make-targets)
- [CI/CD 概述](#cicd-overview)
- [AWS 部署](#aws-deployment)
- [文档索引](#documentation-index)
- [看板](#workboard)
- [管理操作](#admin-operations-guide)
- [改进示例邮件](#improving-example-emails-realism-checklist)
- [贡献指南](#contributing)
- [更新日志与许可](#changelog--license)
## 关于项目
**EnGRADE**(前身为 *Master-Project-Phishing*)是一个为 [ESME](https://www.esme.fr/) 工程学校硕士课程设计的全栈钓鱼防范培训应用。名称源自击剑术语“En garde(戒备)”,寓意时刻保持警惕,与项目使命相符:在学生成为真正受害者之前,训练他们识别并防御钓鱼攻击。
平台包含两个互补的培训工具:
| 工具 | 描述 |
|---|---|
| **钓鱼测验** | 在观看培训视频后进行的单项选择题测验,用于检测学生对真实钓鱼技术的识别能力。 |
| **邮件威胁检查器** | 一个沙箱邮件查看器,用于分析真实的 `.eml` 钓鱼与垃圾邮件样本。学生对每封邮件进行分类并识别其中的钓鱼信号。 |
两个工具的结果都会按学生和 cohort 进行追踪,使讲师能够通过管理仪表板获得可操作的分析数据。
### 10 种钓鱼信号类别
检查器中的每封钓鱼邮件都会标注以下一种或多种信号:
| 信号 | Key | 描述 |
|---|---|---|
| 冒充 | `impersonation` | 发件人假装是某个已知人员或品牌 |
| 域名欺骗 / Punycode | `punycode` | 使用同形或拼写欺骗的类似域名 |
| 外部发件人域名 | `externaldomain` | 邮件来自与声称发件人无关的域名 |
| 伪造 | `spoof` | 显示名称或邮件头被精心伪造以误导 |
| 社会工程 | `socialeng` | 利用心理操纵(权威、恐惧、好奇心) |
| 紧迫性 | `urgency` | 人为制造时间压力以绕过批判性思维 |
| 虚假发票 | `fakeinvoice` | 欺诈性账单或付款请求 |
| 恶意附件 | `attachment` | 被伪装成合法文档的危险文件 |
| 伪造登录页 | `fakelogin` | 链接指向用于窃取凭证的页面 |
| 侧信道通信 | `sidechannel` | 使用二维码、电话号码或其他带外向量 |
## 功能特性
### 钓鱼测验
- 涵盖 URL 分析、伪造、紧迫性战术、CEO 欺诈、Smishing、MFA 绕过等内容的单项选择题
- 每题后提供详细解释,说明答案正确的原因
- 进度条、颜色编码的分数摘要、等级徽章以及每位用户的完整测验历史
- 每项测验在观看培训视频后才会解锁
- 测验定义在 DynamoDB 中,通过 `seed_dynamodb.py` 种子初始化——无需修改代码即可添加新测验
### 邮件威胁检查器
- 位于 `/inspector/` 的独立工具,用于对存储在 S3 中的真实 `.eml` 文件进行动手分析
- 渲染:邮件概览、完整头部、沙箱 HTML 预览、提取的链接、附件列表和安全警告
- 用户将每封邮件分类为 **垃圾邮件** 或 **钓鱼邮件**,并选择使其暴露的信号
- 每个会话最多从 S3 存储桶中随机抽取 8 封邮件(1–3 封垃圾邮件 + 钓鱼邮件)
- 每封邮件所需的信号数量是动态的——由答案键决定,绝不硬编码
- 提交内容保存到符合 GDPR 的匿名表(不存储用户名)
- 全部 8 封邮件提交后会话锁定;管理员可单独或按 cohort 重置
### 管理仪表板
- 概览统计:总用户数、总测验尝试次数、平均分数、分数分布图表
- 每项测验统计、cohort 分析以及检查器信号准确性报告
- 实时统计轮询和 OpenPhish 实时威胁源小部件
- 使用 Redis/ElastiCache 的发布/订阅机制实现实时 SSE 仪表板更新,以及基于 SQS 后端的活动启动器(Lambda 邮件发送器 + SES),支持可选的 EventBridge 调度
- **风险仪表板**:结合测验失败率和检查器信号遗漏率的 cohort 风险评分
- 使用预签名 S3 链接生成 CSV 报告
- **答案键编辑器**:可在不进行代码部署的情况下更改任意邮件的分类和信号;DynamoDB 中的覆盖值优先于静态的 `answer_key.py`
### 身份验证与用户管理
- 使用表单验证和 Werkzeug 密码哈希的登录 / 登出
- 通过 `role` 字段(`admin`、`instructor`、`student`)管理角色——管理员与讲师共享仪表板访问权限;当启用 SSO 时,角色映射至 Microsoft 365 群组
- 当前存在用于二维码辅助注册的公开 `/auth/register` 页面;令牌强化正在追踪(问题 `#78`)
- 支持通过 CSV 批量导入学生
- 生成二维码供 cohort 自助注册:学生扫码 → 填写表单 → Lambda 工作器创建账户并发送 SES 确认邮件
- 学生可自行更改密码
## 技术栈
| 组件 | 技术 |
|-----------|-----------|
| 后端 | Flask 3.1(Python 3.12)、Flask-Login、Flask-WTF、Werkzeug |
| 数据库 | AWS DynamoDB — 9 张按需表 |
| 前端 | Jinja2 + Bootstrap 5(CDN)、Chart.js |
| EML 解析 | Python `email` 标准库(零额外依赖) |
| 二维码 | qrcode[pil] 8.0 |
| Lambda 适配器 | Mangum 0.19(AWS Lambda 的 ASGI 包装器) |
| WSGI 服务器 | Gunicorn 23(本地 / Docker) |
| 异步工作器 | AWS SQS + Lambda(注册工作器) |
| 邮件 | AWS SES |
| 追踪 | AWS X-Ray SDK |
| 部署 | AWS Lambda + API Gateway v2 + CloudFront + Terraform |
| CI/CD | GitHub Actions(OIDC —— 无静态 AWS 密钥) |
**依赖要求:** Python 3.12 · Terraform >= 1.5 · AWS CLI v2 · Docker + Compose。完整的 IAM 权限列表请参见 [`documentation/REQUIREMENTS.md`](documentation/REQUIREMENTS.md),10 张详细 Mermaid 架构图请参见 [`documentation/ARCHITECTURE.md`](documentation/ARCHITECTURE.md)。
## 仓库结构
该仓库被组织为一个单体仓库,其中 **Flask 应用** 与 **AWS 基础设施** 之间有明确的边界。请参考 [`documentation/REPO_SEPARATION.md`](documentation/REPO_SEPARATION.md) 了解如何将它们拆分为两个独立的仓库。
```
master-Project-Phishing/
├── app/ # Flask application (blueprints, models, templates, static)
├── tests/ # Pytest test suite
├── scripts/ # Build, content, and utility scripts
├── documentation/ # Full documentation suite
│ ├── dev/ # Developer guides (setup, contributing, testing, EML)
│ ├── operator/ # Operations guides (deployment, infra, CI/CD)
│ ├── user/ # End-user guides (student, admin)
│ ├── ARCHITECTURE.md # System design + Mermaid diagrams
│ └── REPO_SEPARATION.md # Guide to splitting app vs infra into separate repos
├── examples/ # Real-world .eml phishing samples
├── nginx/ # Nginx reverse proxy configuration
├── phishing-platform-infra/ # AWS infrastructure (Terraform, Lambda source, scripts)
│ ├── terraform/ # Infrastructure as Code (Lambda, DDB, S3, CloudFront…)
│ ├── lambda/ # Lambda function source code
│ │ ├── campaign_mailer/ # Campaign mailer Lambda (SQS → SES)
│ │ └── registration_worker/ # Registration worker Lambda (SQS → DDB → SES)
│ ├── ansible/ # Optional VM deployment playbooks
│ ├── aws/ # Legacy EC2 deployment guide (deprecated)
│ └── scripts/ # Infra + migration helper scripts
├── .github/workflows/ # GitHub Actions CI/CD
├── jury-presentation/ # Project review presentation materials
├── phishing-aoc/ # TryHackMe Advent of Cyber reference materials
├── Dockerfile # Python 3.12-slim + Gunicorn
├── docker-compose.yml # Web + Nginx + DynamoDB Local dev stack
├── seed_dynamodb.py # Seeds admin user + quizzes
├── setup_local_db.py # Creates all DynamoDB tables locally
├── config.py # Env var → app config mapping
├── run.py # Local development entry point
├── requirements.txt # Python runtime dependencies
├── Makefile # Build and workflow shortcuts
├── VERSION # Current version
└── CHANGELOG.md # Version history
```
### `app/` —— Flask 应用
Flask 应用由 `app/__init__.py` 中的 `create_app()` 工厂创建。它在应用对象上初始化 `boto3` 客户端(DynamoDB、S3、S),然后注册四个蓝图:
| 蓝图 | URL 前缀 | 职责 |
|-----------|-----------|----------------|
| `app/auth/` | `/auth` | 登录、登出、修改密码、二维码自助注册、CSV 批量导入 |
| `app/quiz/` | `/quiz` | 测验列表、视频门控、参与测验、完成/结果、历史记录 |
| `app/dashboard/` | `/dashboard` | 管理统计、cohort 分析、风险仪表板、CSV 报告、答案键编辑器、错误报告 |
| `app/inspector/` | `/inspector` | 邮件威胁检查器 —— EML 列表、详细视图、提交答案(JSON API) |
关键文件:
| 文件 | 用途 |
|---|---|
| `app/models.py` | **单一数据访问层** —— 所有 DynamoDB 的读写操作。切勿直接从路由调用 `boto3`。 |
| `app/inspector/answer_key.py` | 静态地面真实基线:每个邮件文件的分类(`Phishing`/`Spam`)与所需信号 |
| `app/templates/` | 按蓝图组织的 Jinja2 模板(`base.html`、`auth/`、`quiz/`、`dashboard/`、`inspector/`) |
| `app/static/` | CSS、JS、SVG 图标、品牌 Logo、培训视频(视频被 .gitignore,需托管在 S3) |
| `app/static/images/en_garde_logo.png` | EnGarde 项目 Logo |
| `app/static/images/esme_logo.png` | ESME 学校 Logo |
| `app/static/images/logos/` | 用于钓鱼培训邮件的 11 个 SVG 品牌 Logo |
### `tests/` —— 测试套件
基于 pytest 的测试,全部通过 `moto` 模拟 AWS。不需要真实的 AWS 账户。
- `conftest.py` —— `mock_aws()` 固件创建全部 9 张 DynamoDB 表和 S3 存储桶;提供 `seed_admin`、`seed_user`、`seed_quiz` 固件以及 `login()` 辅助函数
- 测试模式下禁用 CSRF
- 运行:`make test`(输出 JUnit XML 报告)
- 代码检查:`make lint`(flake8,最大行长度 120)
### `phishing-platform-infra/` —— 基础设施仓库
基础设施现已隔离在 `phishing-platform-infra/` 目录中,以便推送到独立的 `phishing-platform-infra` 仓库。请在 `phishing-platform-infra/terraform/` 目录下运行所有 Terraform 命令。
| 路径 | 用途 |
|---|---|
| `terraform/` | AWS IaC(Lambda、API Gateway、DynamoDB、S3、CloudFront、IAM、SQS、SNS、CloudWatch) |
| `ansible/` | 可选的 VM 配置剧本(替代 Lambda 方案) |
| `aws/` | 遗留 EC2 用户数据脚本与 AMI 笔记 |
| `scripts/` | 基础设施与迁移辅助脚本(`import_resources.sh`、`migrate_dynamodb.py`、`migrate_inspector_attempts.py`、`migrate_s3.sh`) |
| `terraform.tfstate` | 本地状态快照(部署前请迁移至远程状态) |
**Terraform 模块索引(`phishing-platform-infra/terraform/`):**
| 文件 | AWS 服务 |
|---|---|
| `lambda.tf` | Flask 应用 Lambda(Python 3.12,512 MB,30 秒超时) |
| `lambda_registration_worker.tf` | 注册工作器 Lambda(256 MB) |
| `api_gateway.tf` | HTTP API v2 —— 捕获全部 `$default` 指向 Lambda 代理 |
| `cloudfront.tf` | CloudFront 分发 —— 通过 API Gateway 提供稳定 URL |
| `dynamodb.tf` | 9 张按需 DynamoDB 表及其 GSIs |
| `s3.tf` | S3 存储桶用于 EML 样本与培训视频 |
| `sqs_registration.tf` | SQS 队列与死信队列 |
| `sns_ses_registration.tf` | SNS 主题 + SES 身份,用于确认邮件 |
| `cloudwatch_monitoring.tf` | 告警、仪表板、X-Ray 追踪 |
| `iam.tf` | Lambda 执行角色 + GitHub Actions OIDC 部署角色 |
| `acm_custom_domain.tf` | ACM 证书 + Route 53 DNS 验证(可选) |
| `github_actions_oidc.tf` | CI/CD 的联邦身份(无静态密钥) |
| `bootstrap/` | 一次性设置:创建 Terraform 状态 S3 存储桶 |
| `backend/dev.hcl` · `backend/prod.hcl` | 每环境远程状态配置 |
**环境:** `dev`(推送至 `main` 自动部署)与 `prod`(手动调度)。两者均使用 OIDC —— 不在 GitHub 密钥中存储 AWS 凭据。
### `documentation/` —— 完整文档套件
共 23 份文档,按受众组织。请参见下方 [文档索引](#documentation-index) 部分获取完整链接表格。
```
documentation/
├── ARCHITECTURE.md # 10 Mermaid diagrams: system overview, AWS infra,
│ # DynamoDB schema, CI/CD, all major flows
├── REQUIREMENTS.md # Infrastructure, functional & IAM requirements
├── AUDIT_AND_ROADMAP.md # Audit findings + feature roadmap
├── AWS_IMPROVEMENTS.md # AWS cost and architecture optimisation proposals
├── COMPLIANCE_FRAMEWORKS.md # Compliance framework overview
├── GDPR_COMPLIANCE.md # GDPR notes (anonymous inspector table, data retention)
├── FEATURE_PROPOSALS.md # Future feature ideas
├── dev/ # Developer guides (setup, contributing, adding content)
├── operator/ # Operator guides (deployment, infrastructure, CI/CD, maintenance)
└── user/ # User guides (student handbook, admin guide)
```
### `examples/` —— 钓鱼邮件样本库
检查器包含 98 封模拟真实场景的 `.eml` 文件,按攻击类别组织。所有文件同步到 S3 的 `eml-samples/` 前缀下。
```
examples/
├── fake-invoice/ # PayPal, Microsoft, FedEx, Apple invoice fraud
├── impersonation/ # Voice messages, SharePoint, Zoom, IT Helpdesk, callback phishing
├── impersonation-urgency/ # Impersonation + urgency combinations
├── legit-impersonation/ # Convincing legitimate-looking impersonation
├── punycode/ # Homograph attacks, typosquatting, subdomain deception
├── realistic_templates/ # High-fidelity spam and phishing templates
├── spam/ # Marketing, logistics, newsletter, coupon, QR, survey
├── linksec/ # Cloud service impersonation (15 platforms — see below)
│ ├── amazon-web-services-aws/
│ ├── bluejeans/
│ ├── cisco/
│ ├── google-cloud-platform-gcp/
│ ├── google-workspace/
│ ├── gotomeeting/
│ ├── ibm-cloud/
│ ├── microsoft-azure/
│ ├── microsoft-office-365/
│ ├── microsoft-teams/
│ ├── oracle-cloud/
│ ├── ringcentral/
│ ├── skype-for-business/
│ ├── slack/
│ └── zoom/
├── compliance_report.md # EML compliance audit report
└── realism_allowlist.json # Files exempt from the realism validator
```
添加新的 `.eml` 文件时:上传至 S3(`make sync-eml`),然后在 `app/inspector/answer_key.py` 中添加对应条目。文件中未包含的条目将在运行时被排除在检查器池外。
### `scripts/` —— 构建与内容工具脚本(应用)
| 脚本 | 用途 |
|---|---|
| `build_lambda.sh` | 将 Flask 应用打包为 `lambda.zip` |
| `build_registration_worker.sh` | 打包注册工作器为 `registration_worker.zip` |
| `build_campaign_mailer.sh` | 打包 Campaign Mailer Lambda 构件 |
| `validate_eml_realism.py` | 检查 `.eml` 文件是否符合现实主义标准 |
| `audit_eml.py` | 对所有 `.eml` 文件执行合规审计;输出 `compliance_report.md` |
| `generate_eml_samples.py` | 辅助生成新的 `.eml` 样本文件 |
| `fix_eml_names.py` | 标准化 `.eml` 文件名 |
| `fix_eml_images.py` | 将内联图片转换为 base64 编码 |
| `backfill_cohorts.py` | 补全 cohort 字段 |
| `generate_management_deck.py` / `.sh` | 生成管理摘要演示文稿 |
基础设施与迁移辅助脚本现位于 `phishing-platform-infra/scripts/`。
### `phishing-platform-infra/lambda/` —— Lambda 函数源码
独立 AWS Lambda 函数,用于处理异步后台任务。源码位于 `phishing-platform-infra/lambda/`,并由对应 Terraform 定义部署。
#### `registration_worker/` —— 注册工作器
1. 学生扫描二维码 → 填写注册表单
2. Flask 应用将请求入队至 **SQS**
3. **SNS** 触发此 Lambda 接收消息
4. Lambda 在 DynamoDB 中创建用户账户并发送 **SES** 确认邮件
关键文件:`phishing-platform-infra/lambda/registration_worker/handler.py`
#### campaign_mailer/ —— Campaign Mailer Lambda
处理来自 SQS 的钓鱼模拟活动消息,向目标 cohort 群发 SES 邮件,并在 DynamoDB 与 Redis 中记录投递事件。
关键文件:`phishing-platform-infra/lambda/campaign_mailer/handler.py`
### `nginx/` —— 反向代理
用于本地开发(Docker Compose)与可选的 Ansible VM 部署的 Nginx 配置:
- 直接服务 `app/static/`(绕过 Gunicorn 处理静态资源)
- 将所有其他请求代理至 5000 端口的 Gunicorn
### `phishing-platform-infra/ansible/ —— 可选 VM 配置
用于在传统 VM 上部署应用的 Ansible 剧本(替代 Lambda/Terraform 方案)。
请参考 `phishing-platform-infra/ansible/README.md` 获取所需变量。
### `.github/workflows/` —— CI/CD 流水线
| 工作流 | 触发条件 | 目的 |
|---|---|---|
| `ci.yml` | 推送至任意分支、PR 到 `main` | 代码检查(flake8)、EML 真实性验证、测试(pytest + moto)、构建 Lambda 构件 |
| `deploy-dev.yml` | 推送至 `main` | 运行 CI → Terraform 计划 → 应用 → 同步 S3 → 种子 DynamoDB(可跳过) |
| `deploy-prod.yml` | 手动调度 | 同上流程,目标环境为 `prod`(需环境审批) |
| `destroy.yml` | 手动调度 | 拆除所有 Terraform 管理的 AWS 资源 |
| `claude.yml` | PR / Issue 事件 | Claude AI 自动化 |
| `code-review.yml` | PR 事件 | 为 main 分支的 Pull Request 提供审查上下文摘要 |
所有工作流均使用 **OIDC** 进行 AWS 访问 —— 不在 GitHub 密钥中存储静态 AWS 凭据。请将 `AWS_DEPLOY_ROLE_ARN` 与 `TF_VAR_SECRET_KEY` 设置为 GitHub Actions 密钥。
## 邮件样本库
检查器包含模拟以下广泛使用平台与服务的钓鱼邮件:
| 类别 | 示例 |
|---|---|
| 虚假发票 | PayPal、微软、FedEx、Apple 收据伪造 |
| 冒充 | 语音留言、SharePoint、Zoom、IT 帮助台 |
| 紧迫性 | DocuSign、OneDrive、VPN 安全事件 |
| 合法应用冒充 | Slack、Adobe、GitHub 风格 |
| 域名欺骗 / Punycode | Google、通用同形攻击 |
| 垃圾邮件 | 营销、物流、新闻简报、优惠券、二维码、调查 |
| 高级技术 | 线程劫持、像素追踪、回调钓鱼、SSO 欺骗、横向钓鱼 |
| LINKSEC 模板 | AWS、BlueJeans、Cisco Webex、Google Cloud、微软 Azure、Office 365、Teams、Oracle、RingCentral、Skype、Slack、Zoom |
所有 130 封已分类邮件的地面真实数据位于 [`app/inspector/answer_key.py`](app/inspector/answer_key.py)。管理员可通过仪表板的“答案键编辑器”在运行时覆盖任意邮件的分类与信号列表 —— 无需代码部署。
## DynamoDB 架构
| 表 | 用途 |
|---|---|
| `users` | 登录凭据 + cohort 字段(班级/年/专业/学院)、检查器状态(已提交列表 + 锁定标志) |
| `quizzes` | 测验定义,包含内嵌问题数组与视频 URL |
| `attempts` | 测验分数 + cohort 字段,用于分析(每位用户每项测验仅一条记录,通过条件表达式强制) |
| `responses` | 每题答案详情,用于详细报告 |
| `inspector_attempts` | 旧版检查器认证尝试(新流程使用匿名表) |
| `inspector_attempts_anon` | 符合 GDPR 的匿名检查器尝试(不存储用户名) |
| `bugs` | 用户提交的缺陷报告与状态追踪 |
| `answer_key_overrides` | 可由管理员编辑的答案键覆盖,在运行时合并到 `answer_key.py` |
| `cohort_tokens` | 二维码自助注册令牌,90 天 TTL |
| `threat_cache` | OpenPhish 源缓存(Redis/DynamoDB 混合),带 TTL |
| `campaigns` | 钓鱼模拟活动定义与状态 |
| `campaign_events` | 活动投递/打开/点击/验证审计追踪 |
所有表均采用 **按需计费**(PAY_PER_REQUEST)。表名通过环境变量配置 —— 参见 `config.py`。
## 快速启动(本地)
```
# 创建并激活 venv
python3 -m venv .venv
source .venv/bin/activate
# 安装依赖项
python -m pip install -r requirements.txt
# 启动 DynamoDB Local
docker run -d -p 8766:8000 amazon/dynamodb-local
# 配置环境并初始化数据
export DYNAMODB_ENDPOINT=http://localhost:8766
export AWS_REGION_NAME=eu-west-3
export AWS_ACCESS_KEY_ID=fake
export AWS_SECRET_ACCESS_KEY=fake
export DYNAMODB_USERS=phishing-app-dev-users
export DYNAMODB_QUIZZES=phishing-app-dev-quizzes
export DYNAMODB_ATTEMPTS=phishing-app-dev-attempts
export DYNAMODB_RESPONSES=phishing-app-dev-responses
export DYNAMODB_INSPECTOR=phishing-app-dev-inspector-attempts
export DYNAMODB_INSPECTOR_ANON=phishing-app-dev-inspector-attempts-anon
export DYNAMODB_BUGS=phishing-app-dev-bugs
export DYNAMODB_ANSWER_KEY_OVERRIDES=phishing-app-dev-answer-key-overrides
export DYNAMODB_COHORT_TOKENS=phishing-app-dev-cohort-tokens
export DYNAMODB_THREAT_CACHE=phishing-app-dev-threat-cache
export DYNAMODB_CAMPAIGNS=phishing-app-dev-campaigns
export DYNAMODB_CAMPAIGN_EVENTS=phishing-app-dev-campaign-events
export S3_BUCKET=phishing-app-dev-eu-west-3
export SQS_CAMPAIGN_QUEUE_URL=https://sqs.eu-west-3.amazonaws.com/123456789012/phishing-app-dev-campaigns
export SECRET_KEY=dev-secret
python seed_dynamodb.py
# 运行开发服务器
python run.py
```
应用运行在 **http://localhost:5000**。默认管理员:`admin` / `admin123`
**常见问题:**
- **PEP 668 / 受外部管理的环境**:请使用虚拟环境(`python3 -m venv .venv`),而非系统 Python。
- **缺少 `lambda.zip`**:运行 `./scripts/build_lambda.sh`。
- **AWS 凭据问题**:设置 `AWS_PROFILE=terraform-deployer` 再执行 Terraform。
- **视频在 Lambda 中无法加载**:设置 `VIDEO_BASE_URL` 为 S3/CloudFront 的视频基础 URL 并重新运行 `seed_dynamodb.py`。
- 示例:`VIDEO_BASE_URL=https://phishing-app-dev-eu-west-3.s3.eu-west-3.amazonaws.com/videos`
- 上传:`make sync-assets`(需 Terraform 状态)或:`aws s3 sync app/static/videos/ s3://phishing-app-dev-eu-west-3/videos/ --exclude "*" --include "*.mp4" --region eu-west-3`
## Docker Compose(推荐本地开发)
```
# 构建并启动所有服务(Nginx :80 -> Gunicorn -> Flask -> DynamoDB Local :8766)
docker compose up -d --build
# 创建表并初始化数据库
python setup_local_db.py # creates all 9 DynamoDB tables
docker compose exec web python seed_dynamodb.py # seeds admin user + quizzes
# 停止
docker compose down
```
访问 **http://localhost**(端口 80)。Compose 栈运行以下三个服务:
| 服务 | 镜像 | 用途 |
|---|---|---|
| `dynamodb-local` | `amazon/dynamodb-local` | 内存中的 DynamoDB,运行在 8766 端口 |
| `web` | 本地 Dockerfile | Gunicorn + Flask 应用 |
| `nginx` | `nginx:alpine` | 反向代理 + 静态资源服务(端口 80) |
## Make 命令目标
```
make lint # flake8 --max-line-length=120
make test # pytest + moto (JUnit XML report)
make lambda # build lambda.zip
make registration-worker # build registration_worker.zip
make campaign-mailer # build campaign_mailer.zip
make validate-eml # validate .eml file realism
make sync-eml # sync examples/*.eml -> S3 eml-samples/
make sync-assets # sync app/static/videos/*.mp4 -> S3 videos/
make audit-eml # run compliance audit, generate report
```
## CI/CD 概述
**`ci.yml`** —— 在每次推送和 PR 到 `main` 时运行:
1. 代码检查(flake8)+ EML 真实性验证
2. 测试(pytest + moto)——生成 JUnit XML 报告并上传为构件
3. 构建 `lambda.zip` 与 `registration_worker.zip`
**`deploy-dev.yml`** —— 在推送至 `main` 时自动部署:
1. 运行 CI(`ci.yml`)
2. 引导 IAM(对 OIDC 提供者的幂等 `terraform import` 与部署角色)
3. `terraform plan` → 上传计划构件
4. `terraform apply` —— 创建所有 AWS 基础设施
5. 同步 EML 样本与视频资源至 S3
6. 种子 DynamoDB(可通过 `skip_seed=true` 跳过)
**`deploy-prod.yml`** —— 手动调度 `workflow_dispatch`:
- 与开发流程相同的构建 → 计划 → 应用流程,目标为 `prod` 环境(需环境审批规则)
**`destroy.yml`** —— 手动拆除:
- 移除 Terraform 管理的 IAM 资源(保留部署角色以便后续 CI 使用)
- 可选清空版本化的 S3 存储桶
所有工作流均使用 **OIDC** 进行 AWS 访问 —— 不在 GitHub 密钥中存储静态 AWS 凭据。
## AWS 部署
完整的 Terraform 与 AWS 部署指南: [`documentation/operator/DEPLOYMENT.md`](documentation/operator/DEPLOYMENT.md)
### 一次性引导 Terraform 远程状态
```
cd phishing-platform-infra/terraform/bootstrap
terraform init
terraform apply \
-var="state_bucket_name=phishing-terraform-state" \
-var="lock_table_name=phishing-terraform-locks" \
-var="aws_region=eu-west-3"
```
### GitHub Actions 密钥
| 密钥 | 值 |
|---|---|
| `AWS_DEPLOY_ROLE_ARN` | 通过 `terraform output github_actions_deploy_role_arn` 输出 |
| `TF_VAR_SECRET_KEY` | 生成:`python3 -c "import secrets; print(secrets.token_hex(32))"` |
在 **Settings → Environments** 中创建 `dev` 与 `prod` 环境。
### 开发环境 → 生产环境数据迁移
```
# 迁移 S3 存储桶和 DynamoDB 表(保留密码哈希)
./phishing-platform-infra/scripts/migrate_s3.sh
python3 ./phishing-platform-infra/scripts/migrate_dynamodb.py --from dev --to prod
# 先进行干运行
MIGRATE_DRY_RUN=true ./phishing-platform-infra/scripts/migrate_s3.sh
MIGRATE_DRY_RUN=true python3 ./phishing-platform-infra/scripts/migrate_dynamodb.py --from dev --to prod --dry-run
```
## 文档索引
| 指南 | 受众 | 描述 |
|---|---|---|
| [看板](documentation/WORKBOARD.md) | 维护者 | 实时里程碑、问题与分支映射,用于深度扫描待办事项 |
| [架构](<_URL_25/>) | 所有人 | 10 张 Mermaid 图:系统、AWS 架构、Schema、CI/CD、数据流 |
| [需求](documentation/REQUIREMENTS.md) | 所有人 | 基础设施、功能与 IAM 需求 |
| [审计与路线图](documentation/AUDIT_AND_ROADMAP.md) | 所有人 | 已知问题与未来功能路线图 |
| [GDPR 合规](documentation/GDPR_COMPLIANCE.md) | 所有人 | 匿名表、数据保留与隐私说明 |
| [AWS 改进](documentation/AWS_IMPROVEMENTS.md) | 所有人 | 成本与架构优化建议 |
| [合规框架](documentation/COMPLIANCE_FRAMEWORKS.md) | 所有人 | ISO 27001、NIST、GDPR 映射 |
| [功能提案](documentation/FEATURE_PROPOSALS.md) | 所有人 | 未来增强建议 |
| | | |
| [开发者指南](documentation/dev/README.md) | 开发者 | 全部开发文档索引 |
| [本地环境搭建](documentation/dev/SETUP.md) | 开发者 | Docker Compose + DynamoDB Local 配置 |
| [贡献指南](documentation/dev/CONTRIBUTING.md) | 开发者 | 如何提交代码或邮件样本 |
| [添加邮件样本](documentation/dev/ADDING_EML_FILES.md) | 开发者 | 扩充邮件样本库 |
| [添加测验](documentation/dev/ADDING_QUIZZES.md) | 开发者 | 创建新的测验模块 |
| [开发架构](documentation/dev/ARCHITECTURE.md) | 开发者 | 内部实现细节 |
| | | |
| [学生指南](documentation/user/STUDENT_GUIDE.md) | 学生 | 如何使用测验与检查器 |
| [管理员指南](documentation/user/ADMIN_GUIDE.md) | 管理员 | 仪表板操作与用户管理 |
| | | |
| [运维指南](documentation/operator/README.md) | 运维人员 | 索引 |
| [部署](documentation/operator/DEPLOYMENT.md) | 运维人员 | 分步 Terraform + AWS 部署 |
| [基础设施](documentation/operator/INFRASTRUCTURE.md) | 运维人员 | AWS 资源参考 |
| [CI/CD](documentation/operator/CICD.md) | 运维人员 | GitHub Actions 工作流详解 |
| [维护](documentation/operator/MAINTENANCE.md) | 运维人员 | 运营任务(种子、迁移、重置) |
## 看板
请参考 [`documentation/WORKBOARD.md`](documentation/WORKBOARD.md) 作为看板、后备事项与分支命名约定的单一事实来源。
## 管理员操作指南
### 导入学生(CSV)
1. 以管理员身份登录 → **管理 → 导入用户**
2. 上传包含以下必需列的 CSV:
```
username,email,password,class,academic_year,major,facility,group
jdoe,jdoe@school.edu,TempPass123,Class A,2025,CS,Paris,engineering
asmith,asmith@school.edu,TempPass456,Class B,2025,Marketing,Lyon,marketing
```
所有列均为必填项;若未提供 `group`,则默认为 `default`。
### 二维码自助注册
1. 以管理员身份登录 → **管理 → 生成二维码**
2. 提交表单以生成指向 `/auth/register` 的二维码
3. 下载并分享/打印该 PNG 图像
4. 学生扫码 → 填写表单 → 收到 SES 确认邮件(由注册工作器处理)
### 上传邮件样本(.eml)
```
aws s3 sync examples/ s3://phishing-app-
-eu-west-3/eml-samples/ \
--exclude "*" --include "*.eml"
```
上传后,请在 `app/inspector/answer_key.py` 中添加对应的条目。
### 重置检查器访问
每位用户仅可提交一次对分配到的 8 封邮件的答案。全部提交后检查器将锁定。管理员可执行以下重置操作:
- 单个用户:**管理 → 检查器分析 → 重置用户**
- 按 cohort 或全部用户:批量重置筛选器
### GDPR 数据迁移(旧版检查器数据)
若存在包含用户名的旧版检查器尝试记录,请将其迁移至匿名表:
```
python3 phishing-platform-infra/scripts/migrate_inspector_attempts.py --dry-run
python3 phishing-platform-infra/scripts/migrate_inspector_attempts.py
```
### 下载报告
1. **管理 → 报告** —— 测验 / cohort CSV 报告
2. **管理 → 检查器分析** —— 检查器 cohort 报告
3. 点击 **下载 CSV** —— 获取有效期 15 分钟的预签名 S3 链接
## 改进示例邮件(真实性检查清单)
为使 `examples/` 中的邮件更接近真实钓鱼场景,建议:
- **多部分邮件**:包含 `text/plain` 与 `text/html` 两个部分
- **HTML 布局**:使用表格、按钮、品牌颜色与页脚/法律文本
- **内嵌图片**:CID 嵌入的 Logo 与远程图片引用
- **二维码**:嵌入指向测试 URL 的二维码图片
- **追踪像素**:1x1 像素用于模拟打开追踪
- **附件**:PDF 发票、HTML 文件或 ZIP(无害占位符)
- **头部真实性**:Reply-To 不匹配、Return-Path 不匹配、SPF/DKIM/DMARC 结果
- **域名欺骗**:子域名技巧与同形攻击(punycode)
- **紧迫性与社会工程**:时间压力、权威暗示或恐惧诱导
提交前请运行验证器:
```
make validate-eml # writes examples/realism_report.json
```
应被豁免的文件请将其加入 `examples/realism_allowlist.json`。
**参考数据集:**
- https://github.com/SeanWrightSec/phishing-examples
- https://github.com/sunknighteric/EPVME-Dataset
- https://github.com/rokibulroni/Phishing-Email-Dataset
## 贡献指南
欢迎贡献新的邮件样本、测验题目、UI 改进或基础设施优化。请在提交 Pull Request 前阅读 [`documentation/dev/CONTRIBUTING.md`](documentation/dev/CONTRIBUTING.md)。
本项目根据 **CC0**(公共领域)发布,可自由使用。
## 更新日志与许可
- 完整版本历史:[CHANGELOG.md](CHANGELOG.md)
- 当前版本:**1.2.5**
- 许可:**CC0** —— 无保留权利
Built with care for ESME engineering school