iliopdavid/django-amnesia-honeywords
GitHub: iliopdavid/django-amnesia-honeywords
一个 Django 身份验证后端,通过 Amnesia Honeywords 概率标记方案在无需独立 honeychecker 服务的情况下检测凭证泄露后的被盗密码冒用行为。
Stars: 0 | Forks: 0
# django-amnesia-honeywords
一个实现了 **Amnesia honeywords** 方案的 Django 身份验证后端,用于检测数据库泄露——无需单独的 honeychecker 服务。
当攻击者破解了凭证数据库并尝试使用被盗凭证进行在线登录时,该后端会检测提交的密码是*已标记*的凭证还是*未标记*的诱饵(honeyword)。
## 概述
对于每个用户,系统不再存储单个密码哈希,而是存储 `k` 个哈希候选者(1 个真实密码 + `k-1` 个 honeywords)。每个候选者都带有一个 `marked` 布尔标志。真实密码始终被标记;其他候选者以 `p_mark` 的概率被标记。
登录时:
1. 查找与提交的密码匹配的候选者
2. 如果**不匹配** → 拒绝(无效密码)
3. 如果**匹配但未标记** → 检测到泄露(攻击者正在使用被盗凭证)
4. 如果**匹配且已标记** → 成功;以 `p_remark` 的概率重新标记其他候选者
核心优势:**无需单独的 Honeychecker 服务**。系统从不存储哪个索引是真实密码——安全性来源于概率标记方案。
## 功能
- **即插即用的 Django 身份验证后端** — 与 Django 的认证系统无缝集成
- **Honeyword 生成** — 基于简单变异的生成器(可扩展用于自定义生成器)
- **事件记录** — 跟踪所有带有 IP 和 User-Agent 的身份验证尝试
- **Django 信号** — 接入 honeyword 检测事件
- **可配置的策略** — 在检测到泄露时,可选择记录、重置密码或锁定账户
- **无需 Honeychecker** — Amnesia 方案消除了对单独服务的需求
## 架构
```
┌─────────────────────────────────┐
│ Django App │
│ │
│ ┌───────────────────────────┐ │
│ │ HoneywordsBackend │ │
│ │ (authentication) │ │
│ └───────────┬───────────────┘ │
│ │ │
│ ┌───────────▼───────────────┐ │
│ │ amnesia_check() │ │
│ │ - find matching cred │ │
│ │ - check marked flag │ │
│ │ - probabilistic remark │ │
│ └───────────┬───────────────┘ │
│ │ │
│ ┌───────────▼───────────────┐ │
│ │ AmnesiaSet │ │
│ │ └─ k AmnesiaCredentials │ │
│ │ (hash + marked flag) │ │
│ └───────────────────────────┘ │
└─────────────────────────────────┘
```
## 安装
```
pip install django-amnesia-honeywords
```
## 本软件包的功能(以及不具备的功能)
**具备的功能**
- 提供了一个 Django **身份验证后端** (`django_honeywords.backend.HoneywordsBackend`),用于根据 Amnesia honeyword 集合检查密码。
- 为每个用户存储带有概率**标记**的 `k` 个密码候选者(哈希值);在登录时,它可以检测到使用**未标记**候选者的行为,并将其作为泄露信号。
- 记录结果(`real`/`honey`/`invalid`)并在检测到时发出 `honeyword_detected` 信号,以便进行告警/自动化处理。
**不具备的自动化功能**
- 安装本软件包本身**不会**更改您项目的身份验证方式。
您必须显式设置 `AUTHENTICATION_BACKENDS` 才能使用 `HoneywordsBackend`。
- 它无法从已哈希的密码中初始化现有用户。您需要用户的**明文密码**(注册 / 密码修改 / 可控迁移)。
**重要集成说明**
- 当您为用户初始化 honeywords 时,本软件包会将用户的 Django 密码设置为**不可用** (`set_unusable_password()`),以降低在启用 `ModelBackend` 时被绕过的风险。
- 如果您在 `HoneywordsBackend` 之外同时启用了 `django.contrib.auth.backends.ModelBackend`,那么**没有 AmnesiaSet 的用户**仍然可以使用默认的 Django 密码后端进行身份验证。
在生产环境中,建议仅使用 `HoneywordsBackend`,或者确保所有用户都已初始化。
或者从源码安装:
```
git clone https://github.com/iliopdavid/django-amnesia-honeywords.git
cd django-amnesia-honeywords
pip install -e .
```
## 快速开始
### 1. 添加到 Django 设置
```
INSTALLED_APPS = [
# ...
"django_honeywords.apps.DjangoHoneywordsConfig",
]
AUTHENTICATION_BACKENDS = [
"django_honeywords.backend.HoneywordsBackend",
]
# Honeywords 配置(全部可选 — 提供合理的默认值)
HONEYWORDS = {
"AMNESIA_K": 20, # Number of candidates per user
"AMNESIA_P_MARK": 0.1, # Probability of marking a honeyword
"AMNESIA_P_REMARK": 0.01, # Probability of re-marking on success
"ON_HONEYWORD": "log", # "log" | "reset" | "lock"
"LOG_REAL_SUCCESS": False, # Log successful *marked* credential logins (real or marked honeyword)
"LOCK_BASE_SECONDS": 60, # Base lockout duration
"LOCK_MAX_SECONDS": 3600, # Maximum lockout duration
}
```
### 2. 运行数据库迁移
```
python manage.py migrate django_honeywords
```
### 3. 初始化用户(重要)
本软件包无法从现有的哈希中推导出 honeywords:您必须在拥有用户**明文密码**时(注册、密码修改、迁移脚本)初始化用户。
- 管理命令(用于迁移 / 管理脚本):
```
python manage.py amnesia_init_user --password
```
- 通过代码初始化:
```
from django_honeywords.amnesia_service import amnesia_initialize_from_settings
amnesia_initialize_from_settings(user, "real_password")
```
### 4. (推荐)在生产环境中移除 ModelBackend
对于大多数部署环境,请仅配置 honeywords 后端:
```
AUTHENTICATION_BACKENDS = [
"django_honeywords.backend.HoneywordsBackend",
]
```
如果您保持启用 `ModelBackend`,请确保您了解未初始化用户面临的绕过风险。
## 配置选项
| 设置 | 默认值 | 描述 |
|---------|---------|-------------|
| `AMNESIA_K` | `20` | 每个用户的候选密码数量(1 个真实密码 + k-1 个 honeywords) |
| `AMNESIA_P_MARK` | `0.1` | 初始化期间标记每个 honeyword 的概率 |
| `AMNESIA_P_REMARK` | `0.01` | 登录成功后重新标记其他候选者的概率 |
| `ON_HONEYWORD` | `"log"` | 检测到 honeyword 时的操作:`"log"`、`"reset"` 或 `"lock"` |
| `LOG_REAL_SUCCESS` | `False` | 是否记录使用*已标记*凭证进行的成功身份验证 |
| `LOCK_BASE_SECONDS` | `60` | 账户锁定的基准持续时间 |
| `LOCK_MAX_SECONDS` | `3600` | 最大锁定持续时间(指数退避的上限) |
## 操作说明
- **系统检查**:运行 `python manage.py check` 以显示配置警告(例如,通配符主机、测试用哈希器、后端回退)。
- **事件语义**:记录“real”结果对应于**使用已标记凭证登录**(真实密码或已标记的 honeyword)。Amnesia 特意无法区分这些情况。
- **性能**:身份验证最多检查 `k` 个候选者(线性扫描)。请据此选择 `k` 和密码哈希器参数。
## 组件
### Django 模型
- **`AmnesiaSet`** — 将用户与其包含 `k` 个候选者及标记参数的集合关联起来
- **`AmnesiaCredential`** — 带有 `marked` 标志和索引的单个密码哈希
- **`HoneywordEvent`** — 身份验证尝试的审计日志(结果:real/honey/invalid)
- **`HoneywordUserState`** — 跟踪每个用户的锁定和密码重置状态
### 服务
#### `amnesia_service.py`
- `amnesia_initialize(user, password, k, p_mark, p_remark)` — 为用户生成并存储候选者
- `amnesia_initialize_from_settings(user, password)` — 同上,但使用 `HONEYWORDS` 设置中的值
- `amnesia_check(user, password)` — 返回 `"success"`、`"breach"` 或 `"invalid"`
#### `generator.py`
- `SimpleMutationGenerator` — 用于 honeywords 的基本字符变异生成器
- 通过随机变异单个字符来创建变体
- 可扩展:使用 `honeywords(real, k)` 方法实现您自己的生成器
#### `backend.py`
- `HoneywordsBackend` — Django 身份验证后端
- 通过 `amnesia_check()` 对用户进行身份验证
- 在检测到 honeyword 时执行策略(log/reset/lock)
- 在检测到泄露时触发 `honeyword_detected` 信号
#### `policy.py`
- `is_locked(user)` — 检查用户当前是否被锁定
- `apply_reset(user)` — 将用户标记为需要重置密码
- `apply_lock(user)` — 应用指数退避锁定
#### `events.py`
- `log_event(user, username, outcome, request)` — 记录带有元数据的身份验证尝试
### 信号
连接到 `honeyword_detected` 信号以实现自定义告警:
```
from django_honeywords.signals import honeyword_detected
def on_honeyword(sender, user, username, request, event, **kwargs):
send_security_alert(
message=f"Honeyword detected for user {username}",
ip=event.ip_address,
user_agent=event.user_agent,
)
honeyword_detected.connect(on_honeyword)
```
## 管理命令
### `amnesia_init_user`
为现有用户初始化 honeywords:
```
python manage.py amnesia_init_user alice --password "SecurePass123"
```
参数:
- `username` — 用户的用户名
- `--password` — 用户的真实密码(必填)
参数 `k`、`p_mark` 和 `p_remark` 从 `HONEYWORDS` 设置中读取。
## 开发
### 运行测试
```
# 安装 dev dependencies
pip install -e ".[dev]"
# 运行所有测试
pytest
# 运行特定测试组
pytest tests/test_amnesia_a1_models.py # Model creation
pytest tests/test_amnesia_a2_core.py # Core amnesia logic
pytest tests/test_amnesia_a3_backend.py # Authentication backend
pytest tests/test_amnesia_a4_command.py # Management command
```
## 部署说明
- 请勿原样部署 `example_project/settings.py` 配置。
- 使用 `example_project/settings_prod.py` 作为生产环境配置模板(设置 `DJANGO_SECRET_KEY` 和 `DJANGO_ALLOWED_HOSTS`)。
- 在生产环境中,除非您完全了解未使用 `AmnesiaSet` 初始化的用户所面临的绕过风险,否则请避免启用 `django.contrib.auth.backends.ModelBackend`。
- 请勿在生产环境中使用 `MD5PasswordHasher`(它仅在 `example_project/settings_test.py` 中使用,以加快测试速度)。
推荐的生产环境策略:
- 除非您已经具备了完整的密码重置用户体验流程,否则建议使用 `ON_HONEYWORD = "lock"`(或 `"log"`)。
- 如果您设置 `ON_HONEYWORD = "reset"`,您的应用程序必须提供密码重置/修改视图和提示信息,以便用户恢复账户。
## 文档
- 有关生产环境部署清单,请参阅 `docs/deployment.md`。
- 有关在注册/密码修改流程中初始化用户的指南,请参阅 `docs/integration.md`。
- 有关 GitHub + PyPI 发布步骤,请参阅 `docs/releasing.md`。
### 项目结构
```
django-amnesia-honeywords/
├── src/django_honeywords/
│ ├── apps.py # Django app config
│ ├── amnesia_service.py # Core amnesia service
│ ├── backend.py # Authentication backend
│ ├── conf.py # Settings with defaults
│ ├── events.py # Event logging
│ ├── generator.py # Honeyword generation
│ ├── models.py # Database models
│ ├── policy.py # Reset/lock policies
│ ├── signals.py # Django signals
│ └── management/commands/ # Management commands
├── tests/ # Test suite
└── example_project/ # Example Django project for testing
```
## 安全考量
1. **Honeyword 质量**:包含的 `SimpleMutationGenerator` 仅创建基本变体。为了获得更高的安全性,请实现一个能够生成难以区分的 honeywords 的自定义生成器。
2. **审计日志**:所有身份验证尝试都会记录到 `HoneywordEvent` 中。请定期查看这些日志,并为 honeyword 检测设置告警。
3. **参数调优**:`p_mark` 和 `p_remark` 参数控制误报率和检测灵敏度之间的权衡。有关选择值的指导,请参阅 Amnesia 论文。
4. **密码重置流程**:当 `ON_HONEYWORD = "reset"` 时,被标记为 `must_reset` 的用户应被重定向到密码修改页面。请将此与您的应用程序身份验证流程集成。
## 参考文献
- Juels, A., & Rivest, R. L. (2013). *Honeywords: Making password-cracking detectable*. ACM CCS 2013.
- Wang, K. C., & Reiter, M. K. (2021). *Using amnesia to detect credential database breaches*. In 30th USENIX Security Symposium (USENIX Security 21) (pp. 839-855).
## 许可证
MIT 许可证
标签:Atomic Red Team, Django, Python, Syscall, Web开发, 数据泄露检测, 无后门, 蜜语, 逆向工具