飘云阁安全论坛

 找回密码
 快速注册

QQ登录

只需一步,快速开始

查看: 769|回复: 2

[其他内容] [原创][翻译]严加保护SSH-正确的方法

  [复制链接]
  • TA的每日心情
    开心
    2019-3-15 11:00
  • 签到天数: 262 天

    [LV.8]以坛为家I

    发表于 2021-8-24 14:48:20 | 显示全部楼层 |阅读模式
    本帖最后由 梦幻的彼岸 于 2021-8-27 09:52 编辑

    备注:
    原文地址:https://blog.zsec.uk/locking-down-ssh-the-right-way/
    原文标题:LOCKING DOWN SSH - THE RIGHT WAY
    原文信息:安全技能的一些[许多]问题
    作者:Andy Gill


    一个严加保护VPS或类似的小指南,以确保你的SSH连接是尽可能安全的。现在这已经不是什么新鲜事了,而是我最近学到的一些技巧和窍门,使我能够更好地保护我的服务器和主机。
    我将重点介绍几个基础知识,让我们开始:
    • 启用基于密钥的身份验证并生成安全密钥!
    • 启用多因素身份验证(MFA)
    • 启用限速和防火墙
    • 掩盖你的设置
    • 通过Telegram和Slack发送登录通知。
    基于密钥的身份验证
    基于密钥的SSH认证是今天在云中建立新机器时的事实标准,我学到的一个关键的东西是创建强大的密钥和加固/严加保护你的配置,可以在很大程度上帮助提供一个更安全的感觉,把一个主机放在互联网上。以安全的方式创建一个SSH密钥是非常简单的,但是在我们继续做一些之前,首先检查你是否拥有:
    1. for key in ~/.ssh/*; do ssh-KeyGen -l -f "${key}"; done | uniq
    复制代码


    为了让那些想知道的人快速分解上述命令,它主要是通过
    ~/.ssh/内的不同密钥,并显示指定公钥文件的指纹。如果你想了解该命令的全部内容,请查看这个解释shell的链接。
    如果这返回以下任何一种算法,可能值得升级或重新生成新的钥匙,这并不是说你需要销毁你的其他钥匙,而是考虑一些更强大的东西。
    • DSA: 它是不安全的,并且从OpenSSH第7版开始不再支持,因此请按照下面的步骤升级到一个更强大的密钥。
    • RSA:这取决于密钥的大小。如果它有3072或4096位的长度,那么没有问题,但是如果它是其他的,建议升级到更强的密钥。
    • ECDSA:这取决于你的机器在生成随机数方面的能力如何。
    • Ed25519: 这是目前最值得推荐的公钥算法!

    为了生成ED25519密钥,可以使用以下命令:

    1. ssh-keygen -t ed25519 -a 112 -f ~/.ssh/id_ed25519 -C "Insert a Comment Here"
    复制代码
    image.png
    该命令分解如下:
    • -t: 指定要创建的密钥类型,在本例中是Ed25519,但是默认情况下,我相信ssh-keygen会在标准Ubuntu和Debian上生成一个RSA密钥。
    • -a: 这是密钥衍生函数(KDF)的轮数。数字越大,密码验证的速度就越慢,一旦私钥被盗,就会增加对暴力破解密码的阻力。我选择了112作为随机数,但它可以是任何数字。
    • -f: 指定生成的密钥文件的文件名。要在ssh中默认使用它,它必须位于。ssh在您的主目录中,否则可以在ssh进入服务器时使用[size=13.475px]-i标志来指定:[size=13.475px]ssh -i /path/to/id_ed25519 user@host
    • -C: 指定注释的选项。这纯粹是信息,可以是任何东西。但是它通常填充了生成密钥的“在此插入注释”。当您的密钥被添加到主机的authorized_keys文件时,这将是注释。
    生成密钥后,下一步是确保SSH配置启用了基于SSH密钥的身份验证,禁用了基于密码的身份验证。为此,编辑SSH配置文件(是的,我知道vim vs nano...想用什么编辑器就用什么,我更喜欢是nano)。
    1. sudo nano /etc/ssh/sshd_config
    复制代码
    r1pe.png
    我们希望在配置中取消注释两个选项:
    1. PasswordAuthentication no
    2. PubkeyAuthentication yes
    复制代码

    默认情况下,Ubuntu服务器的PubkeyAuthentication设置为 "是",但是为了更加确定,启用它并禁用密码认证是最好的选择。此配置中的其他设置也可以改变,以增加日志的粗略程度,但我们在本节中不打算这样做。
    最后,一旦设置被更改,我们需要通过添加我们的公钥将我们的密钥添加到authorized_keys文件中:
    1. cat ~/.ssh/id_ed25519.pub >> ~/.ssh/authorized_keys
    复制代码

    这将把我们的公钥回显到授权密钥文件中,使我们能够进行SSH。请确保在退出会话之前测试您可以SSH到您的机器中,因为您可能需要处理设置,并且不想将自己锁在外面!

    一旦您满意地完成了所有配置,并且密钥都在正确的位置,请重新启动SSH服务:
    1. sudo systemctl reload sshd.service
    复制代码
    image-20.png
    接下来,一旦我们配置好了密钥,就该用MFA、限速和一些不确定因素来进一步严加保护访问。一个快速的测试显示,我们被提示输入密码,然后被认证(你会注意到认证提示我输入密码,然后是第二个验证码,这就是MFA的作用 )
    强化授权钥匙
    感谢弗洛里安·罗斯指出,授权密钥可以通过命令限制和外壳限制进一步强化,因此,如果您有特定用户,您希望限制对命令和转发等细节的访问。截图来自Florian's tweet:
    多因素身份验证
    要在SSH上启用MFA,可以配置几个选项,我选择使用google authenticator,但也有其他选项。这方面的设置相当简单,需要进行一些调整。

    首先,更新并升级操作系统至最新版本(假设是基于debian/ubuntu):
    1. sudo apt update
    2. sudo apt upgrade -y
    复制代码

    一旦系统全部更新,接下来就是安装Google Authenticator PAM模块,这个模块可以做很多事情,但是我要关注的主要安装是用于SSH身份验证的MFA:
    1. apt install libpam-google-authenticator
    复制代码

    安装PAM应用程序后,您将需要使用PAM附带的助手应用程序来生成基于时间的一次性密码(TOTP){不是我最初认为的pops之首!}要添加第二个因子的用户的密钥。该密钥是基于每个用户生成的,因此不是系统范围的。

    这意味着每个想要使用TOTP身份验证应用程序的用户都需要登录并运行助手应用程序来获取他们自己的密钥;你不能只运行一次就为所有人启用它。为此,只需运行:
    1. google-authenticator
    复制代码

    运行该命令后,您将被询问几个问题。第一个问题是身份验证令牌是否应该基于时间。我们希望选择y:
    1. Do you want authentication tokens to be time-based (y/n) y
    复制代码

    一旦我们选择是,该应用程序将生成一个二维码,可以在您选择的认证应用程序中扫描,我使用谷歌认证器,因为我在其他网站和服务器上也有它。该PAM允许基于时间或基于顺序的令牌。使用基于序列的标记意味着代码从某个点开始,然后在每次使用后递增代码。使用基于时间的令牌意味着代码在经过一定时间(通常是60秒)后随机变化。我们将坚持基于时间的,因为这是像谷歌认证器这样的应用程序所期望的,所以回答y表示是。
    image-1.png
    一旦你扫描二维码,你的应用程序将生成一个TOTP,你可以输入到命令行界面,它会提示你保存紧急代码,像其他多功能事务机一样,如果你的动态口令应用程序不能作为手动覆盖,请暂时保存这些代码。

    剩余的问题告知PAM如何运行。我们将一个一个地检查它们。
    1. Do you want me to update your "/home/zephr/.google_authenticator" file? (y/n)
    复制代码

    这会将键和选项写入。google_authenticator文件。如果选择“否”,程序将退出,并且不保存任何内容,这又会导致验证器应用程序不起作用。因此,我们要为此选择“yes”!
    1. By default, tokens are good for 30 seconds and in order to compensate for
    2. possible time-skew between the client and the server, we allow an extra
    3. token before and after the current time. If you experience problems with poor
    4. time synchronization, you can increase the window from its default
    5. size of 1:30min to about 4min. Do you want to do so (y/n) n
    复制代码

    对该问题选择“是”可在移动的四分钟窗口内启用多达8个有效代码。通过回答“否”,您可以在90秒的滚动窗口内将其限制为3个有效代码。除非您发现90秒窗口有问题,否则回答“no”是更安全的选择。
    1. If the computer that you are logging into isn't hardened against brute-force
    2. login attempts, you can enable rate-limiting for the authentication module.
    3. By default, this limits attackers to no more than 3 login attempts every 30s.
    4. Do you want to enable rate-limiting (y/n) y
    复制代码

    限速意味着远程攻击者在被阻止之前只能尝试一定数量的猜测。如果您以前没有将限速直接配置到SSH中,那么现在正是配置它的最佳时机,我们将在下一节更深入地讨论配置UFW。

    完成此设置后,如果要备份密钥,可以将~/.google authenticator文件复制到受信任的位置。从这里开始,您可以将其部署到其他系统上,或在备份后重新部署,这确实意味着在多个系统之间共享相同的TOTP代码,这不如单独的代码安全!

    完成配置google authenticator的步骤后,下一步是设置SSH配置以允许authenticator正常工作:
    1. sudo nano /etc/pam.d/sshd
    复制代码

    在文件的底部添加以下一行
    1. # Standard Un*x password updating.
    2. @include common-password
    3. auth required pam_google_authenticator.so nullok
    复制代码

    您的配置可能如下所示:
    image-3.png
    最后一行末尾的nullok字告诉PAM,这种身份验证方法是可选的。这允许没有TOTP誓言令牌的用户仍然使用他们的SSH密钥登录。一旦所有用户都有了一个宣誓-TOTP令牌,您就可以从这一行中删除nullok,以强制执行MFA。

    接下来,我们将配置SSH来支持这种身份验证。打开SSH配置文件进行编辑。
    1. sudo nano /etc/ssh/sshd_config
    复制代码

    查找ChallengeResponseAuthentication,并将其值设置为yes。我们还将通过添加身份验证方法和UsePAM来使SSH了解MFA:
    1. # To disable tunneled clear text passwords, change to no here!
    2. PasswordAuthentication no
    3. #PermitEmptyPasswords no

    4. # Change to yes to enable challenge-response passwords (beware issues with
    5. # some PAM modules and threads)
    6. ChallengeResponseAuthentication yes
    7. UsePAM yes
    8. AuthenticationMethods publickey,password publickey,keyboard-interactive
    复制代码

    此外,查找行@ include-common-auth,并通过添加#字符作为该行的第一个字符来注释掉它。这告诉PAM不要提示输入密码。
    保存配置并重新启动SSH服务。
    1. sudo systemctl reload sshd.service
    复制代码

    然后再次测试您是否能够进行身份验证,现在应该会提示您输入SSH密钥密码和验证码:
    image-4.png
    一旦设置了验证,您就完成了保护服务器的第二阶段,通过在两个通道(您的计算机+您的电话)上拥有两个因素(SSH密钥+ MFA令牌),您使得攻击者很难通过SSH强行进入您的主机,并大大提高了您的主机的安全性。
    限速和防火墙
    现在,我们已经完成了一些身份验证强化,接下来是将身份验证尝试限制在我们的服务器上,这也可以通过多种方式完成,第一种可能是最直接的,并使用简单防火墙(UFW)。

    这是迄今为止讨论的所有设置中最简单的,因为它可以通过两个命令完成(如果您没有安装它):
    1. sudo apt install ufw

    2. ## ufw limit ssh various usage ##
    3. ufw limit ssh comment 'Rate limit for openssh server'

    4. ### if sshd is running on tcp port 2022 add ####
    5. ufw limit 2022/tcp comment 'SSH port rate limit'
    复制代码

    上述规则对于防范暴力登录攻击非常有用。当使用限制规则时,ufw通常会允许连接,但如果一个IP地址试图在三十秒内发起六个或更多连接,ufw将拒绝连接。ufw支持按规则记录日志。默认情况下,当数据包与规则匹配时,不会执行日志记录。

    指定log将记录所有与规则匹配的新连接,而log-all将记录所有与规则匹配的数据包。例如,要允许并记录所有新的ssh连接,请使用:
    1. ufw limit log ssh comment 'Rate limit for SSH'
    复制代码

    如果您想更进一步,使用UFW将允许您将服务锁定到特定的ip地址:
    1.    sudo ufw allow from 1.2.3.4 to any port 22
    复制代码

    这将只允许1.2.3.4 SSH到端口22,当您对主机进行端口扫描时,该端口将显示为关闭或已过滤。
    设置FAIL2BAN
    单就UFW而言,设置非常好,因为它在引擎盖下使用了IP表,但是如果进一步检测和响应,我们可以设置Fail2Ban。Fail2Ban本质上是主动寻找潜在的密码身份验证滥用迹象,以过滤掉IP地址,并定期更新系统防火墙,以在一定时间内暂停这些IP地址。

    要设置fail2ban,您只需安装并启用它:
    1. sudo apt install fail2ban
    2. sudo cp /etc/fail2ban/jail.{conf,local}
    3. sudo nano /etc/fail2ban/jail.local
    复制代码

    编辑以下几行来调整设置:
    1. bantime = 1d
    复制代码

    也可以通过赋予负值来永久禁止。

    另一个非常重要的变量是findtime。它定义了连续登录尝试之间允许的持续时间。如果多次登录尝试是在findtime定义的时间内进行的,则会在IP上设置禁令。
    1. findtime = 10m
    复制代码

    最后,还有maxretry。它定义了findtime中允许的失败登录尝试的确切次数。如果findtime内失败的授权尝试次数超过maxretry值,则IP将被禁止重新登录。默认值为5。
    1. maxretry = 5
    复制代码

    Fail2ban还允许您对自己选择的IP地址和IP范围授予豁免权。上面讨论的这些条件不会应用于这些IP,本质上是让您创建某种允许列表。

    要将一个ip添加到此允许列表中,请修改ignoreip行并键入IP地址以免除,理想情况下,您希望您的家庭IP在这里,或者您经常访问主机的机器,以避免您将自己锁在外面!
    1. ignoreip = 127.0.0.1/8 ::1 222.222.222.222 192.168.55.0/24
    复制代码

    设置好您想要的所有选项后,只需启动服务,然后检查状态:
    1. systemctl start fail2ban
    2. systemctl status fail2ban
    复制代码

    image-5.png
    掩盖你的设置
    现在启用了密钥、MFA和限速,我们可以通过安全性进一步保护我们的设置。人们最常见的改变是将SSH端口从端口22移开,以降低暴力攻击和自动扫描攻击,结合良好的防火墙,可以使端口扫描看不到主机(然而,我不会在这篇文章中讨论这个问题)。
    修改SSH端口
    修改SSH端口就像在/etc/SSH/SSH _ config:
    1. sudo nano /etc/ssh/sshd_config
    复制代码
    image-6.png
    只需取消对端口的注释,并将其更改为您想要的任何端口,然后保存文件并重新启动服务:

    全部保存后,您可以使用新端口ssh到您的服务器:
    1. ssh -p 65532 zephr@zsec.uk -v
    复制代码

    SINGLE包授权
    SPA是我以前从未听说过的东西,直到Tim问我是否在这篇文章中报道了它:
    SPA类似于端口碰撞技术,它本质上是一种通过在一组预先指定的关闭端口上生成连接尝试来外部打开防火墙上的端口的方法。这不是什么新鲜事,但这是另一种模糊你的设置的方法,以保护它免受窥探。

    端口碰撞技术是一种较早的第一代技术,它使用TCP和UDP数据包报头中的端口字段来传递信息。通常,这些协议用于封装应用层数据,然而端口碰撞技术通过使用端口号本身作为传输数据的字段,将信息编码成数据包序列发送到各个端口。

    端口碰撞技术场景的一个例子是端口碰撞技术服务器配置一个数据包过滤器来阻止对服务(如SSH)的所有访问,直到端口碰撞技术客户端发送了特定的端口碰撞技术序列。例如,服务器可能要求客户端按顺序向以下端口发送TCP SYN数据包:
    • 23400
    • 1001
    • 2003
    • 65501

    如果服务器监控这个knock序列,包过滤重新配置允许从发送它的IP地址SSH连接。通过利用包过滤提供的连接跟踪机制,在超时后由敲门服务器创建的初始规则被删除后,SSH会话可以保持建立。这通过模糊性增加了额外的安全性,这与SPA略有不同,SPA被认为是新的,它保留了端口碰撞技术的所有好处,但修复了旧技术带来的限制。
    为了设置这一点,我们将安装fwknop,它代表防火墙敲门操作符。要安装和设置fwknop,我们需要在各自的主机上安装客户端和服务器:
    1. Server side:
    2. sudo apt install fwknop-server

    3. Client Side:
    4. sudo apt install fwknop-client
    复制代码


    首先,我们需要设置端口以自动删除 SSH,我使用这个指南完整设置了 fwknop。所以下面的步骤就像从指南中复制的一样: 配置 UFW 以允许 UDP 端口 62201 作为默认值,这可以在配置文件中更改:
    1. ufw allow 62201/udp comment 'SPA Setup for Port Knocking'
    复制代码

    如下配置iptables:
    1. iptables -I INPUT 1 -i eth0 -p tcp --dport 22 -j DROP
    2.   iptables -I INPUT 1 -i eth0 -p tcp -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
    复制代码

    然后,在安装fwknop-client之后,我们将首先在客户端上设置密钥:
    使用 fwknop -K keys.txt 为您的 SPA 生成密钥和 HMAC_key
    1. fwknop -K keys.tx
    2. cat keys.txt

    3. OUT:
    4. KEY_BASE64: example
    5. HMAC_KEY_BASE64: example
    复制代码

    编辑~/.fwknoprc包括您的服务器和上面生成的密钥的详细信息:
    1. [bastion]
    2. SPA_SERVER          <Target IP>  
    3. ACCESS              tcp/22
    4. KEY_BASE64          <BASE64>
    5. HMAC_KEY_BASE64     <BASE64>
    6. USE_HMAC            Y
    复制代码

    接下来,我们需要将相同的密钥数据复制到服务器/etc/fwknop/access.conf上:
    1. #### fwknopd access.conf stanzas ###

    2. SOURCE              ANY
    3. KEY_BASE64: example
    4. HMAC_KEY_BASE64: example
    复制代码

    将所有数据复制到客户端和服务器后,通过运行以下命令检查服务器的状态:
    1. systemctl start fwknop-server
    2. systemctl status fwknop-server
    复制代码

    服务运行后,您应该能够从主机运行以下命令以打开端口:
    1. fwknop -n bastion -R --verbose
    复制代码

    一切都很顺利,看起来应该有点像下面的截图,初始nmap显示端口关闭,然后运行命令打开端口:
    image-11.png
    执行bastion命令:
    image-10.png
    命令后执行nmap扫描:
    image-12.png
    我不会假装理解它是如何工作的,但正如我们所看到的,神奇!打开端口并能够在以下位置进行ssh:
    image-13.png
    为了简化操作,我们还可以在.bashrc或.zshrc或您使用的任何shell中为命令添加别名,以便于记忆:
    1. alias fwknock="fwknop -n bastion -R --verbose"
    复制代码

    Tada! SPA所有的设置和我们的端口是隐藏的,如果你想进一步加强设置,你可以考虑改变SSH端口和端口的knocking端口。
    登录通知
    最后但并非最不重要的是,我们已经经历了强化设置的过程,但是如果我们没有适当的监控来告诉我们何时有人进行身份验证,那么强化设置有什么好处呢?进入登录通知的美丽,这是我前阵子在设置PoshC2和钴击的通知后设置的东西,SSH是合乎逻辑的下一步。

    我将解释如何在两个不同的平台上做到这一点,这在任何支持webhooks的平台上都是切实可行的,因为这是对您的配置文件和一些web请求的一些调整。
    TELEGRAM机器人
    Telegram的bot API非常适合做各种各样的事情,最简单的方法就是先构建你的bot,你可以通过向BotFather发送一条消息来实现:
    1. /newbot
    复制代码

    这将指示机器人创建一个新的机器人,它将提示您输入一个必须以机器人结尾的名称,一旦您为它提供了一个名称,它将为您创建一个新的机器人标识和一个应用编程接口令牌。
    image-14.png
    下一步是设置一个组,在其中添加您自己、您刚刚创建的bot和IDbot。

    IDBot将为您提供CHATID。您可以通过向channel/getgroupid发送消息来实现这一点。它将返回频道的组ID,只需在数字前加一个连字符,这就是CHATID:-123456789作为示例。抓取这个加上http API密钥,并将它们添加到以下脚本中。
    1. # Login Notifications
    2. CHATID=CHANGEME
    3. BOTKEY=CHANGEME

    4. # get hostname
    5. HOSTNM=$( hostname )

    6. # get external IP address
    7. IP=$( curl -s http://whatismyip.akamai.com/ )

    8. # find IP address of person last logged in
    9. LOGININFO=$( last -1 -i | head -n 1)

    10. # parse into nice format
    11. LOGININFO1=$( python3 -c "login='$LOGININFO'.split('   '); del login[1]; del login[1]; print(''.join([x.strip(' ') + '   \n' for x in login]));" )

    12. # send information to telegram notification bot
    13. curl -X POST -H 'Content-Type: application/json' -d "{"chat_id": "$CHATID", "text": "Log in to: $HOSTNM\n$IP\nfrom: $LOGININFO1", "disable_notification": false}" https://api.telegram.org/bot$BOTKEY/sendMessage --silent > /dev/null
    复制代码

    然后可以将它捆绑到bash脚本中并从您的概要文件中调用,或者直接写入概要文件:
    ZSH
    1. nano /etc/zsh/zprofile
    复制代码

    BASH
    1. nano /etc/profile
    复制代码

    保存后,每次通过SSH连接到主机并生成shell时,您将在设置的组中收到一个警报:
    image-15.png
    SLACK机器人
    在设置slack时,设置webhook的过程记录在slack的站点上。按照以下步骤设置webhook,然后您应该有一个如下所示的URL:
    1. https://hooks.slack.com/services/VALUE1/VALUE2
    复制代码

    在slack文档的帮助下,我编写了一个类似于上面bash脚本的python脚本,但是它没有发送到Telegram,而是发送到Slack。
    1. from slack_sdk.webhook import WebhookClient
    2. import os

    3. url = " https://hooks.slack.com/services/VALUE1/VALUE2"
    4. webhook = WebhookClient(url)
    5. HOSTNM = os.popen('hostname').read()
    6. IP = os.popen('curl -s http://whatismyip.akamai.com/').read()
    7. LOGININFO=os.popen('last -1 -i | head -n 1 | cut -d " " -f 1').read()

    8. response = webhook.send(text='Log in to: {}\n from {}\n by\n User: {} \n'.format(HOSTNM,IP,LOGININFO))
    9. assert response.status_code == 200
    10. assert response.body == "ok"
    复制代码

    根据slack文档,您需要安装松弛软件开发工具包:
    1. pip install slack_sdk
    复制代码

    你想怎么保存都行.py并从您的配置文件中引用它,类似于telegram脚本:
    1. python3 /etc/zsh/down.py
    复制代码


    image-19.png
    最后,当您向您的服务器进行身份验证时,您将会收到一个推送通知,通知到任何平台:
    image-17.png
    好了,一切准备就绪!

    快速回顾一下,我们已经成功设置:
    • 安全密钥
    • MFA
    • 防火墙
    • 掩盖你的设置
    • 登录通知



    来自群组: 追寻

    评分

    参与人数 2威望 +2 飘云币 +2 收起 理由
    zhczf + 1 + 1 PYG有你更精彩!
    howardlee + 1 + 1 赞一个,这个帖子很给力!

    查看全部评分

  • TA的每日心情
    擦汗
    昨天 09:10
  • 签到天数: 1913 天

    [LV.Master]伴坛终老

    发表于 2021-8-25 10:01:30 | 显示全部楼层
    这么好的贴子没人回复啊!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    昨天 18:58
  • 签到天数: 579 天

    [LV.9]以坛为家II

    发表于 2021-8-30 20:18:23 | 显示全部楼层
    太牛掰了。感谢分享。
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 登录 | 快速注册

    本版积分规则

    快速回复 返回顶部 返回列表