反向代理 ASUS 路由器 WebUI 需要设置 Referer 与 Host 匹配

今天想给 subconverter 添加一个 webhook,来触发路由器中 Merlin Clash 应用的自动重新加载,这就涉及要把路由器的 API 暴露到互联网上。

我一开始的想法是绑定域名,然后从外面直接访问,因为我的环境只有 IPv6 可用,而 GitHub Action 它只支持 IPv4,所以这条路不行。

那另一条路就是在外部公共环境中放置一个反向代理,我尝试了 Cloudflare Tunnel 和自己腾讯云服务器上的 nginx 反向代理,他们都遇到了一个问题:可以打开登录页,但是无法进行登录,点击登录按钮会刷新网页。

正常来说,不论登录不论账号密码是正确还是错误,那它都会有一个提示。那现在点击登录就像是刷新了网页一样。

我一开始还怀疑是 Cloudflare Tunnel ,它动态 IP 导致每次都连接到一个新的 session,也检查了浏览器中的 cookie,但似乎并不是相关的。

此时我想起来之前,调用 API 的时候,给路由器 API 的请求中必须有一个 Referer 参数,这次让 GPT 验证了下确有其事,调用点在 asuswrt-merlin.ng/release/src/router/httpd/httpd.c

int check_noauth_referrer(char *referer, int fromapp_flag)
{
    char *auth_referer = NULL;
 
    if (fromapp_flag != 0)
        return 0;
 
    if (!referer || !strlen(host_name))
        return NOREFERER;
 
    auth_referer = get_referrer(referer);
 
    if (!strcmp(host_name, auth_referer))
        return 0;
 
    return REFERERFAIL;
}

逻辑上即是验证 Host 和 Referer 必须匹配,那就简单了,在 Caddy 反向代理处设置固定值即可

rt-ax86u.home.kokomi.site {
	reverse_proxy RT-AX86U-CE58. {
		header_up Host "RT-AX86U-CE58"
		header_up Referer "http://RT-AX86U-CE58"
	}
}

这其实相当于公网暴露了,留下一个坑就是,任何人如果多输入错误几次,这个 WebUI 就会被锁,需要 service restart_httpd 重新启动