1. 是什么

htpasswd 是 Apache HTTP Server 附带的一个命令行工具,用于创建和管理 HTTP 基础认证(HTTP Basic Authentication) 的用户口令文件 .htpasswd。

虽然它出身于 Apache,但 Nginx 也使用同一格式的 .htpasswd 文件,因此它在 Web 鉴权里几乎是通用工具。适合给小型服务、内网面板、反代入口加一层简单的账号密码保护。

关联:Web 登录鉴权 (Session, Cookie, Bearer, JWT) 里 Basic Auth 就是 htpasswd 承载的"远古但简单"方案。

鉴权原理(超简版)

  1. 浏览器请求受保护资源,服务器返回 401 Unauthorized 并带响应头 WWW-Authenticate: Basic realm="..."。
  2. 浏览器弹出用户名/密码输入框。
  3. 之后的每次请求都带请求头 Authorization: Basic base64(user:password)。
  4. 服务器用 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-user

7. 没有 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 password

8. 常见坑(Pitfalls)

  1. -c 覆盖整个文件:对已有文件追加用户时误加 -c,会清空之前所有用户。首次之后的操作一律去掉 -c。
  2. bcrypt 在老版本 Apache 不认:Apache 2.4 之前的 mod_auth_basic_file 不支持 $2y$,跨版本部署时确认客户端/服务端兼容性。
  3. Nginx 对哈希格式校验严格:若文件里混入不支持的哈希格式(如 {SHA} 需确认编译模块),整行会被忽略导致登录失败。用 -B 生成最省心。
  4. 密码里含冒号:用户名和密码都不可含 :,否则按冒号解析会错位。
  5. 明文 HTTP:不加 HTTPS 时 base64 即明文,别在生产环境裸奔。
  6. 浏览器记住密码后的弹窗刷新:想退出 Basic Auth 只能关掉浏览器或清站点凭据,没有 logout 概念。

9. 适用边界

  • ✅ 内部工具、管理后台、反代网关入口、临时保护静态资源。
  • ❌ 面向真实用户的注册/登录体系、需要登出/会话过期/多角色的场景——请用完整的 Session/JWT 方案(见 Web 登录鉴权 (Session, Cookie, Bearer, JWT))。

一句话总结: htpasswd 是给"不暴露给陌生人"的页面加把锁的最小工具,命令简单、文件一行一个用户,但安全前提是 HTTPS + bcrypt。


本文归档于个人知识库 · 领域:CS & AI · 模块:04 Project_CS_AI/Web