本文目录导读:

防止SSH暴力破解是服务器安全的重要一环,Shell脚本可以实现多种防护机制,以下是一些常见且有效的方法:
使用fail2ban(推荐,但非纯Shell)
虽然不是纯Shell,但这是最成熟的方法:
# 安装fail2ban apt-get install fail2ban # Debian/Ubuntu yum install fail2ban # CentOS/RHEL # 配置SSH防护 cat > /etc/fail2ban/jail.local << 'EOF' [sshd] enabled = true port = ssh filter = sshd logpath = /var/log/auth.log maxretry = 3 bantime = 3600 findtime = 600 EOF systemctl restart fail2ban
纯Shell脚本实现IP白名单
#!/bin/bash
# IP白名单防护脚本
ALLOWED_IPS=("192.168.1.0/24" "10.0.0.0/8")
AUTH_LOG="/var/log/auth.log"
BAN_DURATION=3600 # 封禁时长(秒)
ban_ip() {
local ip=$1
echo "封禁IP: $ip"
# 使用iptables封禁
iptables -A INPUT -s $ip -j DROP
# 定时解封
(sleep $BAN_DURATION && iptables -D INPUT -s $ip -j DROP) &
}
# 监控日志
tail -f $AUTH_LOG | while read line; do
if echo "$line" | grep -q "Failed password"; then
ip=$(echo "$line" | grep -oP 'from \K(\d+\.\d+\.\d+\.\d+)')
# 检查是否在白名单
in_whitelist=false
for allowed in "${ALLOWED_IPS[@]}"; do
if [[ $ip =~ $allowed ]]; then
in_whitelist=true
break
fi
done
if [ "$in_whitelist" = false ]; then
ban_ip $ip
fi
fi
done
基于失败次数自动封禁
#!/bin/bash
# 失败次数阈值
MAX_ATTEMPTS=5
CHECK_INTERVAL=300 # 检查间隔(秒)
BAN_DURATION=3600
# 临时文件存储失败记录
FAIL_LOG="/tmp/ssh_failed_ips.txt"
check_and_ban() {
while IFS= read -r line; do
ip=$line
attempts=$(grep -c "$ip" /var/log/auth.log | tail -n 100)
if [ "$attempts" -ge "$MAX_ATTEMPTS" ]; then
echo "IP $ip 超过失败次数,执行封禁"
iptables -A INPUT -s $ip -j DROP
echo "$ip" >> /tmp/banned_ips.txt
# 定时解封
(sleep $BAN_DURATION &&
iptables -D INPUT -s $ip -j DROP &&
sed -i "/$ip/d" /tmp/banned_ips.txt) &
fi
done < <(grep -oP 'Failed password for .* from \K(\d+\.\d+\.\d+\.\d+)' /var/log/auth.log | sort -u)
}
# 主循环
while true; do
check_and_ban
sleep $CHECK_INTERVAL
done
增强版:动态防火墙脚本
#!/bin/bash
# 配置
MAX_ATTEMPTS=3
BAN_TIME=3600
WHITELIST=(192.168.1.100 10.0.0.50)
LOG_FILE="/var/log/auth.log"
BAN_LOG="/var/log/ssh_ban.log"
# 获取需要监控的IP列表
get_offending_ips() {
# 分析30分钟内的失败登录
grep "Failed password" $LOG_FILE | \
awk '{print $(NF-3)}' | \
sort | uniq -c | \
awk -v max="$MAX_ATTEMPTS" '$1 >= max {print $2}'
}
# 白名单过滤
is_whitelisted() {
local ip=$1
for whitelist_ip in "${WHITELIST[@]}"; do
if [ "$ip" = "$whitelist_ip" ]; then
return 0
fi
done
return 1
}
# 封禁IP
ban_ip() {
local ip=$1
if ! iptables -C INPUT -s $ip -j DROP 2>/dev/null; then
iptables -A INPUT -s $ip -j DROP
echo "$(date) - 封禁IP: $ip" >> $BAN_LOG
# 异步解封
(sleep $BAN_TIME &&
iptables -D INPUT -s $ip -j DROP &&
echo "$(date) - 解封IP: $ip" >> $BAN_LOG)&
fi
}
# 主逻辑
main() {
local offending_ips=$(get_offending_ips)
for ip in $offending_ips; do
if ! is_whitelisted $ip; then
ban_ip $ip
fi
done
}
# 设置定时执行
while true; do
main
sleep 300 # 每5分钟检查一次
done
SSH配置加固(最基础)
#!/bin/bash
# SSH配置加固脚本
SSHD_CONFIG="/etc/ssh/sshd_config"
# 备份原配置
cp $SSHD_CONFIG ${SSHD_CONFIG}.bak
# 应用安全配置
cat >> $SSHD_CONFIG << 'EOF'
# 限制登录尝试
MaxAuthTries 3
MaxSessions 2
# 禁止root直接登录
PermitRootLogin no
# 使用密钥登录(推荐)
PasswordAuthentication no
PubkeyAuthentication yes
# 限制登录用户
AllowUsers your_username
DenyUsers root
# 限制IP
ListenAddress 192.168.1.0/24
# 超时设置
ClientAliveInterval 300
ClientAliveCountMax 2
EOF
# 重启SSH服务
systemctl restart sshd
完整的防护脚本
#!/bin/bash
# ==================== 配置 ====================
SSH_PORT=22
MAX_ATTEMPTS=5
BAN_TIME=86400 # 24小时
CHECK_INTERVAL=60
LOG_FILE="/var/log/auth.log"
BANNED_FILE="/tmp/ssh_banned_ips.txt"
WHITELIST_FILE="/etc/ssh_whitelist.txt"
# ==============================================
# 初始化
init() {
# 创建必要文件
[ ! -f $BANNED_FILE ] && touch $BANNED_FILE
[ ! -f $WHITELIST_FILE ] && touch $WHITELIST_FILE
# 加载白名单
mapfile -t WHITELIST < $WHITELIST_FILE 2>/dev/null
}
# 日志记录
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> /var/log/ssh_protect.log
}
# 检查IP是否已封禁
is_banned() {
grep -q "$1" $BANNED_FILE
}
# 检查IP是否在白名单
in_whitelist() {
local ip=$1
for wl_ip in "${WHITELIST[@]}"; do
[ "$ip" = "$wl_ip" ] && return 0
done
return 1
}
# 封禁IP
ban_ip() {
local ip=$1
local reason="$2"
if ! is_banned "$ip" && ! in_whitelist "$ip"; then
# 使用iptables封禁
iptables -A INPUT -p tcp --dport $SSH_PORT -s $ip -j DROP
echo "$ip" >> $BANNED_FILE
log "封禁IP: $ip - 原因: $reason"
# 定时解封
(sleep $BAN_TIME &&
iptables -D INPUT -p tcp --dport $SSH_PORT -s $ip -j DROP 2>/dev/null &&
sed -i "/^$ip$/d" $BANNED_FILE &&
log "解封IP: $ip") &
fi
}
# 分析日志并封禁
analyze_and_ban() {
# 获取最近失败的登录IP及其次数
local failed_ips=$(grep "Failed password" $LOG_FILE | \
grep -oP 'from \K(\d+\.\d+\.\d+\.\d+)')
# 统计每个IP的失败次数
echo "$failed_ips" | sort | uniq -c | \
while read count ip; do
count=$(echo $count | tr -d ' ')
if [ "$count" -ge "$MAX_ATTEMPTS" ]; then
ban_ip "$ip" "失败登录${count}次"
fi
done
}
# 监控实时日志
monitor_realtime() {
tail -f $LOG_FILE | while read line; do
if echo "$line" | grep -q "Failed password"; then
ip=$(echo "$line" | grep -oP 'from \K(\d+\.\d+\.\d+\.\d+)')
# 检查短时间内是否再次失败
local recent_fails=$(grep "$ip" $LOG_FILE | grep "Failed password" | \
awk -v date="$(date -d '5 minutes ago' '+%b %d %H:%M')" \
'$0 > date' | wc -l)
if [ "$recent_fails" -ge "$MAX_ATTEMPTS" ]; then
ban_ip "$ip" "5分钟内失败${recent_fails}次"
fi
fi
done
}
# 清理过期封禁
cleanup() {
while IFS= read -r ip; do
if [ -n "$ip" ]; then
# 检查iptables规则是否还在
if iptables -C INPUT -p tcp --dport $SSH_PORT -s $ip -j DROP 2>/dev/null; then
# 检查是否超时(这里简化处理,实际应用中需要记录封禁时间)
log "清理检查IP: $ip"
fi
fi
done < $BANNED_FILE
}
# 主函数
main() {
init
log "SSH防暴力破解脚本启动"
# 启动定时检查和实时监控
while true; do
analyze_and_ban
cleanup
sleep $CHECK_INTERVAL
done &
# 实时监控
monitor_realtime
}
# 执行
main
使用建议
- 先测试:在非生产环境测试脚本
- 保留备用通道:不要在测试完成前完全禁止密码登录
- 结合多种方法:脚本+ fail2ban + 安全配置
- 监控和日志:定期检查封禁日志
- 定期更新白名单:确保合法用户不被误封
这些脚本可以根据实际需求调整参数,建议先在测试环境验证,确保不会误封合法用户。