青龙面板公网端口被扫?应急改密与安全收口实战

发布时间:2026/9/25 6:46:39
青龙面板公网端口被扫?应急改密与安全收口实战 青龙面板只要上了公网就早晚会遇到这么一劫默认5700端口服务特征太明显扫描器一扫一个准。我见过太多案例密码设成admin、123456的被扫到之后不到半小时就被登录面板里被塞了一堆不认识的任务脚本。这篇文章不聊“怎么防”的大道理直接给你一套应急流程密码忘了进不去也好发现被扫想紧急改密也好按文里的步骤走完能把控制权拿回来把端口收住把后路断干净。这套流程我拆成了六块先判断到底是忘密码还是被入侵了再给两套重置密码的方案——一套是删库重新初始化一套是保留数据直接写入新密码然后讲登录态清理和端口收口最后是长期加固和问题排查。全程用我实际踩过的坑说话。1. 应急前先搞清楚是忘密码还是被入侵了1.1 两种场景的共性处理思路先说一个容易被忽略的事实不管你是“忘了密码进不去”还是“发现面板被扫被登录”处理逻辑的前半段是完全一样的——先备份再重置密码然后清登录态最后收端口。区别只在于如果是被入侵后面还要多一步排查后门和清理异常脚本。所以别一上来就急着改端口或者删数据库。先花两分钟确认一下状态猜错场景会导致很尴尬的结果比如你明明是被入侵了结果只改了密码攻击者留下的反弹shell还在又比如你只是忘了密码结果慌乱中把docker容器删了重建配置全丢。这两种情况我都见人遇到过。我自己习惯的做法是先开一个浏览器无痕窗口尝试登录一次。如果能进说明密码没变问题可能出在“面板被加了什么”而不是“密码被改了”如果进不去且提示密码错误那可能是密码被改或者自己忘记。这一步虽然简单但能帮你快速把后续方向定下来。1.2 被入侵的现场痕迹怎么查如果怀疑被扫了别光顾着改密码先做一轮快速排查。顺序不要乱从面板侧先看再到服务器侧。面板侧重点看四个地方定时任务有没有不认识的脚本名称比如一串乱码命名的任务或者定时时间非常频繁、明显不是你设置的任务。订阅管理有没有多出来未知的订阅源攻击者会把恶意脚本通过订阅方式灌进来这样面板一更新恶意代码就自动拉取。环境变量有没有新增的变量有些攻击者是来偷cookie的他可能还没动任务只是把env表里的数据读了一遍。脚本文件目录/ql/scripts下有没有新生成的、不是你自己写的js或py文件重点看最近24小时内mtime有变化的文件。服务器侧也要扫一眼执行top看CPU占用有没有异常的进程飙高。执行ss -antp看有没有可疑的外部连接。执行last -n 20看SSH登录记录里有没有陌生IP。检查~/.ssh/authorized_keys有没有被追加公钥这是最常见的后门植入手段。执行crontab -l看系统层面有没有恶意定时任务。这一套下来基本能判断是被入侵还是单纯忘记密码了。如果查出来确实被入侵那后面重置完密码之后我强烈建议你把面板容器直接重建甚至系统层面都值得重新检查一遍。别抱有侥幸心理。1.3 动手改密码前必须做的备份很多人应急的时候图快上来就删表、删容器结果发现删错了连后悔药都没有。备份这一步不能省而且要做对。青龙面板的数据主要在容器的/ql/config目录下里面最重要的是config.sqlite3这玩意儿存着环境变量、任务、账号信息别丢了。另外/ql/scripts是你自己的脚本有过改动的话也一起备了。先找到数据卷在宿主机的位置docker inspect qinglong --format {{range .Mounts}}{{.Source}} - {{.Destination}}{{println}}{{end}}执行之后你会看到类似/opt/qinglong/config - /ql/config的输出说明宿主机上数据在/opt/qinglong/config。然后直接打包备份tar czf qinglong_backup_$(date %Y%m%d_%H%M%S).tar.gz /opt/qinglong/config /opt/qinglong/scripts备份文件放到面板目录之外的地方哪怕放在当前用户的home目录都行。我自己的习惯是备份完再顺手ls -lh看一眼文件大小确认不是0字节。空备份比没有备份更害人。2. 重置密码方案一数据库删表重初始化2.1 青龙面板的密码到底存在哪先弄明白一件事青龙面板的密码不是明文存在文件里的而是存在SQLite数据库里具体是/ql/config/config.sqlite3这个文件中的auth表。auth表里有username、password、token这些字段其中password字段存的是加密后的密文。你直接UPDATE一个明文密码进去是没用的登录的时候程序会先加密你输入的密码再和数据库里的密文比对明文根本对不上。所以重置密码的关键就两条路要么让程序认为“系统还没初始化过”重新让你设置一次密码也就是删表要么生成一个合法的加密密文直接替换掉数据库里的旧密文这个放下一章讲。这一章先说删表。为什么应急场景下我最推荐删表因为它有一个隐藏好处auth表被删掉之后里面存的所有登录token也会一起消失这意味着攻击者手里已有的会话凭证全部作废效果比单纯改密码干净得多。2.2 具体操作停容器、删表、重启步骤不复杂但每一步都要理解为什么要这么做不然容易在中间卡住。第一步停止容器。这一步的意义是停止面板程序对数据库的写入避免删表过程中产生数据竞争或者文件锁问题。docker stop qinglong第二步确定数据库文件路径。已知挂在宿主机的路径是/opt/qinglong/config数据库文件就是/opt/qinglong/config/config.sqlite3。如果你不确定用上一章讲的docker inspect查一下Mounts就行。第三步用sqlite3命令删表。宿主机如果装了sqlite3直接执行sqlite3 /opt/qinglong/config/config.sqlite3 DROP TABLE auth;如果提示sqlite3: command not found别慌装一下就行。CentOS系用yum install -y sqliteDebian/Ubuntu系用apt install -y sqlite3。第四步重启容器docker start qinglong等个十几秒让面板完成启动然后浏览器无痕窗口访问面板地址。这时候程序检测不到auth表会重新进入初始化引导流程你重新设置一个管理员账号密码就完事了。整个流程行云流水数据里的任务、环境变量、订阅全部原封不动丢的只是登录账号体系。2.3 删表方案的风险提示这个方案有两个要注意的点。第一个如果你面板里有多个用户账号比如分给朋友用删表之后所有用户都没了需要重新创建。第二个删表其实等效于“重置所有账号”是一个比较暴力的操作动手前一定要确认备份已经做好了。还有一个小坑有些版本的青龙在删除auth表后重启不会走初始化流程而是报错或者起不来。这种情况通常是因为配置文件里残留了初始化状态标识。解决的办法是在删除auth表的同时把config目录下和初始化状态相关的记录也清掉。不过不同版本处理方式不同遇到这个情况不用深究直接看第六章的排查表。3. 重置密码方案二不删数据也能改3.1 为什么有时候不想删表删表方案虽然快但有些场景下你想保留auth表里的账号体系或者你只是单纯忘了密码、不想搞得那么“大动干戈”。这时候就需要第二种思路生成合法的密码密文直接UPDATE进数据库。核心问题是青龙面板的密码加密到底怎么做的不同版本源码有差异我们不能盲猜直接进去看源码最靠谱。进入容器docker exec -it qinglong bash然后找认证相关模块ls /ql/utils/ cat /ql/utils/auth.js # 如果存在如果auth.js不存在就全目录搜一下加密关键字grep -rn AES\|CryptoJS\|createHash /ql/utils /ql/src --include*.js | head -20看到结果里的加密方式通常青龙用的方案是CryptoJS.AES.encrypt(密码, 密钥)密钥来源可能是配置文件里的某个字段也可能是环境变量。你需要在源码里找到密钥从哪取。这一步是这套方案里唯一有技术含量的地方。3.2 生成密文并写回数据库假设你在源码里确认了是AES加密密钥存在环境变量Secret里。那生成新密码密文的过程就是在容器内执行一段Node脚本node -e const CryptoJS require(crypto-js); const key process.env.Secret || qinglong; const newPassword 你的新密码记得够长够随机; const encrypted CryptoJS.AES.encrypt(newPassword, key).toString(); console.log(encrypted); 这段脚本的输出就是你新密码对应的密文复制保存好。注意如果你的版本加密方式不同脚本要跟着源码调整比如改成MD5加盐或者别的写法。不熟悉的话就把源码贴进百度让AI帮你写脚本或者干脆用第二章的删表方案不丢人都是合理选择。拿到密文之后退出容器回到宿主机执行UPDATEsqlite3 /opt/qinglong/config/config.sqlite3 update auth set password上面生成的密文 where usernameadmin;如果面板是Docker部署但宿主机没有sqlite3可以先把数据库文件复制出来改完再复制回去但操作前必须停容器不信你试一次就知道什么叫database is locked。docker stop qinglong cp /opt/qinglong/config/config.sqlite3 /tmp/ sqlite3 /tmp/config.sqlite3 update auth set password上面生成的密文 where usernameadmin; cp /tmp/config.sqlite3 /opt/qinglong/config/config.sqlite3 docker start qinglong3.3 两种方案怎么选我直接给你一个选择标准省得纠结对比维度方案一删表重置方案二密文写入操作速度快4步搞定较慢要查源码再执行脚本依赖的知识基本没有会看一下源码里的加密逻辑保留用户账号清空所有账号完全保留清token效果全清最彻底需要手动清token风险点部分版本可能初始化失败密钥找错会导致密码无效适用场景被入侵应急、只想快速夺回控制权忘记密码、需要保留账号体系如果只是忘了密码两个都行看你兴趣如果是被扫端口后应急优先方案一因为省事且清token彻底。4. 改完密码不算完登录态清理与端口收口4.1 让所有旧token失效改完密码不是终点甚至可以说只做了一半。青龙面板的登录机制里登录成功后服务端会发一个token后续请求都靠这个token维持会话。问题在于攻击者如果已经登录过他手里很可能已经握着一个有效token。这意味着什么你改了密码他过期的只是密码登录这条路但他手里拿着token请求照样可能通过认证。所以在重置密码之后必须把auth表里的token字段清掉或者重置。如果你用的是删表方案不用管这一步token已经跟着auth表一起消失了。如果你用的是密文写入方案手动清一下sqlite3 /opt/qinglong/config/config.sqlite3 update auth set token, refresh_token;顺便把auth表里那些你不认识的用户名也一起看看有一并删掉sqlite3 /opt/qinglong/config/config.sqlite3 select id, username from auth;确定哪些账号不是你创建的删sqlite3 /opt/qinglong/config/config.sqlite3 delete from auth where username不认识的名字;这一套做完攻击者手里的凭证全部作废他就算再拿着旧token来敲门也会被拒之门外。4.2 修改默认端口并重建容器把登录态清干净之后下一个动作就是收端口。5700这个端口已经被扫描器标记了不换还等着它继续扫吗青龙面板的端口是启动容器时通过-p参数映射进来的。查看你当前容器的端口映射docker inspect qinglong --format {{json .NetworkSettings.Ports}}输出里能看到5700/tcp映射到宿主机哪个端口。修改端口需要重建容器。先停掉容器再重新run一次数据卷挂载保持不变就行docker stop qinglong docker rm qinglong docker run -d \ --name qinglong \ -p 127.0.0.1:5700:5700 \ -v /opt/qinglong/config:/ql/config \ -v /opt/qinglong/log:/ql/log \ -v /opt/qinglong/scripts:/ql/scripts \ --restart unless-stopped \ whyour/qinglong:latest这里有个容易被忽视的点我上面的命令把新的青龙端口绑到了127.0.0.1:5700也就是说外网直接访问不了只能本机访问。这是最安全的方式配合后面的反向代理把面板暴露到你想要的入口。如果你的诉求是“换个端口继续公网访问”那也不要直接-p 新端口:5700就完事还得配合防火墙白名单只允许你自己的IP访问否则换个端口只是多撑几天的事。4.3 防火墙收口别让5700继续裸奔改端口之后还要把旧端口的访问彻底断掉。就算Docker的端口映射已经改了你还要检查宿主机防火墙和云厂商的安全组。Ubuntu上使用ufw的话操作很直接# 禁止所有IP访问旧端口5700 ufw deny 5700/tcp # 只允许你自己的IP访问新映射出的端口 ufw allow from 你的IP to any port 新端口 proto tcp如果你不习惯ufw用iptables也行iptables -A INPUT -p tcp --dport 5700 -j DROP iptables -A INPUT -p tcp --dport 新端口 -s 你的IP -j ACCEPT iptables -A INPUT -p tcp --dport 新端口 -j DROP这只是宿主机层面的。云服务器还要去控制台检查安全组规则把原来放行5700的规则删掉。这一步漏掉的概率很高很多人折腾半天发现外网还能访问旧端口一查就是云安全组没改。记住Docker端口映射、iptables、云安全组三个地方都要检查。5. 被扫端口后的长期安全加固清单5.1 登录入口用Nginx反向代理挡一层被扫过一次之后如果还继续把面板裸在公网那就不是运气问题是心大了。我后面给所有面板类服务上Nginx反向代理核心思路是三层青龙只监听本地、Nginx负责对外、Basic Auth先顶在前面。Docker部署时青龙监听127.0.0.1:5700然后宿主机装Nginx配置大概长这样server { listen 443 ssl; server_name panel.example.com; ssl_certificate /etc/nginx/ssl/panel.crt; ssl_certificate_key /etc/nginx/ssl/panel.key; auth_basic Access; auth_basic_user_file /etc/nginx/.htpasswd; location / { proxy_pass http://127.0.0.1:5700; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }auth_basic就是你日常理解的“第一次访问要输入账号密码”。这样就算扫描器扫到你这个HTTPS端口第一道关是Basic Auth第二道关才是青龙的面板登录。两层都过了才算拿到控制权。比裸奔强太多了。5.2 日常巡检要做的事被扫之后别想着“改完密码就万事大吉”攻击者可能已经植入了一些你还没发现的东西。我给自己定的巡检习惯每两周花五分钟就够了登录面板看一眼任务列表有没有不认识的任务。看一眼订阅管理有没有未知订阅源。看一眼环境变量列表有没有不该出现的新变量。服务器上执行ss -antp记一下有哪些外联IP新出现的陌生外联要警惕。检查/root/.ssh/authorized_keys有没有新公钥。这一套做完大概五分钟。五分钟的成本好过哪天登录面板发现所有cookie都被偷光了才后知后觉。5.3 备份和恢复不能只是嘴上说说很多人都有备份计划但从来没验证过备份能不能恢复。青龙面板的备份其实极其简单就是你那个config目录里的config.sqlite3压缩打包放别处就行。我一般用一个crontab每天凌晨打包一次保留最近七天0 3 * * * tar czf /backup/qinglong_$(date \%Y\%m\%d).tar.gz -C /opt/qinglong config但更重要的是你要真的演练过从这份备份恢复到面板可用的过程。方法很简单在另一台机器上用相同的数据卷路径启动一个临时容器让备份文件挂进去启动成功就算验证通过。一次都没验证过的备份只能叫安慰剂。6. 常见问题与排查实录6.1 问题速查表把实际操作中容易踩的坑整理成表按费解程度排序问题现象可能原因解决办法删除auth表后重启还是跳到旧登录页浏览器缓存了页面或者面板启动未完成换无痕窗口访问docker logs qinglong看启动日志确认跑起来了删除auth表后面板报错起不来部分版本初始化状态标识残留在配置文件里备份后清空config目录里带state/session字样文件再重启宿主机没有sqlite3命令系统没装CentOS用yum、Ubuntu用apt装sqlite3UPDATE密码后登录还是提示密码错误设置的加密密钥和源码实际使用的不一致返回容器重新确认密钥来源实在搞不定就删表重置重建Docker容器后数据全没了新容器挂载的数据卷路径不对重建前先docker inspect确认旧容器的Mounts路径一模一样地挂端口改到新的外网还能访问旧端口云安全组或宿主机iptables仍然放行旧端口检查云控制台安全组和iptables非常常见面板里多出来不认识的任务删了又出现订阅源还留着恶意脚本会自动拉回先删订阅源再删任务最后清理scripts目录里的垃圾文件容器内执行node命令报module not found加密模块路径写错了到/ql或/usr/local/bin下确认模块位置用绝对路径引入6.2 我在应急中踩过的一次坑我自己操作时吃亏最狠的一次就是改完端口忘了云安全组。那天排查到半夜宿主机iptables规则全改对了Docker映射也确认新端口生效了但从外面一访问还是通。我一度以为是云服务商有CDN缓存拦截结果打开控制台一看安全组里明确写着放行5700/tcp。直接删掉那条规则整个世界清净了。从那以后我养成了习惯凡是涉及端口变更Docker映射、iptables、安全组三个地方按顺序过一遍再收工。还有一个小细节删表或者改库之前如果面板正在运行sqlite3会提示库被锁定。这不是bug是SQLite的正常行为。老老实实先停容器再操作别问我为什么知道。最后说一点我自己的习惯。现在所有面板类服务我都不直接暴露公网了能用内网访问就内网访问非得远程用就连组网工具端口全部收进内网。这样做的代价是最低的但每天不用再担心扫描器找上门。青龙面板是个好工具被扫了也别慌按这套流程走完控制权大概率能拿回来。但记住重置密码只是第一步把访问入口收进该进的地方才是真正的安全。