VPS安全加固

  • VPS日常一些安全措施.

  • 更新

    1
    2
    3
    4
    5
    6
    7
    8
    9
    2017.04.08  VPS日常一些安全措施
    2017.08.22 更新安全措施,添加debian。
    2017.10.30 修正错误,排版.
    2019.01.11 修正错误,增加ssh-key内容,增加Fail2Ban csf配置.
    2019.06.15 修改错误,修正排版,增加ssh登录故障排查,更新ssh-key.
    2019.12.30 修正一些排版,添加 6to4 tunnel 与 防火墙冲突解决.
    2020.03.12 修正排版,增加 ssh 无法登录修正.
    2020.07.05 增加对应 shell 脚本
    2021.06.10 修正一些错误
  • 资料来源:

    https://www.freebsd.org/cgi/man.cgi?query=ssh_config
    https://linux.cn/article-9299-1.html
    等.

导语

  • 更新常用安全措施,至少保证,不会被轻易的成为肉鸡.
  • 系统环境Debian 7
  • CentOS,暂时无法验证命令,没有相关的主机,谨慎直接使用命令.

新建普通用户

我们首次的到的基本都是 root 用户,root 管理服务器固然方便,但是从安全角度看日常最好使用普通用户而非 root.

添加普通用户,添加 sudo 权限

1
2
adduser username
usermod -G sudo username

SSH

  • 方案
    • 更改SSH默认的22端口,建议为任意高位端口.
    • 关闭SSH密码,改为密钥登陆,更改登陆端口.安全性最好,需要谨慎保管私钥.
    • 密钥登陆配置稍繁琐,也可以使用强SSH密码.
    • 使用安全工具,封掉扫描爆破SSH端口的ip,这里是(fail2ban).

ssh故障排查

  • 在新开vps后,有时会遇到无法连接故障,常见排查思路:
    • 确认服务器在线?
      • 常见的是ping一下服务器ip,确认可以连通.
      • 其次通过网页版的vnc进入服务器,确保sshd已启用.
    • 本地网络屏蔽?
      • 因为各种网络环境过于复杂,有可能是本地网络防火墙屏蔽了ssh登录,或者屏蔽了初始的22端口.这样只能通过vnc换端口或者通过跳板机连接.
      • 网络延迟太大,经常性tcp被掐,只能寻找跳板机连接.
    • 本地网络正常,服务器在线,就是无法连接,跳板机也无法连接.
      • 考虑到全网的ssh爆破,有可能是vps默认的ssh连接数量过小,导致爆破的连接堵死了正常连接.
      • 首先考虑通过 vnc 修改 ssh 端口(一般解决),其次将 ssh 默认连接数量调整到较大级别.
      • 临时改 ssh 端口(改到999为例)
        • /usr/sbin/sshd -p 999
      • 修改 ssh 连接数量
        • vi /etc/ssh/sshd_config
        • 找到 MaxStartups 默认设置是 10:30:60 ,表示从第 10 个 ssh 链接开始,有 30% 的概率拒绝新链接,直到 60 个连接为止,完全拒绝新连接.尝试改大一点…
      • 如果提示是 Too many authentication failures for root,需要将验证次数加大一些,修改 /etc/ssh/sshd_configMaxAuthTries 到 20 或更大.

ssh修改默认端口

  • CentOS 命令 如下,以下是将 SSH 端口改为 999 端口

    1
    sed -i 's/#Port 22/Port 999/g' /etc/ssh/sshd_config
  • debian需要打开/etc/ssh/sshd_config 文件,修改其中的port后面的数字

    1
    nano /etc/ssh/sshd_config

    修改其中的port后面的数字,为你要ssh登陆的端口,cltrl + x保存,回车退出。

  • 重启 reboot

ssh-key登陆

  • ssh-key 使用过git应该不陌生,基本是生成一对密钥,将公钥添加到服务器,私钥本地妥善保管.在那里生成都一样,这里选择本地生成,上传到服务器.

  • 生成密钥对

    • 使用ssh-keygen

      1
      2
      # ssh-keygen -b 4096 -t rsa
      ssh-keygen -t ed25519
    • 这里选择rsa生成,(6.15)rsa则加密解密稍慢,生成时间长,且安全性没有ed25519高(细节不表了),这里改为ed25519.
      字节数选择 4096(安全).
      注: 密钥的字节数,仅影响生成密钥的速度,与ssh登陆认真无关.

    • 要求输入密钥的保存路径+名称.默认是/.ssh/id_rsa

    • 输入私钥的密码,留空或者输入自定义密码.回车,回车.

    • 之后在 ./ssh/文件夹下就生成了一对密钥.需要将 .pub上传到服务器.

  • 上传到服务器,有两种方式.

    • ssh-copy-id 命令,直接上传(推荐).

      1
      ssh-copy-id -i id_rsa.pub -p 999  [email protected]

      -i: 指定要上传的公钥.
      -p: ssh端口,指定修改后的ssh端口.

      • 之后要求输入服务器的密码,回车,即完成.
    • 手动上传,写入 authorized_keys 文件.

      • 上传公钥到服务器,这里是scp命令

        1
        scp id_rsa.pub [email protected]:/root/.ssh/

        scp上传 id_rsa.pub 到root用户的.ssh文件夹(没有需要创建)

      • 将公钥内容写入 authorized_keys .

        • 没有则新建,nano,vim,cat都可.

          1
          cat id_rsa.pub >> authorized_keys
      • 两种结果相同,都是将生成的公钥写入了authorized_keys.

  • 修改权限,允许ssh密钥登陆

    • 修改权限

      1
      2
      chmod 700 ~/.ssh
      chmod 600 ~/.ssh/authorized_keys
    • 允许ssh密钥登陆

      1
      nano /etc/ssh/sshd_config

      确保,以下字段内容

      1
      2
      3
      RSAAuthentication yes
      PubkeyAuthentication yes
      AuthorizedKeysFile .ssh/authorized_keys

      (6.15)注: RSAAuthentication 为 ssh 1代,在新的 linux 系统版本中可能不存在,保证另外两个开启即可.

    • 重启ssh服务,或者直接 reboot

      1
      /etc/init.d/ssh restart
  • 现在应该可以使用ssh-key登陆了.验证:

    • 命令

      1
      2
      #   -i: 指定私钥位置,-p: ssh端口 .
      ssh -i ./.ssh/id_rsa -p 999 [email protected]
    • 很多本地终端都还装上了git,为方便管理私钥和登陆,还需要使用ssh.config

SSH Config

  • 通过 ./.ssh/config 文件可以非常方便的管理私钥和登陆.假定本地终端存在git使用的id_rsa 和 vps使用的 id_rsa.vps 两个私钥.

  • 新建./.ssh/config文件,示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Host vps                         # 关键词
    HostName 999.999.999.999 # 主机地址
    User root # 用户名
    IdentityFile ~/.ssh/id_rsa.vps # 认证文件
    Port 999 # 指定端口

    Host coding # 关键词
    HostName git.coding.net # 主机地址
    IdentityFile ~/.ssh/id_rsa
    User git
  • 具体配置项
    每个 Host 都是一个服务器

    • HostName: 服务器地址,可以是域名,也可以是ip地址.
    • User: 用户名
    • IdentityFile: 私钥的路径
    • Port: ssh端口
  • 以示例文件为例,但我们连接vps时,可以直接使用配置的Host关键字 ssh vps 直接链接.而 git 组,保证了git的正常使用.

  • 因为Q的存在,我们不可避免的需要给ssh设置代理,以避免莫名其妙的rst.在config文件中,异常容易.主要是 ProxyCommand 字段.

    • 有两种代理方式,ssh 或者 nc.具体区别是 ssh 是代理也是ssh over ssh 链接服务器. nc则是 ssh over socks4/5/https 链接服务器,详细说明参考 > https://dslztx.github.io/blog/2017/05/19/ssh命令之ProxyCommand选项/

    • 我们更多的本地是 socks5/https,这里是 使用 nc.格式 nc -X 5 -x B:port

      • -X 指代 socks5
    • 示例

      1
      2
      3
      4
      5
      6
      Host vps                         # 关键词
      HostName 999.999.999.999 # 主机地址
      User root # 用户名
      IdentityFile ~/.ssh/id_rsa.vps # 认证文件
      Port 999 # 指定端口
      ProxyCommand nc -x 127.0.0.1:9900 %h %p #代理,本地9900端口
    • 再次 ssh vps 键入 who ,就能看到代理的ip地址了.

  • 更多的说明参考

    https://www.freebsd.org/cgi/man.cgi?query=ssh_config

禁止ssh密码登陆

  • 比较简单,只概述过程.

  • 警告 ,除非确认ssh-key可以正常登陆,否则关闭密码登陆后,只能重装系统(6.15)或者网页 vnc 再开启.

  • 编辑 /etc/ssh/sshd_config 文件.PasswordAuthentication yes 改为PasswordAuthentication no.

  • 重启 ssh 服务,或者 reboot.

fail2ban

  • 此处参考了

    https://linux.cn/article-9299-1.html

  • fail2ban 是 Linux 上的一个著名的入侵保护的开源框架,Python 编写,监控多个系统的日志文件,并根据检测到的任何可疑的行为自动触发不同的防御动作。封禁带恶意标志的IP,如爆破ssh,漏洞扫描等.

  • Fail2Ban 能够降低错误认证尝试的速度,但是它不能消除弱认证带来的风险。 这只是服务器防止暴力攻击的安全手段之一

  • 不只是ssh,理论上只要有对应监控日志, Fail2Ban 就能适配.

普通使用

  • 通常情况下我们只需要保持默认配置即可.

  • 安装fail2ban
    CentOS 需要提前 设置 EPEL 仓库
    以 root 用户登陆,非 root 用户需要 命令前 增加 sudo

    • 安装命令

      1
      2
      3
      4
      //CentOS
      yum install fail2ban
      //Debian / ubuntu
      apt-get install fail2ban
  • 其他命令

    • 重启

      1
      service fail2ban restart
    • 验证状态

      1
      fail2ban-client ping

      返回

      1
      Server replied: pong
  • 设置开机自启动(debian不用前面验证完成,已加入开机启动)

    1
    2
    3
    4
    // CentOS/RHEL 6
    chkconfig fail2ban on
    // CentOS/RHEL 7
    systemctl enable fail2ban

详细设置

  • Fail2Ban 的配置文件在 /etc/fail2ban/ 下,主配置文件是 jail.conf ,但每次配置文件更新都会重新覆盖jail.conf,初次配置需要拷贝 jail.confjail.local ,再更改.这样每次Fail2Ban都会先从 jail.local 读取配置再更新到jail.conf.

  • 警告: Fail2Ban 基于日志文件进行判断,启用对于模块后,但没有日志文件,会报错.

  • 命令

    1
    cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
  • 配置

    • 整个fail2ban的配置都是按照组的形式,如示例.

    • 示例

      1
      2
      3
      4
      5
      6
      [DEFAULT]
      ignoreip = 127.0.0.1/8 192.168.1.100/24
      bantime = 600
      findtime = 600
      maxretry = 3
      destemail = [email protected]

      这一组是最开始的默认配置.
      ignoreip : 忽略的ip地址.一般是本地或者白名单ip.
      bantime : 被禁ip地址默认时间.
      在 findtime 时间内 maxretry 次尝试失败,进入黑名单.
      destemail; 通知的邮件地址,前提是主机要架好邮件服务.

    • 上文提及 fail2ban 是个根据日志文件限制ip的框架,不止ssh,常用的 mysql nginx 等都可以进行类似的配置,且 fail2ban 中都默认内置了相关的规制.(但没有caddy).下文对于内置规则的直接在配置文件中启用即可,没有内置规则的可以字形添加规则并在配置文件中启用(示例是caddy).

  • 配置

    • 命令

      1
      nano /etc/fail2ban/jail.local
    • 通用配置,不再更改了,默认即够用.

    • 启用 SSH 配置,内置规则,只要添加enabled = true字段即可.字段也非常容易明白.

      1
      2
      3
      4
      5
      6
      7
      #
      # SSH servers
      #
      [sshd]
      enabled = true
      port = ssh
      logpath = %(sshd_log)s
    • 添加caddy配置.需要添加新的过滤规则,

      • 所有的过滤规则都在 /etc/fail2ban/filter.d 文件夹下,新建 caddy-req-limit.conf 文件,并写入以下内容.

        1
        2
        3
        [Definition]
        failregex = ^<HOST> -.*"(GET|POST).*
        ignoreregex =
      • 在 /etc/fail2ban/jail.local 中添加,规则组.

        1
        2
        3
        4
        5
        6
        7
        8
        [caddy-req-limit]
        enabled = true
        filter = caddy-req-limit
        action = iptables-multiport[name=ReqLimit, port="http,https", protocol=tcp]
        logpath = /home/nena/logs/caddy/access.log
        findtime = 300
        bantime = 7200
        maxretry = 800
  • 重启服务 service fail2ban restart

CSF 防火墙

  • fail2ban 大多数情况下足够防护了,但面对 ddos 还是需要防火墙来扛.
  • CFS是linux下开源的免费防火墙,基于iptables工作,可以有效的仿佛暴力破解和小型ddos.支持web管理插件(但是这里未使用)
  • 参考

    https://bbs.aliyun.com/simple/t304938.html
    https://www.logcg.com/archives/2873.html
    https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-config-server-firewall-csf-on-ubuntu

安装

  • 下载并安装

    1
    2
    3
    4
    5
    rm -fv csf.tgz
    wget http://download.configserver.com/csf.tgz
    tar -xzf csf.tgz
    cd csf
    sh install.sh
  • 验证命令 perl /usr/local/csf/bin/csftest.pl,输出以下内容时,cfs安装成功.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    Testing ip_tables/iptable_filter...OK
    Testing ipt_LOG...OK
    Testing ipt_multiport/xt_multiport...OK
    Testing ipt_REJECT...OK
    Testing ipt_state/xt_state...OK
    Testing ipt_limit/xt_limit...OK
    Testing ipt_recent...OK
    Testing xt_connlimit...OK
    Testing ipt_owner/xt_owner...OK
    Testing iptable_nat/ipt_REDIRECT...OK
    Testing iptable_nat/ipt_DNAT...OK

配置

  • cfs防火墙,默认工作在测试模式,需要配置相关规则来发挥作用.另外配置错误也无妨,测试模式 默认5分钟清除一次规则.

  • 编辑配置文件 vi /etc/csf/csf.conf

    • 放行端口设置,放行常见端口,

      1
      2
      3
      4
      5
      6
      7
      8
      9
      # Allow incoming TCP ports
      TCP_IN = "80,443,999"
      # Allow outgoing TCP ports
      TCP_OUT = "80,443,999,1:1000"
      # Allow incoming UDP ports
      UDP_IN = "20,21,53,3000:5000"
      # Allow outgoing UDP ports
      # To allow outgoing traceroute add 33434:33523 to this list
      UDP_OUT = "20,21,53,3000:5000"
      • 一定要添加修改后的ssh端口,
      • 对于需要开放的端口段,可以形如 3000:5000 来配置. tcp out 严格一点只留 80 443 和 ssh .为避免莫名故障 这里是 开了 1:1000.
      • 一般是删去不使用的端口.
      • 服务器支持IPV6,还需要配置IPV6端的端口配置,配置规则相同.
    • 允许ping命令.

      1
      2
      # Allow incoming PING 是否允许别人ping你的服务器,默认为1 允许 .0为不允许。
      ICMP_IN = "1"

      一般 ping 命令用来快速检查服务器通断,此项可选,禁用 ping 可以防御 icmp ddos, 禁止 ping 后,可以使用相应的 tcpping 端口 代替,此处就不加累赘了.

    • 防御规则

      • 找到 PORTFLOOD 字段.对应防御规则

        1
        PORTFLOOD = "22;tcp;5;300,80;tcp;20;5,443;tcp;20;5"
      • 22端口,一个ip在300秒内发起超过5次tcp连接,即封禁.

      • 80/443端口,1个ip在20秒内发起超过5次tcp连接,即封禁.

      • 这里一般不需要改动,但像是测试服务器,要将 限制次数/限制时间范围 相应扩大.这里我改成了 "999;tcp;10;300,80;tcp;20;30,443;tcp;20;30".

    • 还有其他高级的配置,包括邮件通知等等,因为没用用到,不再赘述.

  • 重启并测试

    • csf -r 重启防火墙,测试ssh等端口的正常连接,没有问题.
    • 关闭测试模式 /etc/csf/csf.conf 第一行 TESTING = "1" 改为 TESTING = "1"csf -r重启防火墙.

与IPV6 tunnel 冲突

  • 有时会临时用到 Tunnel broker 的 ipv6 Tunnel .一些情况下发现与 我 csf 的 默认配置有冲突. csf 开启则 ipv6 地址无法 ping 通.无大碍,
  • 今天查阅资料无意发现 6to4 需要用到 tcp 的 41 端口.修改一下 csf 的配置即可.

一键脚本

一件简单的事情,拖了 N 久…

debian_init.sh 仅支持 debian(ubuntu 应该也行)

  • 配置 ssh-key
  • 安装 Fail2Ban 并打开 ssh 防御
  • 安装 csf ,但并未配置.

禁用Linux多余端口

  • (6.15)写在前:

    • 设定好 csf 防火墙后,基本不需要再对 iptables 进行设置.
    • debian/ubuntu 系统中可以选择更为友好的 ufw 进行配置,但 ufw 会与 csf 冲突,取一即可.相关资料 UFW
  • 关闭多余端口是永远正确的选择!只留下常用端口 和 SSH端口

  • 配置 iptables 警告 iptables 配置不是一般的复杂,谨慎操作

  • 清空默认规则

    1
    iptables -F
  • 允许22端口,给暴力破解留点空间

    1
    2
    iptables -A INPUT -p tcp --dport 22 -j ACCEPT
    iptables -A OUTPUT -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT
  • 允许53端口 udp ,一般用做DNS服务器,如果你不需要则忽略此条

    1
    2
    iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
    iptables -A INPUT -p udp --sport 53 -j ACCEPT
  • 允许本机访问本机

    1
    2
    iptables -A INPUT -s 127.0.0.1 -d 127.0.0.1 -j ACCEPT
    iptables -A OUTPUT -s 127.0.0.1 -d 127.0.0.1 -j ACCEPT
  • 允许真正 SSH 端口

    1
    2
    iptables -A INPUT -p tcp -s 0/0 --dport 999 -j ACCEPT
    iptables -A OUTPUT -p tcp --sport 999 -m state --state ESTABLISHED -j ACCEPT
  • 允许 80 443 端口,http 和 https

    1
    2
    3
    4
    iptables -A INPUT -p tcp -s 0/0 --dport 80 -j ACCEPT
    iptables -A OUTPUT -p tcp --sport 80 -m state --state ESTABLISHED -j ACCEPT
    iptables -A INPUT -p tcp -s 0/0 --dport 443 -j ACCEPT
    iptables -A OUTPUT -p tcp --sport 443 -m state --state ESTABLISHED -j ACCEPT
  • 允许 其他需要端口 以888 xxx 为例 你有几个端口,就添加几个

    1
    2
    3
    4
    5
    iptables -A INPUT -p tcp -s 0/0 --dport 888 -j ACCEPT
    iptables -A OUTPUT -p tcp --sport 888 -m state --state ESTABLISHED -j ACCEPT

    iptables -A INPUT -p tcp -s 0/0 --dport xxx -j ACCEPT
    iptables -A OUTPUT -p tcp --sport xxx -m state --state ESTABLISHED -j ACCEPT
  • CentOS 保存配置

    1
    iptables-save > /etc/sysconfig/iptables

    重载 iptables

    1
    iptables -L
  • debian 7 保存配置

    1
    2
    iptables-save > /etc/iptables-rules
    ip6tables-save > /etc/ip6tables-rules

    随后修改/etc/network/interfaces文件,最后加入

    1
    2
    pre-up iptables-restore < /etc/iptables-rules
    pre-up ip6tables-restore < /etc/ip6tables-rules

    重启执行iptables -L,看到配置已生效。