在购买自己的VPS之后,首先要做好的就是安全防护工作,本文将主要介绍以下方式来提高VPS的安全防护能力:

  • 修改ssh默认端口,开启密钥登陆并关闭简单密码登录
  • 开启iptables防火墙,关闭不必要端口的入站连接

ssh设置

修改默认端口

修改/etc/ssh/sshd_config文件:

/etc/ssh/sshd_config
1
2
# What ports, IPs and protocols we listen for
Port 12345

将ssh默认端口22改为一个随机的端口。 注意:小于1024的端口为系统默认分配给特定服务的端口,不建议随意占用。

禁用root登陆

开启root用户登录使得攻击者可以轻易的猜到可登陆的用户名,同时使用高权限用户操作,如果操作错误容易引起无法恢复的系统错误。因此建议新建一个普通用户登陆,并加入sudo组,在需要时可执行高权限命令,或者直接切换到root用户操作。

新建用户

新建用户testuser:

1
adduser testuser

接下来会提示输入该用户的相关信息,显示如下:

adduser testuser
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Adding user `testuser' ...
Adding new group `testuser' (1001) ...
Adding new user `testuser' (1001) with group `testuser' ...
Creating home directory `/home/testuser' ...
Copying files from `/etc/skel' ...
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
Changing the user information for testuser
Enter the new value, or press ENTER for the default
Full Name []:
Room Number []:
Work Phone []:
Home Phone []:
Other []:
Is the information correct? [Y/n] y
按照提示输入相关信息后,确认信息正确,则该用户创建完成。

将用户加入sudo组

将用户加入sudo组,在需要执行高权限命令时可以直接在命令前加sudo执行。给某用户赋予sudo权限需要修改/etc/sudoers文件,但是sudoers文件一旦修改错误易造成系统权限混乱,因此不建议直接修改sudoers文件。事实上sudoers文件默认对所有用户(包括root用户)都是只读权限。修改sudoers文件建议通过程序visudo进行,visudo在修改sudoers文件之前会对用户的更改进行检测,当没有出现错误时再将修改写入sudoers文件。 以管理员权限执行命令visudo

1
visudo

# User privilege specification行下加入如下行:

visudo
1
2
3
# User privilege specification
root ALL=(ALL:ALL) ALL
testuser ALL=(ALL:ALL) ALL # 加入这一行
保存退出。

禁用root登陆

修改sshd_config文件,禁用root登陆

/etc/ssh/sshd_config
1
PermitRootLogin no

然后重启ssh使配置生效:

1
/etc/init.d/ssh restart

注意:以上每次修改sshd_config后都可以重启ssh,然后退出当前ssh连接,再按照新的配置登陆ssh,以验证配置的正确。

禁用简单密码登录,使用密钥登陆

禁用简单密码登录能够防止对服务器猜测密码的暴力破解。

创建密钥

首先要创建使用rsa算法加密的公私密钥:

1
ssh-keygen -t rsa

输出如下:

ssh-keygen -t rsa
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Generating public/private rsa key pair.
Enter file in which to save the key (/home/testuser/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in ./test_rsa.
Your public key has been saved in ./test_rsa.pub.
The key fingerprint is:
xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx testuser@vps
The key's randomart image is:
+--[ RSA 2048]----+
| xx. |
| . .. |
| .x***.. |
| . . * |
| == .-. |
| . x |
|X. + >_<! |
| .X *= - x |
|.. ..+** |
+-----------------+

会提示输入密钥保存的位置与名称、密钥密码,密钥密码用以保护密钥,在使用密钥时同时需要输入该密码。如果私钥被窃取,没有密码也无法使用该密钥。如果不想要密码,在要求设置密码时直接按回车键跳过密码输入。

上传公钥至服务器

生成公私钥后,将公钥上传至服务器。如果是在服务器生成的密钥,则需要将私钥传回客户端并删除服务器上的私钥。 使用 scp 命令上传公钥:

1
scp ./ssh/id_rsa.pub usertest@remote_ssh:

设置密钥

将上传的公钥保存到当前用户的~/.ssh目录下,并重命名为authorized_keys

~
1
mv id_rsa.pub ./.ssh/authorized_keys

同时,为了安全可以设置.ssh目录以及authorized_keys的权限

~
1
2
chmod 700 -R .ssh
chmod 400 ./.ssh/authorized_keys

启用密钥并禁用密码登录

编辑/etc/ssh/sshd_config文件,修改以下项目:

/etc/ssh/sshd_config
1
2
3
4
5
6
RSAAuthentication yes      #RSA认证
PubkeyAuthentication yes #开启公钥验证
AuthorizedKeysFile .ssh/authorized_keys #验证文件路径
PasswordAuthentication no #禁止密码认证
PermitEmptyPasswords no #禁止空密码
UsePAM no #禁用PAM

然后保存,重启ssh服务

1
sudo /etc/init.d/ssh restart

现在,退出当前ssh连接,使用密钥就可以登录服务器了。

iptables防火墙设置

Ubuntu自带了非常简单但功能强大的防火墙iptables,如果不配置规则,默认是允许所有流量的。

查看iptables列表

用以下命令可以查看已经生效的iptables规则:

1
sudo iptables -L

显示如下:

sudo iptables -L
1
2
3
4
5
6
7
8
Chain INPUT (policy ACCEPT)
target prot opt source destination

Chain FORWARD (policy ACCEPT)
target prot opt source destination

Chain OUTPUT (policy ACCEPT)
target prot opt source destination

默认是没有任何规则的。也可以加上-v选项查看更为详细的信息。 命令ifconfig可以查看网络接口信息:

ifconfig
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
lo        Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)

venet0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
inet addr:127.0.0.2 P-t-P:127.0.0.2 Bcast:0.0.0.0 Mask:255.255.255.255
UP BROADCAST POINTOPOINT RUNNING NOARP MTU:1500 Metric:1
RX packets:7054342 errors:0 dropped:0 overruns:0 frame:0
TX packets:5911869 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:9292344012 (9.2 GB) TX bytes:1060426275 (1.0 GB)

venet0:0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
inet addr:192.1.2.3 P-t-P:192.1.2.3 Bcast:192.1.2.3 Mask:255.255.255.255
UP BROADCAST POINTOPOINT RUNNING NOARP MTU:1500 Metric:1
其中lo代表本地回环地址,venet0是OpenVZ架构虚拟机中的第一块虚拟网卡,venet0:0是venet0的别名。

iptables 命令解释

iptables常用命令解释:

  • -A chain, –append 添加一条新规则
  • -D chain [rulenumder], –delete 删除一条规则
  • -I chain [rulenumder], –insert 插入一条规则
  • -R chain [rulenumber], –replace 替换一条规则
  • -L [chain [rulenumber]], –list 列出所有规则
  • -P, –policy 策略
  • -i, –in-interface 网络接口名称
  • -m match, –match 扩展匹配
  • -p proto, –protocol 协议,如’tcp’,’udp’
  • -j target, –jump 参数用来指定要进行的处理动作,常用的处理动作包括:ACCEPT、REJECT、DROP、REDIRECT、MASQUERADE等

链(chain):链是一些按顺序排列的规则的列表,iptables 默认的 filter 表包含 INPUT, OUTPUT 和 FORWARD 3条内建的链。

允许连接

首先允许本地回环端口

1
sudo iptables -A INPUT -i lo -j ACCEPT

允许建立关联连接

1
sudo iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

允许访问特定端口

1
sudo iptables -A INPUT -p tcp --dport 12345 -j ACCEPT

如,允许ssh端口:

1
2
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT
# 如果更改了默认ssh端口要更改为修改后的端口(如上文中的12345)

允许FTP端口:

1
2
sudo iptables -A INPUT -p tcp --dport 21 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 20 -j ACCEPT

同时开放多个端口:

1
sudo iptables -A INPUT -p tcp -m multiport --dport 20,21 -j ACCEPT

允许接收ping

1
sudo iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT

接收ping后可以通过ping命令在本地服务端测试网络延迟,但是也会使其他人通过ping来知晓该服务器地址的可用性,如无特殊需要可以不接受所有ping。

阻止其他连接

最后,在以上允许连接的基础上阻止所有其他连接:

1
2
sudo iptables -A INPUT -j REJECT
sudo iptables -A FORWARD -j REJECT

注意:在阻止所有连接之前一定要将允许ssh端口的连接,否则规则生效后会直接断开ssh连接并且无法重新连接。这时只能进入管理后台取消该阻止规则,或者重装系统。

编辑已存在规则

将所有的iptables规则以序号标记显示:

1
sudo iptables -L -n --line-numbers

显示如下:

sudo iptables -L -n --line-numbers
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Chain INPUT (policy ACCEPT)
num target prot opt source destination
1 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:12345
2 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
3 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:20
4 ACCEPT udp -- 0.0.0.0/0 0.0.0.0/0 multiport dports 2000,3000
5 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0
6 DROP all -- 0.0.0.0/0 0.0.0.0/0

Chain FORWARD (policy ACCEPT)
num target prot opt source destination

Chain OUTPUT (policy ACCEPT)
num target prot opt source destination

现在INPUT 链中已经有6条规则了,现在来修改已经存在的规则。

删除一条规则

比如:删除第6条规则

1
sudo iptables -D INPUT 6

插入一条规则

在第2条规则之前插入一条规则

1
sudo iptables -I INPUT 2 -p tcp -i venet0 --dport 1234 -j ACCEPT

保存规则与恢复规则

在Ubuntu上 iptables 默认是不会保存已经设置的规则,系统重启后所有规则将丢失,所以需要将已有规则保存下来。

手动保存规则

root #
1
2
3
# 由于sudo只作用于其后跟的第一个命令,所以以下命令中">"会因为没有写入权限而无法运行,所以直接切换到root用户运行命令。
su root
iptables-save > /etc/iptables.input.rules

保存规则后,设置开机自动从文件恢复规则。编辑开机启动文件/etc/rc.local 在exit 0之前写入以下命令

/etc/rc.local
1
iptables-restore < /etc/iptables.input.rules
保存退出。

自动保存规则

让网卡关闭时自动保存规则,网卡开启时自动恢复规则。 创建/etc/network/if-post-down.d/iptables 文件,添加如下内容:

/etc/network/if-post-down.d/iptables
1
2
#!/bin/bash
iptables-save > /etc/iptables.input.rules
为文件添加执行权限:
1
sudo chmod +x /etc/network/if-post-down.d/iptables

创建/etc/network/if-pre-up.d/iptables 文件,添加如下内容:

/etc/network/if-pre-up.d/iptables
1
2
#!/bin/bash
iptables-restore < /etc/iptables.input.rules
为文件添加执行权限:
1
sudo chmod +x /etc/network/if-pre-up.d/iptables

当网络关闭或开启时就会自动保存与恢复iptables规则。