Linux服务器安全指南二——SSH篇

2023年 9月 28日 26.5k 0

原文:imthenachoman/How-To-Secure-A-Linux-Server: An evolving how-to guide for securing a Linux server. (github.com)

确定你的目标

在你确定目标之前,你首先需要建立你的威胁模型。怎么建立威胁模型呢,这里有一些你需要考虑的几个点:

  • 你为什么想要保护自己的服务器;
  • 你想要增强哪方面的安全;
  • 如何在安全和便利之间做妥协;
  • 下面哪些类型的安全威胁是你最想解决的:
    • 物理机访问对你的服务器算是一个威胁吗,比如某人偷摸着摸到你的服务器跟前。不过现在都是云主机,很少有这种情况;
    • 你是否会开启额外的端口以允许外界访问你的服务器,个人不推荐开启额外端口访问,能使用域名+反向代理就使用,一个是安全,另一个是访问速度快;
    • 个人计算机和服务器文件共享问题,服务器上的一个文件夹挂载到个人电脑上,传文件方便,但是中招可能性会大很多。
  • 你是不是安全备份处理,比如你不小心禁用了服务器密码,你是否有解决方案。我感觉无解这个问题,哈哈哈。
  • 选择Linux分支

    这一部分旨在教导你如何去选择Linux分支,现在Linux分支有点多,有 Debain系列,小红帽系列,Arch Linux等等,还有国产UOS,Deepin,TencentOS,AliOS,OpenCloudOS等等。

    下面可供你选择的原因:

  • 稳定可更新,也可自己操控更新,即便你不是运行最新版本的操作系统也OK。这里点名批评Windows10和Windows11强制更新,虽然不是服务器,但是也耽误事;
  • 保持安全补丁更新。即便你防护做的再好,敌人从内核或者操作系统攻入你也无计可施;
    3.你熟悉的操作系统,使用前建议你先熟悉熟悉;
  • 提供帮助的,或者说社区(生态)庞大的。即便它东西做的再好,如果出现问题你费劲也找不到也无计可施。
  • 安装Linux

    这个章节超出文章讨论范围,主要是每个Linux分支可能不太一样,如果你需要帮助,可以查看Linux分支相关文档或者各类博客等,大概安装步骤如下:

  • 下载操作系统ISO文件;
  • 烧录/拷贝/传输操作系统到介质中(CD或者USB中);
  • 从介质中启动服务器;
  • 跟随提示继续安转。
  • 安装后可以根据自己的需要自定义安装Linux,这样一来会对服务器拥有更高的控制能力,二来也不必要安装一些额外的功能。如果你需要安装软件,可以通过ssh连接到服务器中进行必要的安装。

    安装准备

    • 如果你依赖于额外的端口去访问外界,等系统安装完毕或者系统加固完毕需要禁用端口;
    • 如果服务器访问不需要什么硬件,建议你通过SSH协议去直接访问;
    • 永远保持系统更新,这是很关键的,不然等过阵子你可能拥有跟不上了,历史欠账太多,更新命令如下:sudo apt update &&sudo apt upgrade && sudo apt dist-upgrade
    • 配置好其他需要的设置项:
      • 配置网络
      • 配置挂载路径
      • 创建用户初始化账户
      • 安装核心软件,例如 treemanls
    • 系统安全故障邮件通知,可以用谷歌邮箱,163邮箱等等,配置到服务器上即可,但一般国内不太配置这个,太麻烦;
    • 推荐在开始之前阅读CIS Benchmarks。

    其他重要事项

    • 指南是以dabian系基础上写的,其他Linux发行分支可能用不了,如果你发现用不了的部分,请联系作者;
    • 文件路径和设置也可能略有不同,如果发现有不同点,可以查看相应Linux发行版文档;
    • 在完整参考指南前,可以通读一遍,有些示例可能跟你本地服务器上配置不太相同,或者顺序不太一样;
    • 不要盲目的复制粘贴,尤其在不了解这个脚本是干啥的之前,一些脚本可能破坏你的服务器。

    SSH服务器

    重要提醒★★★

    在你要改动SSH配置文件之前,建议你开着至少2个SSH终端,这样即使改坏了你也能把它改回来。
    感谢Sonnenbrand提供这个小技巧。

    SSH公钥/私钥

    为什么要用公钥/私钥

    连接服务器时,SSH公钥私钥远比密码安全,简单和快速。因为他不需要输入密码,不过也很容易造成密码遗忘,这就是手机要求72小时内必须输入一遍密码,要不然时间久了还真容易忘。

    运作原理和流程

    深层来讲,公钥/私钥通过验证密钥对是不是匹配来正常验证服务器通信的。

  • 公钥用于加密数据;
  • 私钥用于解密数据。
    对SSH服务器来说,公钥私钥对是由客户端创建的。你需要去确保密钥对的安全性,尤其是确保私钥的安全。即便公钥是所有人可见的,你也需要保证其安全,因为有些人可能用公钥来尝试连接你的服务器。
    当你连接服务器时,SSH协议会来搜寻你的公钥是不是匹配你的客户端,一般来说公钥位置放在~/.ssh/authorized_keys文件内。注意这个文件是在你需要登录账号的home文件夹内。当创建好公钥后,你需要把公钥添加到~/.ssh/authorized_keys内,一个简单的办法是用U盘拷贝,另一个办法是通过ssh-copy-id来传输公钥,现在都是云时代了,一般用第二种办法,毕竟运营商的物理机你是不可能看到的。
    创建好公钥后,公钥就放在你的~/.ssh/authorized_keys内了。在主机上,SSH使用公钥和私钥去验证你和建立SSH安全连接。建立后服务器会创建一个单独的线程用于与你的电脑通信。深刻来说,SSH协议通信是通过公钥来加密信息,进而发送到你的电脑上,如果你的电脑没有私钥钥,或者私钥不对,那这个信息就不能解密了,然后服务器就连接失败了。
    公钥私钥相对来说安全性更高,但如果你设置/etc/ssh/sshd_config内的配置PasswordAuthentication no,那你就不能用公钥私钥来登录服务了。
    在设置好公钥私钥后,你也应该设置一个二次登录密码,不过这样你登录过程就不是全自动的了,要麻烦一些。ssh-agent允许你在内存中拥有未加密的私钥一段时间,运行 ssh-add命令,他会提示你输入你的密码,这样你就不需要每次都输入密码了。
    根据linux-audit.com/ 上说的,我们下面会使用Ed25519方案;Ed25519方案提供比ECDSA方案和DSA方案更安全,性能也更好。
  • 目标

    在你的客户端(个人电脑)上创建你的私钥,在服务器上创建公钥。
    如果你之前没有创建聒公钥和私钥,你需要创建他,如果你创建过,就可以忽略这个步骤。

    参考文章/文献

    • www.ssh.com/ssh/public-…
    • help.ubuntu.com/community/S…
    • linux-audit.com/using-ed255…
    • www.digitalocean.com/community/t…
    • wiki.archlinux.org/index.php/S…
    • www.ssh.com/ssh/copy-id
    • man ssh-keygen
    • man ssh-copy-id
    • man ssh-add

    步骤

  • 在你的本地电脑上创建Ed25519密钥对
  • ssh-keygen -t ed25519
    
    Generating public/private ed25519 key pair.
    Enter file in which to save the key (/home/user/.ssh/id_ed25519):
    Created directory '/home/user/.ssh'.
    Enter passphrase (empty for no passphrase):
    Enter same passphrase again:
    Your identification has been saved in /home/user/.ssh/id_ed25519.
    Your public key has been saved in /home/user/.ssh/id_ed25519.pub.
    The key fingerprint is:
    SHA256:F44D4dr2zoHqgj0i2iVIHQ32uk/Lx4P+raayEAQjlcs user@client
    The key's randomart image is:
    +--[ED25519 256]--+
    |xxxx  x          |
    |o.o +. .         |
    | o o oo   .      |
    |. E oo . o .     |
    | o o. o S o      |
    |... .. o o       |
    |.+....+ o        |
    |+.=++o.B..       |
    |+..=**=o=.       |
    +----[SHA256]-----+
    

    如果你设置了passphrase(密码),当你登录服务器时,你需要每次都登录。
    2. 添加公钥到服务器中的~/.ssh/id_ed25519.pub文件内。如果你处在家庭网络,你可能不会遭遇MIM攻击,所以你可以试试用ssh-copy-id来传输你的公钥。

    ssh-copy-id user@server
    
    /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/user/.ssh/id_ed25519.pub"
    The authenticity of host 'host (192.168.1.96)' can't be established.
    ECDSA key fingerprint is SHA256:QaDQb/X0XyVlogh87sDXE7MR8YIK7ko4wS5hXjRySJE.
    Are you sure you want to continue connecting (yes/no)? yes
    /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
    /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
    user@host's password:
    
    Number of key(s) added: 1
    
    Now try logging into the machine, with:   "ssh 'user@host'"
    and check to make sure that only the key(s) you wanted were added.
    

    现在你可以接下来操作了。

    创建SSH允许登录组

    为什么创建

    创建SSH组能让你更快捷的控制服务器,通过以组的形式控制允许登录的账号,我们可以更快捷的添加或者删除SSH许可。

    运行原理

    下面我们将在/etc/ssh/sshd_config文件内添加允许SSH登录的账号组。

    目标

    创建UNIX 账号组来限制账号登录Linux服务器

    提示

    这是设置/etc/ssh/sshd_config安全性的先决条件。

    使用命令
    • man groupadd
    • man usermod
    操作步骤
  • 创建用户组
  • sudo groupadd sshusers
    
  • 添加账号到用户组中
  • sudo usermod -a -G sshusers user1
    sudo usermod -a -G sshusers user2
    sudo usermod -a -G sshusers ...
    

    通过/etc/ssh/sshd_config文件来确保安全

    重要性

    SSH是进入你服务器的门户,所以确保SSH安全尤其重要,尤其是访问外网。

    工作原理

    SSH服务器默认使用/etc/ssh/sshd_config配置文件,所以要想服务器安全一点我们可以在这里下一点功夫。

    目标

    配置SSH文件配置,首先确保你完成了SSH账号组配置。

    参考文章
    • Mozilla's OpenSSH guidelines for OpenSSH 6.7+ at infosec.mozilla.org/guidelines/…
    • linux-audit.com/audit-and-h…
    • www.ssh.com/ssh/sshd_co…
    • www.techbrown.com/harden-ssh-… (broken; try - web.archive.org/web/2020041…)
    • serverfault.com/questions/6…
    • man sshd_config
    操作步骤
  • 创建/etc/ssh/sshd_config备份,移除注释,提高文件可读性;
  • sudo cp --archive /etc/ssh/sshd_config /etc/ssh/sshd_config-COPY-$(date +"%Y%m%d%H%M%S")
    sudo sed -i -r -e '/^#|^$/ d' /etc/ssh/sshd_config
    
  • 编辑/etc/ssh/sshd_config文件,按照下面提示添加或者更改设置。
    注意:SSH协议重复设置会有问题,例如存在两个相同设置,一个是ChallengeResponseAuthentication no,另一个是ChallengeResponseAuthentication yes,SSH会保留第一个,而忽略第二个。如果你的/etc/ssh/sshd_config存在这种情况,为避免出现问题,你需要查找你的文件并删除重复设置项。
  • ########################################################################################################
    # start settings from https://infosec.mozilla.org/guidelines/openssh#modern-openssh-67 as of 2019-01-01
    ########################################################################################################
    
    # Supported HostKey algorithms by order of preference.
    HostKey /etc/ssh/ssh_host_ed25519_key
    HostKey /etc/ssh/ssh_host_rsa_key
    HostKey /etc/ssh/ssh_host_ecdsa_key
    
    KexAlgorithms curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256
    
    Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
    
    MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com
    
    # LogLevel VERBOSE logs user's key fingerprint on login. Needed to have a clear audit track of which key was using to log in.
    LogLevel VERBOSE
    
    # Use kernel sandbox mechanisms where possible in unprivileged processes
    # Systrace on OpenBSD, Seccomp on Linux, seatbelt on MacOSX/Darwin, rlimit elsewhere.
    # Note: This setting is deprecated in OpenSSH 7.5 (https://www.openssh.com/txt/release-7.5)
    # UsePrivilegeSeparation sandbox
    
    ########################################################################################################
    # end settings from https://infosec.mozilla.org/guidelines/openssh#modern-openssh-67 as of 2019-01-01
    ########################################################################################################
    
    # don't let users set environment variables
    PermitUserEnvironment no
    
    # Log sftp level file access (read/write/etc.) that would not be easily logged otherwise.
    Subsystem sftp  internal-sftp -f AUTHPRIV -l INFO
    
    # only use the newer, more secure protocol
    Protocol 2
    
    # disable X11 forwarding as X11 is very insecure
    # you really shouldn't be running X on a server anyway
    X11Forwarding no
    
    # disable port forwarding
    AllowTcpForwarding no
    AllowStreamLocalForwarding no
    GatewayPorts no
    PermitTunnel no
    
    # don't allow login if the account has an empty password
    PermitEmptyPasswords no
    
    # ignore .rhosts and .shosts
    IgnoreRhosts yes
    
    # verify hostname matches IP
    UseDNS yes
    
    Compression no
    TCPKeepAlive no
    AllowAgentForwarding no
    PermitRootLogin no
    
    # don't allow .rhosts or /etc/hosts.equiv
    HostbasedAuthentication no
    
  • 配置如下设置项

    设置项 合法数值 示例 描述 备注
    AllowGroups local UNIX group name AllowGroups sshusers group to allow SSH access to
    ClientAliveCountMax number ClientAliveCountMax 0 maximum number of client alive messages sent without response
    ClientAliveInterval number of seconds ClientAliveInterval 300 timeout in seconds before a response request
    ListenAddress space separated list of local addresses
    • ListenAddress 0.0.0.0
    • ListenAddress 192.168.1.100
    local addresses sshd should listen on See Issue #1 for important details.
    LoginGraceTime number of seconds LoginGraceTime 30 time in seconds before login times-out
    MaxAuthTries number MaxAuthTries 2 maximum allowed attempts to login
    MaxSessions number MaxSessions 2 maximum number of open sessions
    MaxStartups number MaxStartups 2 maximum number of login sessions
    PasswordAuthentication yes or no PasswordAuthentication no if login with a password is allowed
    Port any open/available port number Port 22 port that sshd should listen on
  • 确保没有重复项,下面是检查重复项的语法

  • awk 'NF && $1!~/^(#|HostKey)/{print $1}' /etc/ssh/sshd_config | sort | uniq -c | grep -v ' 1 '
    
  • 重启ssh。
  • sudo service sshd restart
    
  • 检查ssh是否生效。
  • sudo sshd -T
    
    port 22
    addressfamily any
    listenaddress [::]:22
    listenaddress 0.0.0.0:22
    usepam yes
    logingracetime 30
    x11displayoffset 10
    maxauthtries 2
    maxsessions 2
    clientaliveinterval 300
    clientalivecountmax 0
    streamlocalbindmask 0177
    permitrootlogin no
    ignorerhosts yes
    ignoreuserknownhosts no
    hostbasedauthentication no
    ...
    subsystem sftp internal-sftp -f AUTHPRIV -l INFO
    maxstartups 2:30:2
    permittunnel no
    ipqos lowdelay throughput
    rekeylimit 0 0
    permitopen any
    

    删除短Diffie-Hellman密钥

    为什么这么做

    根据Mozilla针对OpenSSH 6.7+的OpenSSH指南,“所有使用的Diffie-Hellman模块应至少为3072位长”。
    Diffie-Hellman算法针对SSH连接建立。

    目标

    移除少于3072比特长度的Diffie-Hellman密钥。

    参考文章
    • Mozilla's OpenSSH guidelines for OpenSSH 6.7+ at infosec.mozilla.org/guidelines/…
    • infosec.mozilla.org/guidelines/…
    • man moduli
    操作步骤
  • 创建 SSH moduli 文件备份:
  • sudo cp --archive /etc/ssh/moduli /etc/ssh/moduli-COPY-$(date +"%Y%m%d%H%M%S")
    
  • 移除短比特Moduli:
  • sudo awk '$5 >= 3071' /etc/ssh/moduli | sudo tee /etc/ssh/moduli.tmp
    sudo mv /etc/ssh/moduli.tmp /etc/ssh/moduli
    

    2FA/MFA认证

    虽然前面的措施很完善了,但黑客还是可以尝试登录你的服务器。Fail2ban 工具能监控谁登录你的服务器并干掉多次尝试登录的人,另外,添加两因素认证也很棒,国内用两因素认证的人不多,主要是做技术的和国外用的多,常见的两因素认证有OnePass,Google Auth和MicroSoft Auth等,国内的话我推荐使用微软的这款,因为能备份数据。
    使用两因素认证后,用户登录需要两方面的认证,一个是需要密码,另一个是由两因素认证器生成的6位数随机密码,随机密码会存在30秒,之后刷新。

    什么情况下不考虑

    如果你感觉这个是在麻烦,你可以不考虑,哈哈哈哈哈,原文是这么说的:

    Many folks might find the experience cumbersome or annoying. And, access to your system is dependent on the accompanying authenticator app that generates the code.

    工作原理

    在Linux中,PAM用于安全认证。PAM有四个部分,你可以试试读读en.wikipedia.org/wiki/Linux_…,第二部分讨论的就是认证。
    当你用终端登录Linux服务器时,你的登录请求会发送到PAM认证任务中,然后PAM会验证你的密码。你可以自定义使用规则。例如,你可以设置一组规则可以直接从终端登录服务器,设置另一组规则通过SSH协议登录服务器。
    本节将更改通过SSH登录时的身份验证规则,使其需要密码和6位代码。
    我们将使用谷歌libpam-google-authenticator PAM 模块去创建和验证TOTP验证码。你可以读取下面的文章去了解TOTP的工作原理。

    • fastmail.blog/2016/07/22/…
    • jemurai.com/2018/10/11/…
      然后我们需要做的是设置服务器SSH PAM,让用户登录的时候带着他们的Token,不然登录不了。PAM第一步会验证密码,第二步验证5位数Token,如果都对了,才会允许用户登录。
    目标

    设置SSH连接的两因素认证。在操作前,你需要确保你的两因素认证器好不好使。指南中使用google-authenticator-libpam。

    参考文章
    • github.com/google/goog…
    • en.wikipedia.org/wiki/Linux_…
    • en.wikipedia.org/wiki/Time-b…
    • fastmail.blog/2016/07/22/…
    • jemurai.com/2018/10/11/…
    操作步骤
  • 安装libpam-google-authenticator,下面是Debian系列的示例:
  • sudo apt install libpam-google-authenticator
    
  • 确保你登录的账户是你要设置认证的账号,运行google-authenticator
  • google-authenticator
    
    Do you want authentication tokens to be time-based (y/n) y
    https://www.google.com/chart?chs=200x200&chld=M|0&cht=qr&chl=otpauth://totp/user@host%3Fsecret%3DR4ZWX34FQKZROVX7AGLJ64684Y%26issuer%3Dhost
    
    ...
    
    Your new secret key is: R3NVX3FFQKZROVX7AGLJUGGESY
    Your verification code is 751419
    Your emergency scratch codes are:
      12345678
      90123456
      78901234
      56789012
      34567890
    
    Do you want me to update your "/home/user/.google_authenticator" file (y/n) y
    
    Do you want to disallow multiple uses of the same authentication
    token? This restricts you to one login about every 30s, but it increases
    your chances to notice or even prevent man-in-the-middle attacks (y/n) Do you want to disallow multiple uses of the same authentication
    token? This restricts you to one login about every 30s, but it increases
    your chances to notice or even prevent man-in-the-middle attacks (y/n) y
    
    By default, tokens are good for 30 seconds. In order to compensate for
    possible time-skew between the client and the server, we allow an extra
    token before and after the current time. If you experience problems with
    poor time synchronization, you can increase the window from its default
    size of +-1min (window size of 3) to about +-4min (window size of
    17 acceptable tokens).
    Do you want to do so? (y/n) y
    
    If the computer that you are logging into isn't hardened against brute-force
    login attempts, you can enable rate-limiting for the authentication module.
    By default, this limits attackers to no more than 3 login attempts every 30s.
    Do you want to enable rate-limiting (y/n) y
    

    注意这个不要用管理员运行。
    3. 创建PAM SSH配置备份。

    sudo cp --archive /etc/pam.d/sshd /etc/pam.d/sshd-COPY-$(date +"%Y%m%d%H%M%S")
    
  • 现在我们把SSH配置添加到/etc/pam.d/sshd:
  • auth       required     pam_google_authenticator.so nullok
    

    可以参考这里来看nullok是什么意思。here (github.com)
    一键命令:

        echo -e "\nauth       required     pam_google_authenticator.so nullok         # added by $(whoami) on $(date +"%Y-%m-%d @ %H:%M:%S")" | sudo tee -a /etc/pam.d/sshd
    
  • 添加如下配置到/etc/ssh/sshd_config:
  • ChallengeResponseAuthentication yes
    

    一键命令

    sudo sed -i -r -e "s/^(challengeresponseauthentication .*)$/# \1         # commented by $(whoami) on $(date +"%Y-%m-%d @ %H:%M:%S")/I" /etc/ssh/sshd_config
    echo -e "\nChallengeResponseAuthentication yes         # added by $(whoami) on $(date +"%Y-%m-%d @ %H:%M:%S")" | sudo tee -a /etc/ssh/sshd_config
    
  • 重启SSH服务器
  • sudo service sshd restart
    

    相关文章

    服务器端口转发,带你了解服务器端口转发
    服务器开放端口,服务器开放端口的步骤
    产品推荐:7月受欢迎AI容器镜像来了,有Qwen系列大模型镜像
    如何使用 WinGet 下载 Microsoft Store 应用
    百度搜索:蓝易云 – 熟悉ubuntu apt-get命令详解
    百度搜索:蓝易云 – 域名解析成功但ping不通解决方案

    发布评论