Jul 10, 2016 from—http://hankerzheng.com/blog/basic-vps-security-setting

前言

开了一个Linode VPS之后, 按着Linode的教程对服务器的安全性能进行一些配置, 写一篇博客, 对配置的过程进行一些记录, 以备今后查看. Linode原文教程请点击这里
本文的方法适用于Ubuntu 16.04

创建一个权限有限的新用户

输入adduser user_name指令, 创建一个名为user_name的新用户, 然后为该用户设定密码

如果不做说明, 系统会创建一个和该用户同名的用户组, 如果需要修改该用户的用户组, 可以使用usermod -G group_name user_name, 该指令会强行把名为user_name的用户的用户组设定为group_name. 也就是说, 在执行这个指令之后, 该用户只属于group_name. 如果想保留用户原用户组, 可以使用-a(append)参数, 即usermod -a -G group_name user_name

给新用户设置sudoer

退出root账户登录, 采用新建的用户登录. 如果该新用户想执行root权限下的指令, 如adduser, usermod等, 有这几种种方法. 一是执行su指令, 在输入root密码后, 将当前用户切换到root; 二是执行sudo COMMAND指令; 或者可以用类似的su -c COMMAND root指令, 在使用root执行完COMMAND后, 马上切回到当前用户.

因为使用sudo指令可以不需要输入root密码, 而只需要当前用户密码即可, 这里推荐使用sudo指令来执行root权限的指令.

但是在试了sudo COMMAND指令后, 系统跳出提示

XXX is not in the sudoers file.  This incident will be reported.

这说明当前的用户并不在sudoer中. 要添加用户到sudoer可以用visudo指令来编辑sudoers.tmp文件. 打开后我们可以看到如下内容

#
# 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.
#
Defaults        env_reset
Defaults        mail_badpass
Defaults        secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

# Host alias specification

# User alias specification

# Cmnd alias specification

# User privilege specification
root    ALL=(ALL:ALL) ALL

# Members of the admin group may gain root privileges
%admin ALL=(ALL) ALL

# Allow members of group sudo to execute any command
%sudo   ALL=(ALL:ALL) ALL

# See sudoers(5) for more information on "#include" directives:

#includedir /etc/sudoers.d

看到root ALL=(ALL:ALL) ALL这一行, 其中第一个ALL指的是主机地址, 第二个ALL:ALL指的是用户以什么身份执行, 最后一个ALL指的是可以使用的指令

这篇文章很好地解释了该如何配置sudoer文件, 关键内容摘录如下:

##如何让普通用户support只能在某几台服务器上,执行root能执行的某些命令?
首先需要配置一些Alias,这样在下面配置权限时,会方便一些,不用写大段大段的配置。Alias主要分成4种: Host_Alias, Cmnd_Alias, User_Alias, Runas_Alias.

1) 配置Host_Alias:就是主机的列表 
Host_Alias      HOST_FLAG = hostname1, hostname2, hostname3 
2) 配置Cmnd_Alias:就是允许执行的命令的列表 
Cmnd_Alias      COMMAND_FLAG = command1, command2, command3 
3) 配置User_Alias:就是具有sudo权限的用户的列表 
User_Alias USER_FLAG = user1, user2, user3 
4) 配置Runas_Alias:就是用户以什么身份执行(例如root,或者oracle)的列表 
Runas_Alias RUNAS_FLAG = operator1, operator2, operator3 
5) 配置权限 
配置权限的格式如下: 
USER_FLAG HOST_FLAG=(RUNAS_FLAG) COMMAND_FLAG 
如果不需要密码验证的话,则按照这样的格式来配置 
USER_FLAG HOST_FLAG=(RUNAS_FLAG) NOPASSWD: COMMAND_FLAG 

设置完成后保存并退出该文件即可.

巩固SSH登录接口

我们一般采用ssh登录Linode服务器, 但是普通密码很容易就会被暴力方法攻破. 这里我们介绍密钥对登录ssh的方法, 从而巩固ssh登录的安全性能.

首先, 根据本文的方法本地创建密4096-bit RSA钥对

然后, 将公钥上传到服务器/home/user_name/.ssh/authorized_keys文件中. 为了安全起见, 使用sudo chmod 600 authroized_keys指令将该文件的权限修改为仅对root读写.

最后, 在putty客户端上的ssh中选中刚才生成的私钥.

这样一番设置后, 在此登录时, 我们只需要输入创建密钥对时的passphrase就可以完成用户登录了.

SSH Daemon配置

禁止通过ssh登录root账户

修改/etc/ssh/sshd_config文件, 将PermitRootLogin修改为no.

禁止所有用户通过ssh密码登录

修改/etc/ssh/sshd_config文件, 将PasswordAuthentication修改为no.
如果应用了这条, 那么所有用户都必须要使用密钥登录.

只对一种网络协议进行监听

Daemon默认对IPv4和IPv6两种协议都进行监听. 如果用户没有两种需求, 可以关闭对一个协议的监听. 这个关闭只是对SSH Daemon而言, 并不影响网络访问. 这个修改可以通过在/etc/ssh/sshd_config文件中添加AddressFamily inet来实现只对IPv4的监听, 添加AddressFamily inet6来实现只对IPv6的监听

重启SSH服务以更新配置

sudu systemctl restart sshd

安装Fail2Ban

Fail2Ban是一个能够封禁输入密码错误次数过多用户IP的软件. 该软件可以监控多种协议登录, 例如HTTP, SSH, SMTP. 默认情况下, Fail2Ban只监控SSH协议. 具体安装过程, 请看这篇文章

配置防火墙

此处我们介绍一种网络流量控制器iptables, 它一般都会集成在Linux系统中.

UFW是一个Ubuntu系统自带的iptables控制器(准确地说, UFW是iptables的图形界面), 如果想直接使用用UFW, 可以看这篇文章

查看当前iptables规则

查看IPv4规则的指令为sudo iptables -L, 查看IPv6规则的指令为sudo ip6tables -L

默认的iptables没有应用任何规则, 在新建的Linode系统中, 我们一般能看到下面的防火墙规则, 分别表示所有的流入, 流出, 以及换发流量都是允许的.

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

IPtables基本规则设置

下面的配置内容只是Linode给出的参考, 具体的设置可以参考这篇文章

设置IPv4过滤过则, 打开文件/tmp/v4, 输入以下内容:

*filter

# Allow all loopback (lo0) traffic and reject traffic
# to localhost that does not originate from lo0.
-A INPUT -i lo -j ACCEPT
-A INPUT ! -i lo -s 127.0.0.0/8 -j REJECT

# Allow ping.
-A INPUT -p icmp -m state --state NEW --icmp-type 8 -j ACCEPT

# Allow SSH connections.
-A INPUT -p tcp --dport 22 -m state --state NEW -j ACCEPT

# Allow HTTP and HTTPS connections from anywhere
# (the normal ports for web servers).
-A INPUT -p tcp --dport 80 -m state --state NEW -j ACCEPT
-A INPUT -p tcp --dport 443 -m state --state NEW -j ACCEPT

# Allow inbound traffic from established connections.
# This includes ICMP error returns.
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# Log what was incoming but denied (optional but useful).
-A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables_INPUT_denied: " --log-level 7

# Reject all other inbound.
-A INPUT -j REJECT

# Log any traffic that was sent to you
# for forwarding (optional but useful).
-A FORWARD -m limit --limit 5/min -j LOG --log-prefix "iptables_FORWARD_denied: " --log-level 7

# Reject all traffic forwarding.
-A FORWARD -j REJECT

COMMIT

如果希望启用Linode Longview或者Linode NodeBalancers, 需要在HTTP, HTTPS过滤过则那一栏加入以下规则:

# Allow incoming Longview connections.
-A INPUT -s longview.linode.com -m state --state NEW -j ACCEPT

# Allow incoming NodeBalancer connections.
-A INPUT -s 192.168.255.0/24 -m state --state NEW -j ACCEPT

同样的, 对IPv6的过滤过则设置, 打开文件/tmp/v6, 输入一下内容

*filter

# Allow all loopback (lo0) traffic and reject traffic
# to localhost that does not originate from lo0.
-A INPUT -i lo -j ACCEPT
-A INPUT ! -i lo -s ::1/128 -j REJECT

# Allow ICMP
-A INPUT -p icmpv6 -j ACCEPT

# Allow HTTP and HTTPS connections from anywhere
# (the normal ports for web servers).
-A INPUT -p tcp --dport 80 -m state --state NEW -j ACCEPT
-A INPUT -p tcp --dport 443 -m state --state NEW -j ACCEPT

# Allow inbound traffic from established connections.
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# Log what was incoming but denied (optional but useful).
-A INPUT -m limit --limit 5/min -j LOG --log-prefix "ip6tables_INPUT_denied: " --log-level 7

# Reject all other inbound.
-A INPUT -j REJECT

# Log any traffic that was sent to you
# for forwarding (optional but useful).
-A FORWARD -m limit --limit 5/min -j LOG --log-prefix "ip6tables_FORWARD_denied: " --log-level 7

# Reject all traffic forwarding.
-A FORWARD -j REJECT

COMMIT

apt-get指令会通过IPv6来解析资源镜像的域名. 如果防火墙设置为完全关闭IPv6, 这会导致Ubuntu更新变得很慢. 这个问题可以通过去掉文件/etc/gai.conf里面preecedence ::ffff:0:0/96 100这句话前面的注释号解决

应用防火墙规则(Ubuntu)

使用下面指令来应用配置的iptables过滤过则:

sudo iptables-restore < /tmp/v4
sudo ip6tables-restore < /tmp/v6

iptables-persistent能在系统启动的时候自动加载iptables规则, 建议安装. 安装指令为sudo apt-get install iptables-persistent. 安装完成后, iptables-persistent会弹出窗口询问是否要保存当前的iptables规则, 选择yes.

最后, 删除iptables配置的临时文件sudo rm /tmp/{v4,v6}

确认当前iptables规则

指令sudo iptables -vL以及sudo ip6tables -vL能查看当前防火墙的过滤规则.

修改iptables规则

iptables规则被强制设计成从上往下的形式, 也就是说数据包在被iptables过滤的时候, 是一次次按照顺序分别通过每一个规则的, 所以才称之为iptables Chain(链). 因此, 添加规则时, 不能使用iptables -A或者ip6tables -A指令, 而应该使用iptables -I或者ip6tables -I指令

插入规则

插入规则时, 需要指明规则插入的位置. 可以执行sudo iptables -L --line-numbers指令得到当前过滤规则的列表. 加入我们需要添加Linode Longview连接, 并且将该规则的顺序设定为INPUT Chain的8, 我们只需要输入sudo iptables -I INPUT 8 -p tcp -dport 8080 -j ACCEPT

替换规则

sudo iptables -R INPUT 9 -m limit --limit 3/min -j LOG --log-prefix "iptables_INPUT_denied: " --log-level 7

删除规则

sudo iptables -D INPUT 8