本文内容的合理性正进一步评估中,请谨慎观看。
日志
- 2023-04-13:增加更多ssh使用技巧的提醒,即我的另一篇文章《Linux基础 实用Linux命令一览表》
- 2023-04-08:增加关于root登陆的建议,即密钥对登录的同时禁密码登陆。详见《Linux基础 基于密钥对的SSH远程登陆》。这样创建非root用户则不是必需的。
- 2023-04-05:新增Fail2ban防扫描和暴力破解的教程。
前言
在Linux基础 装饰你的Shell中,我们简单地复习了一下Vim
的用法,还接触了一些比较酷的Linux软件,比如ohmyzsh
和htop
。
虽然这些功能看似很强大,但你还不是真正的强大。因为在某种程度上,你的VPS还暴露在一个危险的互联网环境中,而你对此可能还没有太多的认识。所以,本回我将讨论个人VPS安全的相关问题。与个人对应的自然是企业级的安全了,不过那在我的能力范畴之外了。
大家可能偶有耳闻网络安全相关的新闻。比如,facebook的帐号信息被泄露啦,twitter上的名流被人冒名顶替啦。还有以前我读书那会的爆炸性新闻——美国“棱镜计划”和斯诺登。这些好像离我们十分遥远。说近的,平时互联网中很多自动化的攻击,对付它们往往也需要耗费大量的精力。
在日常生活中,会定期改改密码的人估计都是凤毛麟角。平时大家很少过分地考虑网络安全,好像一直也没啥事。这是为什么呢?对于这个问题,我也没有明确答案。不过,我有几个推测,大家可以参详一下:
- 私人信息基本上已经是被窃取了。这点我就不想多说了。我还记得以前有骚扰电话可以准确地说出我的电话、名字、身份证号和住址。我也不知道这些信息是怎么被泄露出去的,可能在发生在很久以前,具体原因也不可考了。
- 你的密码还是相对安全的。
- 我们平时使用的服务,比如银行、淘宝、微信之类的,账户和密码的安全由服务商保证。它们基于
https
和ssl
协议,在数学原理和现代密码学原理的buff加持下使得直接破解是十分困难。我们平时说的密码泄露,多半是自己在不安全的地方(比如http开头的网站)输入了自己的帐号信息,又或者你使用了弱密码
被别人暴力破解了。所以“定期更换复杂的密码”是一种比较合理的建议(当然,我认为bitwarden才是最佳实践)。 - 随着移动智能设备的流行,二次验证也变得十分常见。比如你输入正确的帐户信息后,可能还要手机再确认一下,这样的帐户基本上很难被窃取。如果攻击者同时获得了你的手机和你的帐户信息,这基本上就意味着你可能遭遇了绑架之类的人身攻击了,这时候人身安全是优先考虑的问题了。
所以呀,在日常生活中,其实是服务提供商帮你考虑了安全问题。可是,如果你玩VPS的话,你就变成VPS的安全负责人了。这时,你就需要了解一些基本的网络安全的知识了。试想你通过http协议传输密码,那么你的信息将以明文的方式在互联网中传播。这根本没有任何安全性可言。
关于个人VPS的安全,如果以后有更多观点再补充。网络安全是一个相对的概念,你要做到的不是绝对安全,而是比大多数人安全。这样攻击者就不会去啃你这个硬骨头,而去找一些软柿子(那些没有安全防护的VPS)捏了(这么说好像有点腹黑,哈哈)。不过也不用太担心安全问题。毕竟你的VPS才开通没久,也没有布署多少网络服务,攻击者暂时还没发现你。况且,正规的云服务商本身也有一些安全措施,攻击者要突破他们的防线也绝非易事。
总之,在进一步学习Linux之前,我建议大家对自己的VPS做一些安全防护。这里会介绍一些通用的、简单的但却十分有效的安全措施。
测试环境
uname -a # Linux VM-12-8-ubuntu 5.4.0-42-generic #46-Ubuntu SMP Fri Jul 10 00:24:02 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
不使用ubuntu系统的小伙伴可以参考一下,但不保证一定有效。
安全措施
你应该可以正常地顺着下面的代码一步步无障碍运行。
更新软件
旧版本的软件可能会含有某些漏洞,从而成为攻击者发起攻击的基础。这个怎么说呢,其实作为个人用户没有太多可以做的。请保持软件的最新状态吧!我使用OpenMediaVault
这个NAS系统时,安全相关的更新会强制自动安装的。
下面这个命令你也学过了:
sudo apt-get update && sudo apt-get upgrade
使用非root用户
更加建议使用密钥对来连接VPS并禁密码登陆。详见《Linux基础 基于密钥对的SSH远程登陆》。尽管这一步已经不是必须的,但建议你走走流程,熟悉一下Linux系统的用户管理。
创建非root用户
首先,创建一个新用户组:
# 创建新用户组
sudo groupadd -g 344 test
344
叫做gid
,我是随便取的。你只要取一个不为0的整数应该都可以,因为0是root用户组专用的gid。另外,1000
、100
也是很常见的内置用户组。如果你打算用这些用户组,那你可以不需要运行此命令。
这时,有童鞋可能会问:为什么用户(组)会有id
和name
这两个属性呢?这个问题以后再讨论。
接着,我们为test
用户组创建一个用户,名字叫做test_user
。
# 创建一个新用户
sudo useradd \
-m -d /home/test_user `#自动创建用户目录`\
-s /bin/bash `#设置默认shell`\
-g test `#主组`\
-G sudo `#副组`\
test_user
这个命令有点长,而且结构有点奇怪,哈哈 🙂
这其实是一种shell命令的可视化写法,通过\
号将一行中的多个元素分至不同的行。在shell中,这会被认为是一条命令。
这样拆分写的好处是,可以比较清晰地看到代码的功能结构。你以后运行或记录很长的shell命令时,也可以使用这个技巧。在markdown的代码框中,可以用TAB
链来迅速生成前方空格,或者用Shift+TAB
消除前方空格。以后有机会,你可以自己试试看。它和下面的写法是等价的:
sudo useradd -m -d /home/test_user -s /bin/bash -g test -G sudo test_user
下面我们将这个用户(组)删除。
# 删除用户
sudo userdel test_user
# 删除用户组
sudo groupdel test
注意,要将所有的用户删除后才可以删除用户组。
然后,根据类似的方法创建自己专属的用户和用户组吧!我这里就用test_user:test
来展示了。
下面,我给这个用户设置一个密码:
# 设置密码
sudo passwd test_user # 假设我输入了testtest
要输入两次密码并完全一样才会生效:
New password:
Retype new password:
passwd: password updated successfully
这个密码,在我们调用sudo
的权限会用到。
那么,要怎么切换到test_user
用户呢?可以这样:
su test_user # su <用户名>
如果你目前的用户级别不比test_user
高,它会要求你输入密码。这个密码就是testtest
。
如果你是root
,直接就切换过去了。应该可以理解这种层次的关系以及它的合理性吧?
在切换的一瞬间,你会发现漂亮的ohmyzsh
不见了。这是因为我们用了默认的/bin/bash
的缘故。那么怎么搞回来呢?国内小伙伴只要(实际使用时test_user
要换成你自己的非root用户名):
# 国内
ZSH=/home/test_user/ohmyzsh sh -c "$(wget -O- https://gitee.com/pocmon/ohmyzsh/raw/master/tools/install.sh)"
国外小伙伴只要:
# 国外
ZSH=/home/test_user/ohmyzsh sh -c "$(wget -O- https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
按提示操作。看,又回来了。舒服啊!主题自己改,我不多说。不懂的回去《Linux基础 装饰你的Shell》复习。当然,你也可以将oh-my-zsh安装在一个任何用户都可以访问的目录,然后在~/.zshrc
里指定$ZSH
路径。你以后熟悉Linux的时候,可以尝试一下。毕竟我是比较懒的,就不折腾了。
言归正传。我们可以观察一下主机都有哪些用户:
sudo less /etc/passwd
自己看一下就好了,最下面应该是新的用户。按q
可以终止less命令的使用。
观察home目录
我们进入一下新用户的home目录:
cd ~
看看目录的内容:
ls -hl
输出total 0
,表示什么都没有。
这时,观察一下home目录的绝对路径:
pwd
输出/home/test_user
。
好吧,在Linux里创建新用户就是这么简单?对呀,我也不知道为什么这么简单呀:satisfied:
这里就是新家了,以后基本上就是在这里部署应用啦!
探索sudo
这个时候,我们试一下与root
的交互。比如:
cd /root
输出bash: cd: /root: Permission denied
。因为我们是普通用户嘛,没有办法进入root
的目录。在大多数情况下,你甚至没有办法进入另外一个普通用户的home
目录,除非你的权限比它高级。所以如果你想保护一些东西,可以用root
权限保护它。
我们再试试能不能使用sudo
:
sudo apt-get update
输入密码后就可以正常地运行了。因为创建用户的时候,sudo
是test_user
的副组。是不是很帅呐:relaxed:
这时,我们再输入这个命令,观察一下我们的用户:
id
输出如下:
uid=1002(test_user) gid=344(test) groups=344(test),27(sudo)
uid
是用户的id,gid
是用户组的id。这里看到test_user
属于test
和sudo
两个用户组。如果test_user
不属于sudo
用户组,它将不可以使用sudo
!
至于uid
和gid
的具体用途,以后玩Docker的时候你会有所体会的。这里按下不表。
最后,我个人认为你可以看一下/etc/sudoers
文件:
ls -hl /etc/sudoers
输出是:
-r--r----- 1 root root 825 Apr 17 14:01 /etc/sudoers
看!在默认状态下,这个文件就算是root
用户也只可以查看而不可以改动。说明它真的很重要喔!
实际上,它控制了用户对于root
权限调用的程度。我们可以尝试来改动一下它。
首先,让它变成root可修改的文件
sudo chmod +600 /etc/sudoers # 600是啥我以后再介绍
然后用Vim编辑它:
sudo vim /etc/sudoers
它的内容应该会类似于:
#
# This file MUST be edited with the 'visudo' command as root.
#
# Please consider adding local content in /etc/sudoers.d/ instead of
# directly modifying this file.
#
# See the man page for details on how to write a sudoers file.
# timestamp_timeout=30即有效期改成30分钟。
Defaults env_reset, timestamp_timeout=30
Defaults mail_badpass
Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin"
# User privilege specification
root ALL=(ALL:ALL) ALL
...
如刚刚运行sudo apt-get update
时,你要输入密码。默认这个授权时间是5分钟。
你可以改得稍微长一些,比如30min。我们将Defaults env_reset
来改为Defaults env_reset, timestamp_timeout=30
即可。Vim退出:wq
后生效。如果你不想改,就不要做任何事。直接:q!
退出。
之后,我们将它的权限改回来:
sudo chmod -w /etc/sudoers && ls -hl /etc/sudoers
输出为:
-r--r----- 1 root root 847 Apr 19 13:38 /etc/sudoers
这里值得注意的一行是:root ALL=(ALL:ALL) ALL
。这意味着root用户在做事情时都不用输入密码(没理解错吧?)。不要让普通用户轻易地拥有这种能力!
另外,你还可以即时强行结束sudo
对你的授权:
sudo -K
此后你再调用sudo
权限,就要再次输入用户密码获得授权。
其实sudo
还有很多更高级的用法,不过我们作为新手了解这些就足够了。
目前阶段咱们还是稳一波,乖乖地用普通的非root用户和密码来做事:relaxed:
禁用root使用ssh密码登陆
我们用非root用户的重要原因,就是因为我们要禁用root通过ssh登陆我们的VPS。像腾讯云,在初始化系统的时候就是禁root的。这是为什么呢?
我用自己来举例。比如,我可以通过ssh user@ip
的方式尝试我的另一台VPS:
一般情况下,主机是允许root
用户远程登陆的。而root
用户的名字一般就是root
。所以,如果攻击者知道你VPS的ip地址(ping你的域名获得)、用户名(默认有一个root可用)和ssh端口号(默认22),那么保护你电脑的就只有你的用户密码了。如果你的root密码被破解了(比如你用了一些123456
的弱密码),那你的VPS就任人鱼肉了!如果你只是非root用户密码被破解,那么root用户可以暂时保护一下你。不过这种时候基本上已经非常危险了。
所以呀,我们用非root用户是有原因的,这样我们可以在用户名这个层面上增强VPS的安全防护。
当然,如果你能进一步操作ssh端口号和ip,那么你的VPS的安全等级将呈指数级上升!我下面还会介绍如何进行设置ssh端口和ip的!
我不知道root
用户能不能改名,但我觉得没必要。你用一个新的非root用户,然后禁root远程登陆就行了。
这里我们开始讲讲怎么禁用root
用户远程ssh登陆。首先,我们编辑ssh程序的设置文件:
sudo vim /etc/ssh/sshd_config
在界面中应该在类似的内容:
#Port 22
#AddressFamily any
AddressFamily inet
#ListenAddress 0.0.0.0
#ListenAddress ::
#HostKey /etc/ssh/ssh_host_rsa_key
#HostKey /etc/ssh/ssh_host_ecdsa_key
#HostKey /etc/ssh/ssh_host_ed25519_key
# Ciphers and keying
#RekeyLimit default none
# Logging
#SyslogFacility AUTH
#LogLevel INFO
# Authentication:
#LoginGraceTime 2m
PermitRootLogin no (就是这里!!)
# PermitRootLogin prohibit-password
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10
找到PermitRootLogin
参数,它的值yes
改成no
。要注意去掉前面的#
号。:wq
退出保存。
重启ssh服务后生效:
sudo service sshd restart
这里要切记,不要关闭旧的Shell
。新开一个Shell
,用你刚刚的非root用户登陆Shell
。成功后再关闭旧的Shell
窗口。切记切记!
如果你不喜欢总是用非root用户登陆然后输入root密码,并且访问远程VPS的设备又比较固定的话,也推荐你限制root用户只能通过证书登录。只要添加你本地设备的公钥到root帐户里的authorized_keys
中,然后将PermitRootLogin
后面的yes
/no
改为without-password
,最后重启ssh服务即可。关于VPS信任的具体操作可以看我的另外一篇博文《Linux基础 实用Linux命令一览表》中的VPS相互信任
一小节。
隐藏公网ip
从前面的讨论,我们知道VPS的安全也可以在公网ip的层面进行操作。
我们可以通过这个命令获取自己的公网ip:
curl ifconfig.me
它通常长成这样:000.00.00.00
,3个点分成4段数字。如果你用VPS,这个公网ip是固定的。如果你用的是家用宽带,这个ip是动态变化的,一般是48小时左右变化一次(视装网地区而定)。某些公司的网络是专线网,公网ip也是固定的。
隐藏ip之前,你应该要准备一个域名并托管在cloudflare上(其它域名托管商没有用过,不知道有没有类似的功能。这里我只展示cloudflare怎么用)。
这部分内容是我的推测,未经求证。也许我的理解有误,欢迎专业人士留言指正了!
安装UFW防火墙
前面,我们通过更改ssh端口的方式增强安全性。其实呢,你还可以通过管理VPS所有的端口来进一步增加安全性喔!这里我们介绍ufw
。
首先,给大家可以看一段wiki上的介绍:
大致来说,ufw是一个简单好用的防火墙工具,使用iptables
进行设置。这里我不准备展开介绍iptables
。自己想了解百度Google即可。
这里多说一句,iptables
其实是一个很强大的防火墙工具,不过它确实很难用。如果你学会熟练地使用iptables
的话,我觉得ufw
应该也可以不用。像我们这种新手用ufw
就足够了。
首先,观察一下自己的机器有没有ufw
which ufw # /usr/sbin/ufw
没有的话,直接安装一个:
sudo apt-get install ufw
如果有的话,就可以开始了!
用sudo ufw status
查看防火墙状态。如果你之前没有设置过ufw
,一般是显示Status: inactive
。
下面我们逐步来设置ufw
。
- 设置
ufw
的默认值
sudo ufw default deny incoming # 禁止所有进站的流量
sudo ufw default allow outgoing # 允许所有出站的流量
- 允许https/http连接
sudo ufw allow 80 # 默认http
sudo ufw allow 443 # 默认https
- 允许新ssh端口(下文会用到)
sudo ufw allow 1234/tcp comment 'SSH_2' # 1234记得换成你自定义的端口喔
如果你遵循我的docker教程,80
端口和443
端口一般是由Nginx proxy manager进行管理。一般情况下,都是Nginx软件管理80和443端口(比如宝塔面板)。
你也可以根据自己的需要开放端口:
sudo ufw allow <你的端口号>/tcp comment '你想要的备注'
如果你用docker,通常要添加某个应用的端口号,这样才可以正常地通过NPM反代。
值得一提的是,iptable
可以提供更加精细的调控,但ufw
我还不知道怎么精细地控制端口不同类型的流量。
- 启动ufw:
sudo ufw enable # 启动ufw。重启主机后正式生效。
其它常用的命令有:
# 查看帮助
ufw -h
# 如果你改动了ufw规则,记得reload一下生效
sudo ufw reload
# 显示规则的数字
sudo ufw status numbered
# 删除某个规则。基于sudo ufw status numbered命令。
sudo ufw delete <数字>
# 删除规则更好用的方法是 ufw delete <rule>。比如:
ufw delete allow 22 # 删除规则allow 22
ufw delete allow 22/tcp # 删除规则allow 22/tcp
更改默认的ssh端口
默认的ssh端口号是22
。SSH 的端口一般建议把它改成一个大于1024小于65535的整数。比如,我想改成1234
。
在你的VPS后台防火墙里先打开1234
端口。有些VPS后台可能没有防火墙,就可以不用管。
下面,简单地用ufw
将新的ssh端口1234
打开:
sudo ufw allow 1234/tcp comment 'SSH' # 1234记得换上你自己的端口啦
然后像修改root访问ssh的权限一样打开ssh的设置文件:
sudo vim /etc/ssh/sshd_config
在开头不远处就一个#Port 22
的字样。#
号在多数情况下是注释号,表明后面的内容不生效。
将#
号去除,然后22
改为1234
:
Port 1234
重启ssh服务生效
sudo service sshd restart
此时不要关闭终端,新开一个窗口进行用新端口号、非root用户进行ssh登陆测试。如果成功,就可以关闭旧的Shell了。OK,安全指数+1,哈哈!新端口成功后,旧的22
端口已经没有用。可以关掉了。
更多ssh使用的技巧可参考我的文章《Linux基础 实用Linux命令一览表》 (ฅ´ω`ฅ) :
禁ping
仅Ubuntu/ufw有效。其它Linux发行版可自行找类似教程
就算你隐藏了公网ip,别人通过穷举法还是有可能发现你的ip。所以还是设置自己的主机禁ping,伪装成是一台不能使用的机器吧。这是一种非常强的保护特征,因为扫IP应用一般优先攻击可以ping通的ip。
很简单,只要
sudo vim /etc/ufw/before.rules
外面到本地的访问是由INPUT
控制的,其中echo-request
就是ping所采用的类型。因此,只要找到ok icmp codes for INPUT
下面的记录:
# ok icmp codes for INPUT
-A ufw-before-input -p icmp --icmp-type destination-unreachable -j ACCEPT
-A ufw-before-input -p icmp --icmp-type time-exceeded -j ACCEPT
-A ufw-before-input -p icmp --icmp-type parameter-problem -j ACCEPT
# -A ufw-before-input -p icmp --icmp-type echo-request -j ACCEPT
-A ufw-before-input -p icmp --icmp-type echo-request -j DROP
如上面的代码框所示,找到含有echo-request
,把ACCEPT
改成DROP
。这样外面的机器就无法ping通你的VPS了!
可重新加载一下ufw
以使改动生效(不知道是否是必需):
sudo ufw reload
你可以用windows个人电脑或者Linux的主机ping一下你的VPS;或者直接使用Chinaz来ping:
成功设置时会出现“满江红”现象,提示Ping不可用。
Fail2ban防扫描和暴力破解
Fail2ban是防止后台暴力扫描的流行保护软件之一。推荐安装:
安装Fail2ban
:
sudo apt update && sudo apt install fail2ban -y
查看一下状态:
sudo fail2ban-client status
有时候,会出现类似报错:
[5583]: ERROR Failed to access socket path: /var/run/fail2ban/fail2ban.sock. Is fail2ban running?
这提示fail2ban并未启动。你可以用systemctl status fail2ban
命令进一步核实。如果确实未启动,只要:
sudo systemctl start fail2ban
即可启动fail2ban。
值得一提的是,fail2ban默认ssh是被监控的:
Status
|- Number of jail: 1
`- Jail list: sshd
你可以在/etc/fail2ban/filter.d
里查看各种应用的默认配置。我看sshd.conf
的设置是挺强的,大家用默认的配置文件问题不大:
我还建议大家设置一下/etc/fail2ban/jail.local
文件(有些系统是/etc/fail2ban/jail.conf
)中的sshd选项。比如,我的选项是:
该配置是一种比较流行的方案。它将启用SSH监视,并配置 fail2ban
以在5次无效登录尝试之后封禁IP地址,封禁时间为1小时(3600s
)。虽然不是永久封禁,但已经是一种很强的防护了,恶意IP不太可能持续地进行攻击。
查看工作状态:
# 查看fail2ban的工作状态
sudo fail2ban-client status
# 查看sshd监视的状态
sudo fail2ban-client status sshd
# 检查当前封禁的IP地址列表
sudo fail2ban-client status sshd | grep "Banned IP list"
/var/log/fail2ban.log
保存了拦截日志。查看全部记录
less /var/log/fail2ban.log
如果有攻击记录,内容类似:
查看实时拦截:
tail -f -n 30 /var/log/fail2ban.log
这里的内容类似《NAS系列 PVE基本设置 》的“Fail2ban防扫描和暴力破解”小节。更多高级用法以后再研究。
小结
这一节,我们基本对个人的VPS进行了基本的防护,包括对ip、端口、用户的操作。这样可以让VPS更安全,但也不是绝对的。我也并没有太多经验。
总之,你可以在此基础上进行深入的Linux学习了,比如布署Docker应用和Wordpress之类的!
如果你以后网站做大做强了,访问量很大的时候,还是需要请专业的团队来帮忙维护的!
参考资料
---------------
完结,撒花!如果您点一下广告,可以养活苯苯😍😍😍
vps我一般只有需要操作时,才通过供应商提供的网页版shell开启sshd,同时开启证书登录,只要退出vps就把ssh服务关闭,应该就安全了。
我还是比较常登陆VPS的,所以这种策略对我来说不太合适 (~ ̄▽ ̄)~
嗯嗯,我目前vps就是用来中转,npm+frps。其他的都不装,目前是这样,这样端口开的少,比较偷懒。不知道我这样有什么不好的。按照你的方法,装了ufw,平时就开了两个端口,应该比较安全了吧。∩__∩
差不多 ~ 其实也可以装一下fail2ban之类的防护软件嘛,可以对持续攻击进行较好保护
嗯嗯,这个确实很有用,正在研究中🤝
补充一个安全选项(=・ω・=):
这也是一个不错的策略。我更加推荐的是只通过密钥访问,详见《Linux基础 基于密钥对的SSH远程登陆》。
博主文中的<Docker系列 两大神器Nginx proxy manager (NPM)和ddns-go的安装>, 该部分点进去后,报404?
我回去后看看。你可以现在学习地图里找找这个文章
好活,又学到了(☆ω☆)PS:这美女背景真养眼
眼睛是心灵的窗户,不能怠慢! (☆ω☆)
博主,我想问下为什么在新创建的用户中安装ohmyzsh后没有.zshrc文件
https://p.sda1.dev/7/721c84e8c5aaedc11a2522273b0c9fb6/屏幕截图 2022-10-21 233435.png
因为ohmyzsh每次安装时只针对当时的用户。你可以按照这里的提示安装: https://blognas.hwb0307.com/linux/linux-basic/399 搜索“oh-my-zsh二次安装”ヾ(≧∇≦*)ゝ
大佬,vps采用密钥对的登陆方式是不是也能大幅度的提升安全性呢
据说是这样,不过我平时用得也不多。安全性的追求程度和应用场景是相适应的。家用场景下,普通的密码登陆就行。注意,不要用123456之类的弱密码。
好文?????
哈哈,自己学完了随便写写,怕以后忘记了~谢谢鼓励哈! 🙂