Caddy ipfilter 插件的默认设定是不安全的!

一直以来,我都使用 ipfilter 插件为本站的关键页面设置 IP 白名单.不过,前段时间在使用 Cloudflare 的时候,却偶然发现了 ipfilter 存在的一个问题.

我遇到的问题是这样的:当 Caddy 服务器运行在代理(比如 CDN) 之后时,可以通过 realip 插件来指定 Caddy 以及插件们看到的访客 IP 是代理 IP 还是访客的真实 IP. 唯独 ipfilter 会忽略 realip 提供的访客 IP, 并且总是拿访客的真实 IP 去匹配白名单/黑名单里的 IP. 这样做的问题在于:在启用 Cloudflare CDN 后,我希望阻止除了 Cloudflare 缓存服务器以外的任何人直接访问我的站点.一个自然的思路是,把 Cloudflare 的 IP 段放进白名单里.然而,这么做之后就没人能打开我的网站了,因为 ipfilter 会拿访客真实 IP 去匹配白名单里的 Cloudflare IP, 当然匹配不上啦.(理想情况下,它应该拿代理 IP 去匹配,如果匹配成功则说明访客是通过 Cloudflare 的代理间接访问的,可以放行;如果匹配失败则说明访客绕过了代理直接访问本站,应该拒绝访问)

当然,那时候我采用了另外的方案解决了阻止访客直接访问这个问题.不过 ipfilter 的怪异行为一直让我很好奇🤔

后来我终于发现, ipfilter 还有个 strict 选项(文档).这个选项默认关闭.当关闭时, ipfilter 总是会从 X-Forwarded-For 头拿到 IP; 而打开时, ipfilter 的行为就和其它的插件相同了,会接受来自 realip 提供的 IP.这就是上述问题的答案.

进一步,我发现这个选项的默认设定是不安全的.事实上,当 strict 设定为关闭时, ipfilter 会信任任意的源提供的 X-Forwarded-For 头.根据规范, X-Forwarded-For 的值是 [CLIENT IP], [PROXY1 IP], [PROXY2 IP], ... .因此,恶意访客若知道白名单 IP, 完全可以把这个 IP 放在 X-Forwarded-For 的第一个位置,把自己伪装成转发来自白名单 IP 请求的一个代理,以此绕过 ipfilter 的限制.换句话说, ipfilter 不应该信任所有的 X-Forwarded-For 头.

而 realip 正好考虑到了这一点,可以信任一部分源,并忽略其它源提供的 X-Forwarded-For 头.在 realip 中可以通过 from 选项设定信任的 IP (比如 Cloudflare 的 IP). 此外, realip 也有一个 strict, 当开启时,会把伪装自己是代理的信任名单以外的 IP 都给封掉.(文档)

综上所述,如果你的服务器在代理背后,又需要设定 IP 白名单,推荐采用下列配置:

realip {
        from cloudflare # realip 预置了 Cloudflare 等厂商的 IP 列表
        strict
}
ipfilter /[CRITICAL_PAGE] {
        rule allow
        ip [WHITELISTED IP]
        strict
}

(事实上,那两个 strict 开一个就足够抵御伪装成代理的恶意访客了)

以上.

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注