Htpasswd 基础鉴权
1. 是什么
htpasswd 是 Apache HTTP Server 附带的一个命令行工具,用于创建和管理 HTTP 基础认证(HTTP Basic Authentication) 的用户口令文件 .htpasswd。
虽然它出身于 Apache,但 Nginx 也使用同一格式的 .htpasswd 文件,因此它在 Web 鉴权里几乎是通用工具。适合给小型服务、内网面板、反代入口加一层简单的账号密码保护。
关联:Web 登录鉴权 (Session, Cookie, Bearer, JWT) 里 Basic Auth 就是 htpasswd 承载的"远古但简单"方案。
鉴权原理(超简版)
- 浏览器请求受保护资源,服务器返回
401 Unauthorized并带响应头WWW-Authenticate: Basic realm="..."。 - 浏览器弹出用户名/密码输入框。
- 之后的每次请求都带请求头
Authorization: Basic base64(user:password)。 - 服务器用 htpasswd 文件里的哈希验证。
这套弹窗只发生在文档导航(地址栏打开受保护 URL)。SPA 里的 fetch / XHR 拿到 401 不会弹框,也不会自动带 Basic。详见 fetch 不会弹出 HTTP Basic 登录框 (fetch does not prompt for HTTP Basic)。
⚠️ base64 不是加密,只是编码。user:password 可被任意解出。必须配合 HTTPS,否则等于明文送密码。
2. 核心命令
-c 表示创建新文件(注意:会覆盖已有文件),其他增删改操作不加 -c。
# 新建文件并添加第一个用户(交互式输入密码)
htpasswd -c /etc/nginx/.htpasswd alice
# 追加用户 / 修改已有用户密码
htpasswd /etc/nginx/.htpasswd bob
# 用命令行参数直接给密码(-b = batch,避免交互)
htpasswd -b /etc/nginx/.htpasswd bob 'P@ssw0rd'
# 删除用户
htpasswd -D /etc/nginx/.htpasswd bob
# 验证用户/密码是否匹配(成功返回 0)
htpasswd -vb /etc/nginx/.htpasswd alice 'correct-password'
# 不写文件,直接打印到 stdout(可用于管道或临时生成)
htpasswd -nb alice 'P@ssw0rd'常用参数速查
| 参数 | 含义 |
|---|---|
-c | 创建文件(覆盖已有),只在首次使用 |
-b | 密码直接写在命令行(batch 模式),勿在 shell 历史中留真实密码 |
-n | 输出到 stdout 而不写文件 |
-B | 使用 bcrypt 哈希(推荐) |
-m | 使用 Apache MD5 变体($apr1$,旧默认,兼容 Apache 旧版本) |
-s | 使用 SHA-1(不安全,不要用) |
-D | 删除用户 |
-v | 验证用户名密码 |
3. 哈希算法选哪个
| 算法 | 参数 | 哈希前缀 | 安全性 | 备注 |
|---|---|---|---|---|
| bcrypt | -B | $2y$ | ✅ 推荐 | 抗 GPU/彩虹表,现代标准 |
| Apache MD5 | -m | $apr1$ | ⚠️ 一般 | 旧默认,为兼容老 Apache 保留 |
| SHA-1 | -s | {SHA} | ❌ 不要用 | 快速可破 |
| crypt | -d | 无 | ❌ 不要用 | 依赖系统 glibc,平台相关 |
| 明文 | -p | 无 | ❌ 禁止 | 明文存密码 |
推荐命令:htpasswd -cB file user(bcrypt 默认 cost 为 5,用 -C 10 可调高,越大越慢越抗暴力破解)。
破解难度与加固
| 攻击面 | 风险 | 应对 |
|---|---|---|
| 传输层 | base64 只是编码,裸 HTTP 抓包即得明文 | 必须 HTTPS,否则密码直接暴露 |
| 离线破解(拿到 .htpasswd) | bcrypt 抗(cost≥10 单 GPU 每秒仅几十~几百次尝试);$apr1$ MD5 弱(亿级/秒);SHA-1/明文秒破 | 用 -B,cost≥10,密码用随机长串 |
| 在线爆破 | Basic Auth 无内置锁定/频率限制 | Nginx limit_req 或 fail2ban |
| 机制结构 | 无登出/无过期、浏览器缓存凭据 | 仅限低敏感入口,敏感面换完整方案 |
量化参考:拿到哈希文件后,$apr1$ MD5 配中等强度密码(如 8 位字母数字)通常几小时到几天可破;bcrypt(cost 10) 下 8 位强随机密码基本不可行。密码强度 + bcrypt 才是核心防线。
4. 文件格式
每行一个用户,用户名:哈希,用冒号分隔:
alice:$2y$05$ln9BqJ8VZf2E6dT0yV1sYeVx7JQkF1QmP0ZvZzQz8Yz7y6x5w4u
bob:$apr1$P7Q2GmY1$Hh2QjKf3Xx0nWmSgQp4Lz1- 用户名不能包含冒号(分隔符),否则解析错乱。
- 权限建议
600(仅所有者读写):chmod 600 /etc/nginx/.htpasswd。 - 修改后 Nginx 无需 reload,每请求实时读取。
5. 在 Nginx 中使用
location /admin/ {
auth_basic "Restricted Area";
auth_basic_user_file /etc/nginx/.htpasswd;
# 对特定子路径放行,可覆盖父级
location /admin/public/ {
auth_basic off;
}
}要点:
auth_basic的字符串会作为弹窗 realm 提示语。auth_basic_user_file指向 htpasswd 文件路径。- 嵌套 location 里
auth_basic off;可对子路径放行。 - 所有走 HTTPS,否则账号密码明文在网络上传输。
6. 在 Apache 中使用(.htaccess)
AuthType Basic
AuthName "Restricted Area"
AuthUserFile /etc/apache2/.htpasswd
Require valid-user7. 没有 htpasswd 工具时怎么生成
方式一:openssl(Apache MD5 变体,兼容 Nginx/Apache)
openssl passwd -apr1方式二:Python + bcrypt(生成 bcrypt 格式)
python3 -c "
import bcrypt
pwd = b'your-password'
h = bcrypt.hashpw(pwd, bcrypt.gensalt(rounds=10))
print('user:' + h.decode())
"方式三:直接用 Python htpasswd 库(一次性生成)
pip install htpasswd
python3 -m htpasswd -cb file user password8. 常见坑(Pitfalls)
-c覆盖整个文件:对已有文件追加用户时误加-c,会清空之前所有用户。首次之后的操作一律去掉-c。- bcrypt 在老版本 Apache 不认:Apache 2.4 之前的
mod_auth_basic_file不支持$2y$,跨版本部署时确认客户端/服务端兼容性。 - Nginx 对哈希格式校验严格:若文件里混入不支持的哈希格式(如
{SHA}需确认编译模块),整行会被忽略导致登录失败。用-B生成最省心。 - 密码里含冒号:用户名和密码都不可含
:,否则按冒号解析会错位。 - 明文 HTTP:不加 HTTPS 时 base64 即明文,别在生产环境裸奔。
- 浏览器记住密码后的弹窗刷新:想退出 Basic Auth 只能关掉浏览器或清站点凭据,没有 logout 概念。
9. 适用边界
- ✅ 内部工具、管理后台、反代网关入口、临时保护静态资源。
- ❌ 面向真实用户的注册/登录体系、需要登出/会话过期/多角色的场景——请用完整的 Session/JWT 方案(见 Web 登录鉴权 (Session, Cookie, Bearer, JWT))。
一句话总结: htpasswd 是给"不暴露给陌生人"的页面加把锁的最小工具,命令简单、文件一行一个用户,但安全前提是 HTTPS + bcrypt。
本文归档于个人知识库 · 领域:CS & AI · 模块:04 Project_CS_AI/Web