当前位置: 代码网 > 服务器>服务器>Linux > Linux防止SSH暴力破解的多种方法

Linux防止SSH暴力破解的多种方法

2026年04月27日 Linux 我要评论
引言ssh(secure shell)是 linux 系统管理员远程管理服务器最常用的协议。它安全、稳定、功能强大,但也正因为如此,ssh 服务往往成为黑客攻击的首要目标 ——

引言

ssh(secure shell)是 linux 系统管理员远程管理服务器最常用的协议。它安全、稳定、功能强大,但也正因为如此,ssh 服务往往成为黑客攻击的首要目标 —— 尤其是暴力破解(brute force attack)。攻击者通过自动化脚本不断尝试用户名和密码组合,试图获得系统访问权限。一旦成功,后果不堪设想:数据泄露、系统被控、沦为肉鸡、甚至被用于发动进一步攻击。

在本文中,我们将深入探讨如何从多个维度有效防御 ssh 暴力破解攻击。不仅会介绍传统配置方法,还会提供 java 实现的实时监控与自动封禁工具,并结合可视化图表帮助你理解攻击模式和防御机制。

什么是 ssh 暴力破解?

ssh 暴力破解是指攻击者利用自动化程序,反复尝试不同的用户名和密码组合,以期“撞开”系统的登录大门。这类攻击通常具有以下特征:

  • 高频次连接请求(每秒数次到数百次)
  • 使用常见用户名(如 root, admin, test
  • 使用弱密码字典(如 123456, password, qwerty
  • 来源 ip 分布广泛或集中在某些恶意 ip 段
  • 攻击持续时间长,可能持续数天甚至数周

小知识:根据 shodan.io 的统计,全球每天有超过 200 万次 ssh 登录尝试来自恶意扫描器。

ssh 攻击趋势分析(mermaid 图表)

我们先来看一组模拟的 ssh 攻击频率随时间变化图,这有助于理解为何我们需要主动防御:

从上图可见,攻击并非均匀分布,而是集中在工作时间段,且周三出现“持续攻击”,说明攻击者也在“上班”。我们需要的是动态、智能、多层次的防御策略。

方法一:修改默认 ssh 端口

这是最基础但非常有效的一步。默认的 ssh 端口是 22,绝大多数自动化脚本都只会扫这个端口。改个端口,能过滤掉 90% 的低级扫描。

操作步骤:

  1. 编辑 ssh 配置文件:
sudo nano /etc/ssh/sshd_config
  1. 找到 port 22,修改为其他端口(比如 2222):
port 2222
  1. 重启 ssh 服务:
sudo systemctl restart sshd
  1. 别忘了在防火墙放行新端口:
sudo ufw allow 2222/tcp

注意:修改端口前请确保你有其他方式访问服务器(如控制台),避免把自己锁在外面!

方法二:禁用 root 登录

root 是 linux 的超级用户,也是攻击者的首要目标。禁用其直接登录可大幅提升安全性。

操作步骤:

编辑 /etc/ssh/sshd_config

permitrootlogin no

然后重启 ssh:

sudo systemctl restart sshd

之后,你需要先用普通用户登录,再通过 su -sudo 提权。

方法三:启用密钥认证,禁用密码登录

密码容易被暴力破解,而 ssh 密钥几乎不可能被暴力攻破(前提是私钥保管好)。

操作步骤:

  1. 在本地生成密钥对(如果还没有):
ssh-keygen -t rsa -b 4096
  1. 将公钥上传到服务器:
ssh-copy-id -p 2222 user@your-server-ip
  1. 修改 /etc/ssh/sshd_config
passwordauthentication no
pubkeyauthentication yes
  1. 重启 ssh:
sudo systemctl restart sshd

现在只能通过私钥登录,暴力破解彻底失效!

方法四:使用 fail2ban 自动封禁恶意 ip

fail2ban 是一个入侵防御软件,它能监控日志文件,发现多次失败登录后自动将 ip 加入防火墙黑名单。

安装与配置:

sudo apt update
sudo apt install fail2ban

复制默认配置:

sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

编辑 jail.local,设置 ssh 监控:

[sshd]
enabled = true
port = 2222
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 86400
findtime = 600

解释:

  • maxretry = 3:10分钟内失败3次就封
  • bantime = 86400:封禁24小时
  • findtime = 600:监控最近10分钟内的日志

启动服务:

sudo systemctl enable fail2ban
sudo systemctl start fail2ban

查看封禁状态:

sudo fail2ban-client status sshd

方法五:配置防火墙限制访问来源

如果你的团队只有固定几个 ip 需要访问 ssh,那就只允许这些 ip 连接。

使用 ufw(ubuntu):

sudo ufw allow from 192.168.1.100 to any port 2222
sudo ufw deny 2222
sudo ufw enable

使用 firewalld(centos/rhel):

sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.100" port protocol="tcp" port="2222" accept'
sudo firewall-cmd --permanent --remove-service=ssh
sudo firewall-cmd --reload

这样,非白名单 ip 根本连不上 ssh 端口。

方法六:部署自研 java 监控工具(实战代码!)

虽然 fail2ban 很强大,但有时我们需要更灵活的控制 —— 比如对接企业内部告警系统、发送邮件、记录数据库、或对接云平台 api。

下面是一个用 java 编写的简易 ssh 暴力破解监控器,它读取 /var/log/auth.log,检测失败登录,自动调用 iptables 封禁 ip。

项目结构简洁,适合二次开发集成到现有运维平台。

项目依赖(maven)

<dependencies>
    <dependency>
        <groupid>ch.qos.logback</groupid>
        <artifactid>logback-classic</artifactid>
        <version>1.4.11</version>
    </dependency>
    <dependency>
        <groupid>org.apache.commons</groupid>
        <artifactid>commons-lang3</artifactid>
        <version>3.13.0</version>
    </dependency>
</dependencies>

核心代码:sshmonitor.java

import org.apache.commons.lang3.stringutils;
import org.slf4j.logger;
import org.slf4j.loggerfactory;
import java.io.bufferedreader;
import java.io.file;
import java.io.filereader;
import java.io.ioexception;
import java.time.localdatetime;
import java.time.format.datetimeformatter;
import java.util.*;
import java.util.concurrent.executors;
import java.util.concurrent.scheduledexecutorservice;
import java.util.concurrent.timeunit;
import java.util.regex.matcher;
import java.util.regex.pattern;
public class sshmonitor {
    private static final logger logger = loggerfactory.getlogger(sshmonitor.class);
    // 日志文件路径(ubuntu/debian)
    private static final string auth_log_path = "/var/log/auth.log";
    // 匹配失败登录的正则表达式
    private static final string failed_login_pattern =
            ".*failed password for (?:invalid user )?(\\s+) from (\\d+\\.\\d+\\.\\d+\\.\\d+).*";
    // 白名单ip(不封禁)
    private static final set<string> white_list = set.of(
            "127.0.0.1",
            "192.168.1.1", // 示例,替换成你的管理ip
            "10.0.0.1"
    );
    // 失败次数阈值
    private static final int max_retry = 5;
    // 封禁时长(秒)
    private static final int ban_duration = 3600; // 1小时
    // 存储ip失败次数
    private final map<string, integer> failedattempts = new hashmap<>();
    // 存储已封禁ip及解封时间
    private final map<string, localdatetime> bannedips = new hashmap<>();
    public void startmonitoring() {
        scheduledexecutorservice scheduler = executors.newscheduledthreadpool(1);
        // 每10秒扫描一次日志
        scheduler.scheduleatfixedrate(this::scanauthlog, 0, 10, timeunit.seconds);
        // 每分钟清理过期封禁
        scheduler.scheduleatfixedrate(this::unbanexpiredips, 0, 1, timeunit.minutes);
        logger.info("ssh 暴力破解监控器已启动...");
    }
    private void scanauthlog() {
        file logfile = new file(auth_log_path);
        if (!logfile.exists()) {
            logger.warn("日志文件不存在: {}", auth_log_path);
            return;
        }
        try (bufferedreader reader = new bufferedreader(new filereader(logfile))) {
            string line;
            pattern pattern = pattern.compile(failed_login_pattern);
            while ((line = reader.readline()) != null) {
                matcher matcher = pattern.matcher(line);
                if (matcher.matches()) {
                    string user = matcher.group(1);
                    string ip = matcher.group(2);
                    if (white_list.contains(ip)) {
                        continue; // 白名单跳过
                    }
                    failedattempts.merge(ip, 1, integer::sum);
                    int attempts = failedattempts.get(ip);
                    logger.warn("检测到失败登录: 用户={} ip={} 尝试次数={}", user, ip, attempts);
                    if (attempts >= max_retry && !bannedips.containskey(ip)) {
                        banip(ip);
                    }
                }
            }
        } catch (ioexception e) {
            logger.error("读取日志文件失败", e);
        }
    }
    private void banip(string ip) {
        try {
            // 调用 iptables 封禁
            string cmd = string.format("iptables -a input -s %s -j drop", ip);
            process process = runtime.getruntime().exec(cmd);
            process.waitfor();
            localdatetime unbantime = localdatetime.now().plusseconds(ban_duration);
            bannedips.put(ip, unbantime);
            logger.info("⛔ 已封禁 ip: {},解封时间: {}", ip, unbantime.format(datetimeformatter.ofpattern("yyyy-mm-dd hh:mm:ss")));
            // 可选:发送邮件/企业微信/钉钉通知
            // sendalert("ssh暴力破解警报", "ip " + ip + " 因多次失败登录已被封禁");
        } catch (exception e) {
            logger.error("封禁ip失败: {}", ip, e);
        }
    }
    private void unbanexpiredips() {
        localdatetime now = localdatetime.now();
        list<string> tounban = new arraylist<>();
        for (map.entry<string, localdatetime> entry : bannedips.entryset()) {
            if (now.isafter(entry.getvalue())) {
                tounban.add(entry.getkey());
            }
        }
        for (string ip : tounban) {
            try {
                string cmd = string.format("iptables -d input -s %s -j drop", ip);
                process process = runtime.getruntime().exec(cmd);
                process.waitfor();
                bannedips.remove(ip);
                failedattempts.remove(ip); // 清除计数
                logger.info("✅ 已解封 ip: {}", ip);
            } catch (exception e) {
                logger.error("解封ip失败: {}", ip, e);
            }
        }
    }
    // 可扩展:发送告警通知
    private void sendalert(string title, string content) {
        // 此处可集成邮件、slack、企业微信、钉钉等
        // 示例略...
    }
    public static void main(string[] args) {
        new sshmonitor().startmonitoring();
    }
}

如何运行?

  1. 编译打包成 jar:
mvn clean package
  1. 后台运行(需 root 权限,因为要执行 iptables):
sudo java -jar ssh-monitor.jar
  1. 查看日志:
tail -f logs/app.log

可扩展功能建议:

  • 对接 redis 存储状态,支持多节点部署
  • 记录攻击日志到 mysql/elasticsearch
  • 调用云厂商 api(如阿里云、aws)添加安全组规则
  • 发送 telegram/slack/dingtalk 告警
  • 支持 geoip 定位攻击者地理位置

攻击者地理分布模拟(mermaid 图表)

了解攻击来源有助于制定更有针对性的防御策略。以下是模拟的攻击 ip 地理分布:

渲染错误: mermaid 渲染失败: parsing failed: lexer error on line 3, column 5: unexpected character: ->“<- at offset: 34, skipped 4 characters. lexer error on line 3, column 10: unexpected character: ->:<- at offset: 39, skipped 1 characters. lexer error on line 4, column 5: unexpected character: ->“<- at offset: 48, skipped 4 characters. lexer error on line 4, column 10: unexpected character: ->:<- at offset: 53, skipped 1 characters. lexer error on line 5, column 5: unexpected character: ->“<- at offset: 62, skipped 5 characters. lexer error on line 5, column 11: unexpected character: ->:<- at offset: 68, skipped 1 characters. lexer error on line 6, column 5: unexpected character: ->“<- at offset: 77, skipped 4 characters. lexer error on line 6, column 10: unexpected character: ->:<- at offset: 82, skipped 1 characters. lexer error on line 7, column 5: unexpected character: ->“<- at offset: 91, skipped 4 characters. lexer error on line 7, column 10: unexpected character: ->:<- at offset: 96, skipped 1 characters. lexer error on line 8, column 5: unexpected character: ->“<- at offset: 104, skipped 4 characters. lexer error on line 8, column 10: unexpected character: ->:<- at offset: 109, skipped 1 characters. parse error on line 3, column 12: expecting token of type 'eof' but found `35`. parse error on line 4, column 12: expecting token of type 'eof' but found `25`. parse error on line 5, column 13: expecting token of type 'eof' but found `15`. parse error on line 6, column 12: expecting token of type 'eof' but found `10`. parse error on line 7, column 12: expecting token of type 'eof' but found `8`. parse error on line 8, column 12: expecting token of type 'eof' but found `7`.

可见,攻击来源分布广泛,无法单纯靠地域屏蔽。但可以结合威胁情报(如 abuseipdb)动态更新黑名单。

方法七:使用云端威胁情报服务

一些第三方服务提供全球恶意 ip 数据库,我们可以定期拉取并更新本地防火墙规则。

推荐两个免费 api:

abuseipdb
emerging threats

示例:定时拉取 abuseipdb 黑名单

#!/bin/bash
# download-blacklist.sh
api_key="your_api_key_here"
blacklist_url="https://api.abuseipdb.com/api/v2/blacklist?confidenceminimum=90"
curl -g $blacklist_url \
  -h "key: $api_key" \
  -h "accept: application/json" \
  --data-urlencode "confidenceminimum=90" \
  | jq -r '.data[].ipaddress' > /tmp/abuseip_blacklist.txt
while read ip; do
    iptables -a input -s $ip -j drop
done < /tmp/abuseip_blacklist.txt
logger "已从 abuseipdb 更新 $(wc -l < /tmp/abuseip_blacklist.txt) 个恶意ip"

添加到 crontab,每天凌晨更新:

0 2 * * * /path/to/download-blacklist.sh

方法八:双因素认证(2fa)

即使密码或密钥泄露,2fa 也能提供最后一道防线。推荐使用 google authenticator。

ubuntu 安装步骤:

sudo apt install libpam-google-authenticator

运行初始化:

google-authenticator

按提示操作,保存备用码,扫描二维码绑定手机 app。

编辑 pam 配置:

sudo nano /etc/pam.d/sshd

添加:

auth required pam_google_authenticator.so

编辑 ssh 配置:

sudo nano /etc/ssh/sshd_config

确保:

challengeresponseauthentication yes
authenticationmethods publickey,keyboard-interactive

重启 ssh:

sudo systemctl restart sshd

下次登录时,除了密钥,还需输入手机上的 6 位验证码。

方法九:定期审计与日志分析

再好的防御也需要定期检查。建议每周审查 ssh 登录日志:

# 查看最近成功登录
last

# 查看失败登录
grep "failed password" /var/log/auth.log | tail -20

# 统计攻击最频繁的ip
grep "failed password" /var/log/auth.log | awk '{print $11}' | sort | uniq -c | sort -nr | head -10

也可以用 goaccess、elk、graylog 等工具做可视化分析。

方法十:使用端口敲门(port knocking)

这是一种“隐写术”式的安全机制:ssh 端口默认关闭,只有按特定顺序“敲击”几个端口后,才临时开放 ssh。

安装 knockd:

sudo apt install knockd

配置 /etc/knockd.conf

[options]
    usesyslog

[openssh]
    sequence    = 7000,8000,9000
    seq_timeout = 10
    command     = /sbin/iptables -a input -s %ip% -p tcp --dport 2222 -j accept
    tcpflags    = syn

[closessh]
    sequence    = 9000,8000,7000
    seq_timeout = 10
    command     = /sbin/iptables -d input -s %ip% -p tcp --dport 2222 -j accept
    tcpflags    = syn

启动服务:

sudo systemctl start knockd
sudo systemctl enable knockd

客户端敲门:

knock your-server-ip 7000 8000 9000
ssh -p 2222 user@your-server-ip

完成操作后,再敲反向序列关闭端口:

knock your-server-ip 9000 8000 7000

隐蔽性极强,但操作略繁琐,适合高安全场景。

测试你的防御是否生效

部署完上述措施后,务必进行测试:

  1. 端口扫描测试
nmap -p 22,2222 your-server-ip

应只看到 2222 开放(或完全无响应)。

  1. 暴力破解模拟(仅限自己服务器!):
hydra -l root -p /path/to/passwords.txt ssh://your-server-ip:2222 -t 4

观察是否被 fail2ban 或 java 工具封禁。

  1. 登录测试

确保你仍能通过密钥 + 2fa 正常登录。

总结:构建纵深防御体系

没有单一方案能 100% 防御 ssh 暴力破解。最佳实践是分层防御

每一层都是保险丝,即使某一层被绕过,下一层仍能阻止入侵。

结语

ssh 是我们管理 linux 服务器的生命线,保护它就是保护我们的数字资产。通过本文介绍的十种方法 —— 从简单改端口,到编写 java 自动防御程序 —— 你可以根据自身需求构建一套坚固、灵活、智能的防御体系。

记住:安全不是一次性任务,而是持续的过程。定期更新、审计、演练,才能在真正的攻击来临时从容应对。

保持警惕,安全无忧。

如果你觉得本文有帮助,欢迎分享给你的运维小伙伴!一起提升 linux 服务器的安全水位!

本文所有代码示例均可在标准 linux + java 11+ 环境下运行。生产环境使用前请充分测试并做好备份。

以上就是linux防止ssh暴力破解的多种方法的详细内容,更多关于linux防止ssh暴力破解的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com