飘在云端

啊!那蓝真天,白真云!

· 随笔 · · 606次浏览

关闭宝塔 CSRF,避免移动端H5 CSRF 校验失败

安卓 Google WebView v95.0.4638.74 访问宝塔面板,临时修改查看一些配置,宝塔一直报 CSRF 校验失败,请重新登录,尝试清除浏览器缓存、cookies,情况依旧,PC 端 谷歌浏览器 v95.x 访问正常。

宝塔面板设置里提供了一个开发者模式开关,可以关闭 CSRF 校验,但会占用大量内存,详细面板调试信息输出还会增加生产环境安全风险。

反馈给客服无果,他们要我安装 堡塔APP,我:???,能手机 H5 解决的事还要下个APP?这还涉及到什么重量级操作非得设计开发一个 臃肿的APP客户端来实现?
抱着玩一玩的心态去下载了APP,发现需要付费,非专业版/企业版用户无法使用,付费没问题,坑的是这个仅仅是绑定到一个服务器,手头有多台服务器就得买多个宝塔专业版授权,不然你只能单独买 这个所谓的 堡垒APP 插件,价格每个月 39.8 CNY,我也只能笑笑,这专业版不要也罢,直接转让出了,本分事不做,歪风邪气学了一堆,强制绑定账户等下饭操作、乱改系统环境真是国内环境的特色。

那么就取一个折中方案,自强去改相关文件吧,只关闭 CSRF 校验,其他安全设置保持不变。

  • 测试环境:宝塔面板 Linux 免费版 v7.7.0

    需要修改如下文件:

/www/server/panel/__init__.py

定位到 1437 行 左右,把以下内容直接删除即可:

def check_csrf():
#CSRF校验
if app.config['DEBUG']: return True
request_token = request.cookies.get('request_token')
if session['request_token'] != request_token: return False
http_token = request.headers.get('x-http-token')
if not http_token: return False
if http_token != session['request_token_head']: return False
cookie_token = request.headers.get('x-cookie-token')
if cookie_token != session['request_token']: return False
return True
  • 请输入图片描述

往下翻 2 行,把以下内容删除:

#模块访问前置检查
if 'request_token' in session and 'login' in session:
    if not check_csrf(): return public.ReturnJson(False,'INIT_CSRF_ERR'),json_header

继续修改第二个相关文件: /www/server/panel/BTPanel/__init__.py
搜索 csrf 关键字,有13个结果,把它们相关行删除,具体删除如下:
定位到 1302 行附近,删除

if fun:
        if fun.find('.json') != -1:
            if 'request_token' in session and 'login' in session:
                if not check_csrf(): return public.ReturnJson(False, 'INIT_CSRF_ERR'), json_header
    args = None

定位到 1594 行附近,删除

def check_csrf():
# CSRF校验
if app.config['DEBUG']: return True
request_token = request.cookies.get('request_token')
if session['request_token'] != request_token: return False
http_token = request.headers.get('x-http-token')
if not http_token: return False
if http_token != session['request_token_head']: return False
cookie_token = request.headers.get('x-cookie-token')
if cookie_token != session['request_token']: return False
return True

往下翻 2 行,删除

# 模块访问前置检查
    if 'request_token' in session and 'login' in session:
        if not check_csrf(): return public.ReturnJson(False, 'INIT_CSRF_ERR'), json_header

定位到 1905 行附近,删除

get = json.loads(get)
if not check_csrf_websocket(ws,get): return

定位到 1976 行附近,删除

get = json.loads(get)
if not check_csrf_websocket(ws,get): return

定位到 2025 行附近,删除

get = json.loads(get)
if not check_csrf_websocket(ws,get): return

定位到 2053 行附近,删除

def check_csrf_websocket(ws,args):
'''
    @name 检查websocket是否被csrf攻击
    @author hwliang<2021-07-24>
    @param ws<WebSocket> websocket对像
    @return void
'''
if g.is_aes: return True
is_success = True
if not 'x-http-token' in args: 
    is_success = False

if is_success:
    if session['request_token_head'] != args['x-http-token']: 
        is_success = False

if not is_success:
    ws.send('token error')
    return False
return True

全部修改完之后,重启面板,立刻生效。