服务器被暴力破解每天几千条失败登录记录,改了SSH端口装了fail2ban还是挡不住,批量锁定FTP账号比你想的简单,一个脚本十行命令就能把30个站的FTP全锁了只留白名单IP
去年底接手一台客户服务器,上面跑了30多个WordPress站点,每个站点配了独立FTP账号。某天翻vsftpd日志,发现一个越南IP在48小时内对这30个FTP账号轮流试密码,累计失败登录超过8000次。虽然fail2ban在封IP,但攻击者换IP的速度比fail2ban封禁的速度还快——封一个换一个,像打地鼠。
最后解决问题的方法很简单:写了一个Shell脚本,批量把30个FTP账号全部锁定(禁止登录),只留了两个管理员用的账号,给这两个账号配了白名单IP。暴力破解立刻停了,因为攻击者连"账号是否存在"都探测不出来了。之后需要给客户开放FTP时,再跑一个解锁脚本,用完立刻重新锁定。整个过程不超过十分钟。
FTP批量锁定解锁这件事,本质上有三个层次:
- 1最浅层是"知道怎么锁定单个FTP账号"——在宝塔面板里点停用,或者在Linux里跑usermod -L。
- 2中层是"能批量操作"——一个脚本搞定所有FTP账号的锁定和解锁,而不是一个个点。
- 3深层是"能制定策略"——什么时候锁、锁哪些、留谁不锁、解锁后多久自动重新锁、不同服务器不同策略。
一、为什么FTP账号需要批量锁定,而不是"设个强密码就完了"
很多站长觉得FTP账号安全=设个复杂密码。实际上FTP协议本身有先天性的安全问题:FTP是明文传输协议,用户名和密码在网络上是裸奔的。虽然现在大多数环境用了FTPS(FTP over SSL/TLS),但只要攻击者能接触到服务器所在的网络段,抓包破解只是时间问题。
更关键的是,站群场景下的FTP账号有一个致命特征:账号多、使用频率低、长期处于"开着但不用"的状态。一个服务器上30个站点,每个站点配一个FTP账号给客户或编辑使用,但真正每天用FTP上传文件的人可能不到3个。剩下27个账号就是27扇开着的门,虽然上了锁(有密码),但门本身一直存在。
风险1:暴力破解

攻击者用字典穷举密码,fail2ban只能延缓不能根除。30个账号×每个每天被试探1000次=3万次攻击。
风险2:闲置账号
30个账号可能25个长期不用,但攻击者不知道哪个在用、哪个不在用。全锁了只留需要的,攻击面缩小90%。
风险3:人为泄露
FTP密码可能通过邮件、微信、文档分享过。不知道哪些人手里有密码,批量改密码+锁定是最保险的。
安全领域有个概念叫"最小权限原则"和"默认拒绝策略":不用的服务关掉,不用的端口封掉,不用的账号锁掉。FTP账号批量锁定就是这个原则在站群运维中的落地——平时全锁,谁要用临时解锁,用完重新锁。
二、四种场景下的批量锁定解锁方案,从宝塔面板到纯命令行
方案一:宝塔面板批量管理(适合面板用户,最简单)
如果你用的是宝塔面板,FTP账号管理在"FTP"菜单里。默认情况下Pure-FTPd是宝塔的FTP服务,每个FTP账号对应一个系统用户(格式通常是www_ftp_站点名)。单个账号的锁定:找到对应账号,点"停用"按钮。
但宝塔面板的FTP管理界面没有"全选→批量停用"的按钮,一个一个有停用,30个站点要点30次。解决方法是用宝塔API批量操作。宝塔面板提供了完整的API接口,包括FTP用户管理。
Python脚本:通过宝塔API批量停用FTP账号
import requestsimport json# 宝塔面板API基础信息PANEL_URL = "https://你的服务器IP:面板端口"API_KEY = "你的API密钥"def get_ftp_list():"""获取所有FTP用户列表"""url = f"{PANEL_URL}/ftp?action=GetList"data = {"request_token": API_KEY, "request_time": "now"}resp = requests.post(url, data=data, verify=False)return resp.json().get("data", [])def set_ftp_status(username, status="0"):"""设置FTP用户状态:0=停用,1=启用"""url = f"{PANEL_URL}/ftp?action=SetStatus"data = {"request_token": API_KEY,"request_time": "now","username": username,"status": status}resp = requests.post(url, data=data, verify=False)return resp.json()# 批量停用所有FTP账号(保留白名单中的账号)WHITELIST = ["admin_ftp", "webmaster_ftp"] # 不锁定的账号users = get_ftp_list()for user in users:name = user.get("name", "")if name in WHITELIST:print(f"⏭ 跳过白名单账号: {name}")continueresult = set_ftp_status(name, "0")print(f"🔒 已锁定: {name}")print("批量锁定完成")方案二:Linux命令行批量锁定(适合有SSH权限的用户,最灵活)
宝塔面板底层用的Pure-FTPd,每个FTP账号对应一个Linux系统用户(用户名格式为www_ftp_xxx)。在Linux系统层面,usermod -L命令可以锁定用户账号(在/etc/shadow中密码字段前加!),usermod -U解锁。这意味着批量锁定FTP账号本质上就是批量锁定对应的Linux系统用户。
Shell脚本:批量锁定所有FTP相关账号(一行命令版本)
# 锁定所有www_ftp_开头的FTP账号cat /etc/passwd | grep '^www_ftp_' | cut -d: -f1 | xargs -I {} usermod -L {}Shell脚本:带白名单的批量锁定/解锁(推荐版本)
#!/bin/bash# FTP批量锁定脚本(带白名单)# 白名单:这些账号不会被锁定WHITELIST=("www_ftp_admin" "www_ftp_webmaster")# 锁定或解锁,传参 lock 或 unlockACTION=${1:-lock}# 获取所有FTP系统用户FTP_USERS=$(cat /etc/passwd | grep '^www_ftp_' | cut -d: -f1)for user in $FTP_USERS; do# 跳过白名单skip=falsefor wl in "${WHITELIST[@]}"; doif [ "$user" == "$wl" ]; thenskip=truebreakfidoneif [ "$skip" = true ]; thenecho "⏭ 跳过白名单: $user"continuefiif [ "$ACTION" = "unlock" ]; thenusermod -U "$user" 2>/dev/nullecho "🔓 已解锁: $user"elseusermod -L "$user" 2>/dev/nullecho "🔒 已锁定: $user"fidoneecho "操作完成"# 使用方式:# bash ftp_lock.sh lock → 批量锁定# bash ftp_lock.sh unlock → 批量解锁方案三:Pure-FTPd命令行直接管理(不依赖宝塔,直接操作FTP服务)
Pure-FTPd有自己的用户数据库(通常存储在/etc/pure-ftpd/pureftpd.passwd或/etc/pure-ftpd/pureftpd.pdb),和Linux系统用户是两套体系。通过pure-pw命令可以直接管理FTP用户,不需要操作Linux系统用户。
Pure-FTPd命令:列出所有FTP虚拟用户并批量操作
# 列出所有Pure-FTPd虚拟用户pure-pw list# 禁用某个FTP用户(临时禁止登录,不删除账号)pure-pw usermod 用户名 -r # -r表示restrict,限制登录# 恢复某个FTP用户pure-pw usermod 用户名 -R # 取消限制# 批量禁用(从用户列表中读取)pure-pw list | awk '{print $1}' | while read user; dopure-pw usermod "$user" -recho "已限制: $user"done# 改完后必须更新Pure-FTPd数据库pure-pw mkdb方案四:vsftpd环境下的批量锁定(不用宝塔、不用Pure-FTPd的场景)
如果你的服务器用的是vsftpd而不是Pure-FTPd,批量锁定的方法略有不同。vsftpd的用户管理依赖Linux系统用户+PAM认证,或者虚拟用户配置文件。
vsftpd批量锁定:使用/etc/vsftpd/user_list黑名单

# 1. 在vsftpd.conf中启用userlist_denyecho "userlist_enable=YES" >> /etc/vsftpd/vsftpd.confecho "userlist_deny=YES" >> /etc/vsftpd/vsftpd.conf# 2. 批量把FTP用户加入黑名单文件cat /etc/passwd | grep '^ftp_' | cut -d: -f1 > /etc/vsftpd/user_list# 3. 重启vsftpd生效systemctl restart vsftpd# 解锁:清空user_list文件(保留白名单)echo "admin_ftp" > /etc/vsftpd/user_listsystemctl restart vsftpd三、四种方案对比:按你的环境选一种就够了
| 方案 | 适用环境 | 操作方式 | 批量难度 | 需要权限 | 推荐度 |
|---|---|---|---|---|---|
| 宝塔面板API | 装了宝塔面板的服务器 | Python调API | 低 | 面板管理员 | ⭐⭐⭐⭐⭐ |
| usermod批量 | 有SSH的Linux服务器 | Shell脚本 | 低 | root | ⭐⭐⭐⭐⭐ |
| pure-pw命令 | Pure-FTPd虚拟用户环境 | Shell命令 | 中 | root | ⭐⭐⭐⭐ |
| vsftpd user_list | vsftpd环境 | 修改配置文件+重启 | 中 | root | ⭐⭐⭐ |
四、锁定只是第一步,配套的安全策略比锁本身更重要
批量锁定FTP账号是基础操作,但要真正把FTP安全做好,需要一套完整的策略。锁了账号但端口还开着,攻击者照样能探测FTP服务是否存在。锁了账号但没限制IP来源,白名单账号被撞库成功照样沦陷。
在iptables或ufw里只允许特定IP访问21端口(FTP控制端口)和被动模式端口范围。即使FTP账号没锁定,攻击者从非白名单IP连端口都到不了。如果使用云服务器,可以在云防火墙(安全组)层面设置,比服务器本地防火墙更前置。
iptables -A INPUT -p tcp --dport 21 -s 你的办公IP -j ACCEPT
iptables -A INPUT -p tcp --dport 21 -j DROP
fail2ban默认是封IP,但可以配置成"封IP的同时锁定被攻击的账号"。在fail2ban的action里加一条usermod -L命令,某个账号被爆破3次就直接锁账号,比只封IP更狠。这样攻击者换IP也没用,因为账号已经被锁了。
最容易被忽略的一点:临时解锁了一个FTP账号给客户用,用完之后忘了重新锁定,账号又变成"开着但不用"的状态。用crontab设置定时任务,每天凌晨2点自动跑一遍锁定脚本,确保所有非白名单账号始终处于锁定状态。临时需要用时手动解锁,第二天自动锁回去。
0 2 * * * /root/scripts/ftp_lock.sh lock >> /var/log/ftp_lock.log 2>&1
FTP协议本身的安全缺陷是无法通过锁定账号完全解决的——只要FTP服务在运行,攻击者就能探测端口、尝试登录。长期来看,用SFTP(SSH File Transfer Protocol)替代FTP是更彻底的做法。SFTP走SSH通道,加密传输,而且和SSH共用端口(22),少开一个端口就少一个攻击面。如果用户只是上传下载文件,SFTP客户端(FileZilla、WinSCP都支持SFTP)体验和FTP几乎一样。
五、多服务器场景:一个脚本管多台服务器的FTP账号
如果你的站群分布在多台服务器上,每台服务器都要单独SSH上去跑锁定脚本,10台服务器就是10次操作。这种情况可以用一个中控脚本通过SSH远程执行命令,一次操作管所有服务器。
中控脚本:SSH远程批量锁定多台服务器的FTP账号
#!/bin/bash# 多服务器FTP批量锁定中控脚本# 服务器列表(IP或域名)SERVERS=("root@192.168.1.10""root@192.168.1.20""root@192.168.1.30")# 要执行的远程命令REMOTE_CMD="cat /etc/passwd | grep '^www_ftp_' | cut -d: -f1 | xargs -I {} usermod -L {}"for server in "${SERVERS[@]}"; doecho "正在操作: $server"ssh -o ConnectTimeout=5 "$server" "$REMOTE_CMD"if [ $? -eq 0 ]; thenecho "✅ $server 锁定完成"elseecho "❌ $server 操作失败,请检查连接"fiecho "---"doneecho "全部服务器操作完成"前提是已经配置好了SSH免密登录(ssh-keygen + ssh-copy-id),否则每台服务器都要输密码,批量就没意义了。如果服务器用的是宝塔面板,中控脚本也可以统一调宝塔API,不需要SSH。
六、三个容易出错的点,操作之前先看清楚
· 别把root或系统关键用户锁了
批量锁定脚本用grep过滤FTP用户时,确认过滤条件精确。比如用'^www_ftp_'精确匹配宝塔FTP用户前缀,而不是模糊匹配'ftp'(可能误伤系统ftp用户)。白名单一定要配,至少保留一个能登录的账号。
· 锁定Linux系统用户会影响的不只是FTP
usermod -L锁定的是Linux系统用户账号,不仅仅是FTP登录。如果这个用户还被用于其他服务(比如SSH登录、数据库连接),锁定后这些服务也会受影响。确认FTP用户是独立的、不和其他服务共用的。
· 批量解锁后记得重新锁定
临时解锁后用完一定要重新锁定。依赖crontab定时自动锁定是兜底方案,但不能完全依赖——如果攻击者在你解锁后的几个小时窗口期内发起攻击,定时任务还没触发。解锁操作的流程应该是:解锁→用户完成操作→立即锁定,中间不留空窗期。可以写一个"解锁后X小时自动锁定"的at命令或sleep+lock的后台进程。
最后说几句
FTP批量锁定这件事,技术含量不高,一个Shell脚本十几行代码就能搞定。但真正有价值的不是脚本本身,而是"默认锁定、按需解锁、用完即锁"这套运维思维。把这个思路延伸到其他服务也一样——不用的端口关掉,不用的服务停掉,不用的账号锁掉。攻击面越小,安全风险越低,这个道理简单到几乎不用解释,但真正落实到30个站的运维里,大部分人都在出了问题之后才想起来做。
另外有个大方向值得考虑:如果FTP只用来上传文件,那SFTP完全可以替代,少开一个端口、加密传输、和SSH统一管理。如果用的是建站平台而不是自建服务器,FTP管理更简单——平台会抽象掉底层用户管理,后台直接控制账号启停,不需要上服务器敲命令。无论哪种方案,批量操作+白名单+定时锁定这三板斧配齐了,FTP被爆破这件事基本就不用操心了。
核心要点:
- 站群场景FTP账号特点是"多、杂、长期闲置",攻击面大,默认应该全部锁定
- 宝塔面板用户用API批量操作最省事,一行Python调接口批量停用
- 有SSH权限直接用usermod -L批量锁定Linux系统用户,Shell脚本十几行搞定
- 白名单机制是核心:至少保留1-2个管理员账号不锁,配IP白名单限制来源
- crontab定时自动锁定是兜底方案,每天凌晨跑一遍确保没漏网之鱼
- IP白名单在防火墙层面做,比单纯锁账号更安全(攻击者连端口都到不了)
- 长期方案考虑SFTP替代FTP,走SSH通道加密传输,少开端口少攻击面
- 多服务器场景写中控脚本,SSH远程批量执行,一台机器管所有服务器
