☰
Authelia 登录频率限制(Regulation)配置全指南:防暴力破解的账户封禁机制
2026/10/4 9:05:49 网站建设 项目流程

Authelia 登录频率限制(Regulation)配置全指南:防暴力破解的账户封禁机制

【免费下载链接】autheliaThe Single Sign-On Multi-Factor portal for web apps. OpenID Certified™ and Post-Quantum Cryptography Ready.项目地址: https://gitcode.com/GitHub_Trending/au/authelia

Authelia内置的Regulation(频率限制)系统能够在用户名/密码认证端点检测到过多失败尝试时,对账户进行临时封禁,从而有效抵御暴力破解攻击。本文以 docs/content/configuration/security/regulation.md 为核心骨架,结合internal/regulation、internal/configuration、internal/handlers等模块的源码实现,系统讲解regulation配置块的每一个参数、底层判定算法、与认证流程的集成方式,以及通过authelia storage bans命令手动管理封禁条目的实战方法。

读完本文你将能够:理解modes、max_retries、find_time、ban_time四个配置项的精确语义与默认值;掌握封禁判定(计数窗口、成功重置、封禁时长)的真实算法;学会排查与运维封禁条目,让账户在ban_time到期后自动恢复登录。

一、Regulation 是什么:为什么要限流

Regulation 是 Authelia 安全体系中的一层认证防爆破(brute-force prevention)机制。当攻击者针对用户名/密码登录端点(即第一因素认证,1FA)反复尝试弱口令或撞库时,Regulation 会统计find_time时间窗口内的失败次数,一旦达到max_retries阈值,即按配置的modes封禁用户账号或来源 IP,封禁持续ban_time时长。

与前端限流、验证码等方案不同,Regulation 是服务端、持久化的:

  • 每次认证尝试(成功或失败)都会写入存储层(MySQL/PostgreSQL/SQLite)的认证日志表;
  • 封禁记录(BannedUser/BannedIP)同样持久化到数据库,Authelia 重启后依然有效;
  • 封禁到期后记录不会自动删除,但查询时通过时间条件判定其已失效,账户即可恢复登录。

二、Configuration:完整配置示例

Regulation 配置位于configuration.yml的regulation顶层键下,一个完整可用的最小示例:

regulation: modes: - 'user' - 'ip' max_retries: 3 find_time: '2m' ban_time: '5m'

字段说明速览:

配置项类型默认值作用
modeslist(string)['user']封禁的生效对象:user(封账号)或ip(封来源 IP)
max_retriesinteger3达到该失败次数即触发封禁;设为0可完全禁用 Regulation
find_timestring,integer(duration)2 minutes统计失败尝试的时间窗口
ban_timestring,integer(duration)5 minutes触发封禁后的封禁时长

提示:在文档站点中该示例块带有 “config-alert-example” 提示,表示这是可复制到configuration.yml的推荐基线配置。其中同时启用了user与ip两种模式,属于比较严格的双重防护配置。

三、Options:四个配置参数深度解析

3.1 modes:封禁对象(user / ip)

modes决定封禁的主体是谁。文档明确指出推荐使用ip模式,并强调一个重要行为:无论当前配置了哪种封禁模式,只要数据库中已经存在有效的封禁记录,该用户或 IP 都会被拒绝访问——也就是说,modes只影响“自动产生新封禁”的判定路径,而不影响“已存在的封禁是否生效”的检查路径。

模式描述
user封禁的对象是用户账号,即max_retries次失败均发生在同一用户名下
ip封禁的对象是远程来源 IP,即max_retries次失败均来自同一 IP

从源码看,模式的解析发生在 regulator.go 的 NewRegulator:

users: config.MaxRetries > 0 && utils.IsStringInSlice(typeUser, config.Modes), ips: config.MaxRetries > 0 && utils.IsStringInSlice(typeIP, config.Modes),

注意两个细节:

  1. max_retries为 0 时无论modes配了什么,users和ips都为false,Regulation 整体失效,这与文档中 “Setting this option to 0 disables regulation entirely” 的描述完全一致;
  2. modes的合法取值仅有user与ip,其余值会在配置校验阶段直接报错。校验逻辑见 validator/regulation.go:
for _, mode := range config.Regulation.Modes { switch mode { case "ip", "user": break default: validator.Push(fmt.Errorf(errFmtRegulationInvalidMode, mode)) } }

对应测试 regulation_test.go 验证了:单独ip、单独user、["ip","user"]均合法,["invalid"]或混合非法值会被拒绝,空modes列表则回落到默认值['user']。

3.2 max_retries:失败阈值

max_retries是触发封禁所需的失败次数。默认值3,即 3 次失败即可封禁。设置为0会完全禁用 Regulation(如上文NewRegulator中所示,0 会让users/ips同时为 false)。

阈值语义在 regulator.go 的 expires 方法 中体现得非常清晰:

// 如果 find_time 窗口内的失败次数小于 max_retries,则不封禁 if len(failures) < r.config.MaxRetries { return nil }

也就是说,失败次数必须达到(>=)max_retries才会封禁。

3.3 find_time:失败统计时间窗口

find_time是“在多久的时间范围内统计失败尝试”。类型为string,integer,语法为 Go duration 格式,例如'2m'、'30s'、'1h'。默认值2 minutes。

文档中的经典示例:设置max_retries: 3、find_time: '2m',意味着用户必须在2 分钟内累计 3 次失败登录才会被禁。

底层实现中,find_time被转换为一个“起始时间点”,用于在存储层查询该时间点之后的认证日志。见 regulator.go 的 HandleAttempt:

since := r.clock.Now().Add(-r.config.FindTime) r.handleAttemptPossibleBannedIP(ctx, since) r.handleAttemptPossibleBannedUser(ctx, since, username)

而存储层的 SQL 查询按time > ?过滤(sql_provider_queries.go):

SELECT time, successful FROM authentication_logs WHERE time > ? AND username = ? AND auth_type = '1FA' AND banned = ? ORDER BY time DESC LIMIT ?;

注意查询条件auth_type = '1FA'——只有第一因素(密码/用户名)认证的失败才会计入 Regulation 统计,这也印证了 Regulation 防的是“用户名/密码端点”的暴力破解。

3.4 ban_time:封禁时长

ban_time是封禁持续的时间。默认值5 minutes,到期后账户自动恢复登录。它同样使用 duration 语法。

封禁到期时间的计算方式值得注意(regulator.go 的 expires 方法):

expires := failures[0].Time.Add(r.config.BanTime) return &expires

即:封禁的到期时间 = 窗口内第一次失败尝试的时间 +ban_time,而不是“触发封禁的时刻 +ban_time”。因此封禁会在“首次失败后的ban_time”时点自动解除。

3.5 配置校验规则:find_time 与 ban_time 的关系

校验器强制约束find_time必须小于或等于ban_time,否则配置加载失败。错误信息定义在 validator/const.go:

regulation: option 'find_time' must be less than or equal to option 'ban_time'

这一约束的合理性在于:统计窗口(find_time)不应大于封禁周期(ban_time),否则可能出现“封禁已过期但统计窗口仍然覆盖着更早的失败记录”的语义混乱。对应测试见 regulation_test.go。

同时,find_time与ban_time若被设置为非正值(如-1),会被重置为默认值(validator/regulation.go),相关行为在TestShouldSetDefaultRegulationTimeDurationsWhenNegative中有覆盖。

四、工作流程:从一次失败登录到账户被禁

将配置与源码串起来,一次完整的 Regulation 判定流程如下:

  1. 认证前检查:在FirstFactorPasswordPOST处理器执行密码校验之前,先调用Regulator.BanCheck(ctx, username)检查该用户或来源 IP 是否已在封禁中(handler_firstfactor_password.go)。若命中封禁(返回regulation.ErrUserIsBanned),直接返回401 Unauthorized,不再执行密码比对;
  2. 记录尝试:无论密码校验成功与否,都会通过doMarkAuthenticationAttempt→Regulator.HandleAttempt记录一条认证日志(response.go),写入AuthenticationAttempt结构对应的authentication_logs表(model/regulation.go);
  3. 触发统计:HandleAttempt中,仅当满足“本次尝试失败 + 当前无生效封禁 + Regulation 已启用(ips || users)+ 认证类型为 1FA”四个条件时,才执行封禁判定(regulator.go);
  4. 分别检查 IP 与用户:handleAttemptPossibleBannedIP与handleAttemptPossibleBannedUser各自查询find_time窗口内的失败记录(按 IP 或按用户名),调用expires计算封禁到期时间;
  5. 写入封禁:达到阈值后,向banned_ips/banned_users表写入一条Source: "regulation"、Reason: "Exceeding Maximum Retries"的封禁记录(regulator.go、model/regulation.go)。

expires判定算法的关键点(regulator.go):

  • 失败记录按时间倒序遍历,遇到第一条成功记录立即停止计数——也就是说,窗口内只要有一次成功登录,之前的失败不再累计;
  • 当失败计数达到max_retries后停止继续累加(已经该禁了);
  • 早于since(即超出find_time窗口)的记录被跳过;
  • 最终以失败列表中的最早一条失败时间加上ban_time作为封禁到期时间。

一个值得注意的行为:成功登录会“重置”窗口内的失败累计。这在expires的break loop分支中体现——一旦遇到Successful == true的记录就停止统计,因此攻击者若在窗口内有一次成功登录,其此前的失败将不计入封禁判定。

五、封禁的解除与手动管理:authelia storage bans

文档明确提示:无论当前配置的封禁模式如何,数据库中已存在的封禁记录始终生效;封禁条目可通过authelia storage bans命令族手动管理。该命令的定义见 commands/storage.go,文档参考见 docs/content/reference/cli/authelia/authelia_storage_bans.md。

命令层级结构:

authelia storage bans ├── user │ ├── list │ ├── add <username> │ └── revoke [username] └── ip ├── list ├── add <ip> └── revoke [ip]

5.1 查看封禁列表

authelia storage bans user list authelia storage bans ip list

对应 SQL 只返回当前仍有效的封禁:revoked = FALSE AND (expires IS NULL OR expires > NOW())(见 sql_provider_queries.go)。

5.2 手动添加封禁

authelia storage bans user add john --duration "1 day" --reason "suspicious activity" authelia storage bans ip add 203.0.113.5 --permanent --reason "abuse"

add子命令支持的参数(storage.go):

参数缩写默认值说明
--duration-d1 day封禁时长,与--permanent互斥
--permanent-pfalse永久封禁(expires为 NULL)
--reason-r空封禁原因,写入reason字段

若同时指定--permanent与--duration,命令会报错拒绝执行。

5.3 撤销封禁

authelia storage bans user revoke john authelia storage bans ip revoke 203.0.113.5 # 按封禁记录 ID 撤销 authelia storage bans user revoke --id 42

revoke可通过-i/--id指定封禁记录 ID,或直接传用户名/IP 值。撤销后该条封禁的revoked标记为真,不再影响登录。

5.4 手动封禁 vs 自动封禁的差异

手动添加的封禁与 Regulation 自动产生的封禁共用同一张banned_users/banned_ips表,但Source字段不同:自动封禁的Source恒为"regulation"、Reason为"Exceeding Maximum Retries",而手动封禁可以自定义Reason。由于文档明确“只要数据库中存在有效封禁记录即拒绝访问”,手动封禁同样会立即生效,可用于应急封禁某账号或某恶意 IP。

六、最佳实践与注意事项

  1. 推荐使用ip模式:user模式容易被攻击者利用来“锁死”他人账号(拒绝服务),而ip模式对正常用户影响更小。文档明确推荐ip;
  2. 同时启用两种模式需谨慎:user+ip双模式意味着同一来源 IP 和账号都可能被禁,防护更严但误伤面更大;
  3. max_retries: 0会彻底关闭 Regulation:如果希望仅保留“已存在封禁仍然生效”的能力而不再自动产生新封禁,可以这样配置,但注意这会失去自动防爆破能力;
  4. find_time与ban_time的关系:find_time必须<=ban_time,且封禁到期时间基于“窗口内最早一次失败 +ban_time”,调优时需结合真实登录频率;
  5. 封禁记录会一直保留在数据库中:到期只是“失效”而非“删除”,可通过authelia storage bans user list/authelia storage bans ip list定期审计,必要时手动撤销;
  6. Regulation 只统计 1FA 认证:从 SQL 查询条件auth_type = '1FA'可以看出,TOTP、WebAuthn 等第二因素的失败不计入封禁统计。

七、相关源码与文档导航

  • 配置文档:docs/content/configuration/security/regulation.md
  • 配置 Schema 与默认值:internal/configuration/schema/regulation.go
  • 配置校验:internal/configuration/validator/regulation.go、internal/configuration/validator/regulation_test.go
  • Regulation 核心实现:internal/regulation/regulator.go、internal/regulation/types.go、internal/regulation/const.go
  • 认证流程集成:internal/handlers/handler_firstfactor_password.go、internal/handlers/response.go
  • 存储层结构与 SQL:internal/model/regulation.go、internal/storage/sql_provider_queries.go
  • 封禁管理命令:internal/commands/storage.go、docs/content/reference/cli/authelia/authelia_storage_bans.md

【免费下载链接】autheliaThe Single Sign-On Multi-Factor portal for web apps. OpenID Certified™ and Post-Quantum Cryptography Ready.项目地址: https://gitcode.com/GitHub_Trending/au/authelia

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询