Windows&Linux加固

该课件这不是一个完整的Windows & Linux 教程,不会解释Windows & Linux 操作系统架构和管理的每一个细节(根据前面的学习,这里根本没必要详细说明),只介绍一些加固操作系统的技巧。

Linux

OS security

更新策略

在更新系统内核、服务或程序之前,请记住检查任何可能因系统更新/升级而崩溃的软件。

该计算机可能正在使用与您的发行版的较新版本不兼容的未打补丁的旧软件。

检查包管理器

验证包存储库是否已正确配置。根据所使用的包管理器,选择命令组其中一个:

# yum repolist
# apt-cache policy
# zypper repos
确保配置了GPG密钥
# rpm -q gpg-pubkey --qf '%{name}-%{version}-%{release} --> %{summary}\n'
# apt-key list
# zypper repos
安装前验证包
在redhat上:
rpm --verify
rpm -Va >>> verify all

在ubuntu上:
apt install debsums
debsums -l >>> generate a list 
debsums -c  >>> check all
检查包完整性
基于Debian:
#单个包
debsums [package]
#所有安装的包
dpkg -l | egrep '^ii' | awk '{print $2}' | xargs sudo debsums | egrep -v 'OK'
#如果您怀疑某个文件更改了,但不知道它来自哪个包,请尝试: 
dpkg -S /full/path/to/file

基于Redhat:
#单个包
rpm --checksig [package]

更新基于 Debian 的系统

#更新存储库
sudo apt update

#升级所有包
sudo apt upgrade

#完整发行版升级(包括内核)
sudo apt dist-upgrade

#删除旧的未使用的包以释放空间
apt auto-remove

手动安全更新

要手动安装与安全相关的更新而不安装非安全更新,只需运行以下command:

sudo unattended-upgrade -d

如果你想查看是否有任何安全相关的更新可用,但不想看到任何非安全的更新,像这样:

sudo unattended-upgrade --dry-run -d

Debian & Ubuntu 自动更新

您可以通过安装一个名为unattentedupdates的实用程序来在Debian上设置自动的安全更新

1 .用apt update && apt upgrade更新系统。

2 .运行以下命令安装它:

sudo apt install unattended-upgrades

3 .安装完成后,通过运行以下命令启用和启动服务:

sudo systemctl enable unattended-upgrades
sudo systemctl start unattended-upgrades

这确保了服务在系统启动时运行并且始终保持不变。

4 .现在需要对配置文件进行更改。默认的配置文件可以在/etc/apt/apt.conf.d/50unattended-upgrades找到

unattended-upgrades 包会忽略以//开头的行,因为该行被视为注释。因此,如果您希望存储库自动更新,则需要从该行前面删除//

例如,从“security”行中删除//"origin=Debian,codename=${distro_codename},label=Debian-Security"; 此部分如下所示:

nano /etc/apt/apt.conf.d/50unattended-upgrades
...

Unattended-Upgrade::Origins-Pattern {
        // Codename based matching:
        // This will follow the migration of a release through different
        // archives (e.g. from testing to stable and later oldstable).
        // Software will be the latest available for the named release,
        // but the Debian release itself will not be automatically upgraded.
//      "origin=Debian,codename=${distro_codename}-updates";
//      "origin=Debian,codename=${distro_codename}-proposed-updates";
        "origin=Debian,codename=${distro_codename},label=Debian";
        "origin=Debian,codename=${distro_codename},label=Debian-Security";

        // Archive or Suite based matching:
        // Note that this will silently match a different release after
        // migration to the specified archive (e.g. testing becomes the
        // new stable).
//      "o=Debian,a=stable";
//      "o=Debian,a=stable-updates";
//      "o=Debian,a=proposed-updates";
//      "o=Debian Backports,a=${distro_codename}-backports,l=Debian Backports";
};
将软件包列入黑名单

配置文件的Unattended-Upgrade::Package-Blacklist部分允许您阻止特定软件包的升级。

要阻止特定软件包的升级,请将所需的软件包名称添加到列表中。例如,添加“apache2”和“vim”:

...

Unattended-Upgrade::Package-Blacklist {
    // The following matches all packages starting with linux-
//  "linux-";
    "apache2";
    "vim";
    // Use $ to explicitely define the end of a package name. Without
    // the $, "libc6" would match all of them.
//  "libc6$";
//  "libc6-dev$";
//  "libc6-i686$";

    // Special characters need escaping
//  "libstdc\+\+6$";

    // The following matches packages like xen-system-amd64, xen-utils-4.1,
    // xenstore-utils and libxenstore3.0
//  "(lib)?xen(store)?";

    // For more information about Python regular expressions, see
    // https://docs.python.org/3/howto/regex.html
};

...
删除依赖

通过将remove - unused - kernel - packagesremove - new - unused - dependenciesremove - unused - dependencies选项更改为true,可以显式地设置unattended-upgrades 服务来删除未使用的依赖项。删除//以取消注释这些行。

...

// Remove unused automatically installed kernel-related packages
// (kernel images, kernel headers and kernel version locked tools).
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";

// Do automatic removal of newly unused dependencies after the upgrade
Unattended-Upgrade::Remove-New-Unused-Dependencies "true";

// Do automatic removal of unused packages after the upgrade
// (equivalent to apt-get autoremove)
Unattended-Upgrade::Remove-Unused-Dependencies "true";

..
启用自动更新

要启用自动更新,请创建一个新的自动更新文件:/etc/apt/apt.conf.d/20auto-upgrades

nano /etc/apt/apt.conf.d/20auto-upgrades
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
APT::Periodic::AutocleanInterval "7";

Update-Package-Lists :1启用自动更新,0禁用。

Unattended-Upgrade :1启用自动升级,0禁用。

AutocleanInterval :启用X天自动清理包。上面的配置表示系统每 7 天清除一次下载存档

启用自动重启

通过删除前导斜杠来取消注释行,并将false更改为true,如下所示:

Unattended-Upgrade::Automatic-Reboot "true";
测试配置
sudo unattended-upgrades --dry-run --debug

更新基于 Redhat7 的系统

对于基于Red hat的系统(包括CentOS和Oracle Linux),在安装过程中不存在自动更新机制。因此,使用默认配置,需要自己执行更新:

sudo yum upgrade

有时,您可能只想查看是否有任何与安全相关的更新可以安装。运行以下命令:

sudo yum updateinfo list updates security

如果您只想安装安全更新,则运行以下命令:

sudo yum upgrade --security
CentOS 7 自动更新
sudo yum install yum-cron
sudo systemctl enable --now yum-cron

要配置它,请进入/etc/yum目录并编辑yum-cron.conf文件。在文件的顶部,您会看到:

[commands]
# What kind of update to use:
# default = yum upgrade
# security = yum --security upgrade
# security-severity:Critical = yum --sec-severity=Critical
upgrade
# minimal = yum --bugfix update-minimal
# minimal-security = yum --security update-minimal
# minimal-security-severity:Critical = --sec-severity=Critical
update-minimal
update_cmd = default

这里列出了我们可以进行的各种类型的升级。最后一行显示我们准备更新所有内容。

假设您只想自动应用安全更新。只需将最后一行更改为:

update_cmd = security

在第 15 和 20 行,您将看到以下行:

download_updates = yes
apply_updates = no

这表明在默认情况下,yum-cron只设置为自动下载更新,而不是安装更新。

如果您希望自动安装更新,请将apply_updates参数更改为yes.

与 Ubuntu 不同,没有设置可以让系统在更新后自动重启

email行设置为向root用户发送消息。如果您想在自己的帐户上接收消息,请在这里更改。

#要连接到以发送电子邮件的主机的名称。 
email_host = localhost

要查看邮件,您需要安装一个邮件阅读器程序(如果还没有安装的话)。(如果您在安装操作系统时选择了最小安装,则没有安装。)你最好的选择是安装mutt,像这样:

sudo yum install mutt

与所有操作系统一样,某些更新将需要重新启动系统。

如何知道何时需要重新启动系统?当然是使用needs-restart命令。不过,首先需要确保在系统上安装了needs-restart:

sudo yum install yum-utils

安装包后,有3种方式使用需要重启。如果您只是在没有任何选项开关的情况下运行该命令,您将看到需要重新启动的服务以及需要您重新启动计算机的软件包。您还可以使用 -s 或 -r 选项,如下所示:

sudo needs-restarting 这显示了需要重新启动的服务,以及系统可能需要重新启动的原因。

sudo needs-restarting -s 这仅显示需要重新启动的服务。

sudo needs-restarting -r 这仅显示需要重新启动系统的原因。

更新基于 Red Hat 8 的系统

yum和dnf之间的区别在于,dnf具有不同的自动更新机制。现在不安装yum-cron包,而是安装dnf-automatic包,如下所示:

sudo dnf install dnf-automatic

/etc/dnf目录中,将看到该automatic.conf文件,按照跟CentOS 7 配置 yum-cron.conf 文件相同的方式配置该文件。dnf-automatic不像旧的 yum-cron 那样作为 cron job工作,而是使用 systemd 计时器。首次安装dnf-automatic时,计时器被禁用。通过运行以下代码行启用它并启动它:

sudo systemctl enable --now dnf-automatic.timer

输入以下代码行来验证它是否在运行:

sudo systemctl status dnf-automatic.timer

如果它成功启动,您应该会看到如下内容:

[donnie@redhat-8 ~]$ sudo systemctl status dnf-automatic.timer
dnf-automatic.timer - dnf-automatic timer
Loaded: loaded (/usr/lib/systemd/system/dnf-automatic.timer;
enabled; vendor preset: disabled)
Active: active (waiting) since Sun 2019-07-07 19:17:14 EDT; 13s
ago
Trigger: Sun 2019-07-07 19:54:49 EDT; 37min left
Jul 07 19:17:14 redhat-8 systemd[1]: Started dnf-automatic timer.
[donnie@redhat-8 ~]$

服务管理

禁用未使用的服务和端口,将它们从启动任务中删除。

备忘单

Systemd 服务命令

Command Description
systemctl stop service-name 停止运行服务
systemctl start service-name 启动服务
systemctl restart service-name 重启正在运行的服务
systemctl reload service-name 重新加载服务的所有配置文件
systemctl status service-name 显示服务是否正在运行
systemctl enable service-name 在启动时启动服务
systemctrl disable service-name 启动时禁用服务
systemctl show service-name 显示服务信息
systemctl -H target command service-name 远程执行systemctl命令

Systemd 信息命令

Command Description
systemctl list-dependencies 显示单元依赖项
systemctl list-sockets 列出套接字活动
systemctl list-jobs 查看活动的systemd作业
systemctl list-unit-files 列出服务的开机状态
systemctl list-units 列出默认目标(如运行级别)

更改系统状态

Command Description
systemctl reboot 重启系统
systemctl poweroff 关机
systemctl emergency 紧急模式
systemctl default 默认模式

查看日志消息

Command Description
journalctl 显示所有收集的日志消息
journalctl -u sshd.service 查看 sshd 服务消息
journelctl -f 跟踪日志文件
journelctl -k 仅显示内核消息

Targets

systemd 明确定义了一类不同的单元(类型为 .target)作为常见操作模式的众所周知的标记。然而,除了依赖管理之外,target并没有其他单元所拥有的真正的超级能力。

唯一需要真正了解的target是用于日常使用的 multi-user.target 和 graphics.target,以及用于访问单用户模式的 rescue.target。要更改系统的当前操作模式,请使用 systemctl isolate 命令

sudo systemctl isolate multi-user.target

之所以叫isolate子命令,是因为它激活指定的target及其依赖项,但停用所有其他单元。

查看系统默认启动的target:

systemctl get-default
Set Default Target
sudo systemctl set-default multi-user.target
查看系统的所有可用targets
systemctl list-units --type=target 
单元之间的依赖关系

单个单元可以用以下设置关闭这些假设:

DefaultDependencies=false
向服务添加依赖项

将 my.local.service 添加为 multi-user.target 的依赖项,因此当系统处于多用户模式时,将启动此服务

sudo systemctl add-wants multi-user.target my.local.service

管理服务

仅显示已加载和活动的服务
systemctl list-units --type=service
systemctl -t service --state=active 
systemctl list-unit-files --state=enabled

所有已安装的单元文件,无论它们是否处于活动状态:

systemctl list-unit-files --type=service
启用/禁用引导启动
systemctl enable/disable smb
检查服务状态
systemctl status smb
no pager
systemctl -a --no-pager
systemctl -a | grep .
显示已安装的所有服务文件
systemctl list-unit-files

如果你编辑一个/lib/systemd/system文件(一个单元文件/一个服务文件),那么你需要使用这个命令将它重新加载到 systemd 中,之后你可以对该服务执行“restart”、“start”、“stop”等操作:

systemctl --system daemon-reload
查看 systemd 信息
// Some cosystemctl list-dependencies : Show a unit’s dependencies
systemctl list-sockets : List sockets and what activates
systemctl list-jobs : View active systemd jobs
systemctl list-unit-files : See unit files and their states
systemctl list-units : Show if units are loaded/active
systemctl get – default : List default target (like run level)
管理临时文件 (/tmp)
systemd-tmpfiles

创建系统服务

公共单元文件路径
/usr/lib/systemd/system
/lib/systemd/system
/etc/systemd/system
/run/systemd/systemcreating a unit file
创建一个单元文件
cd /etc/systemd/system

创建一个名为 your-service.service 的文件并包含以下内容:

[Unit]
Description=<description about this service>

[Service]
User=<user e.g. root>
WorkingDirectory=<directory_of_script e.g. /root>
ExecStart=<script which needs to be executed>
Restart=always

[Install]
WantedBy=multi-user.target

对于包含虚拟环境的 Python 特定项目:

[Unit]
Description=<project description>

[Service]
User=<user e.g. root>
WorkingDirectory=<path to your project directory containing your python script>
ExecStart=/home/user/.virtualenv/bin/python main.py
Restart=always
# replace /home/user/.virtualenv/bin/python with your virtualenv and main.py with your script

[Install]
WantedBy=multi-user.target

OR

[Unit]
Description=<project description>

[Service]
User=<user e.g. root>
WorkingDirectory=<path to your project directory>
ExecStart=/bin/bash -c 'cd /home/ubuntu/project/ && source venv/bin/activate && python test.py'

[Install]
WantedBy=multi-user.target
激活并启动新服务

重新加载服务文件以包含新服务

sudo systemctl daemon-reload

启动你的服务

sudo systemctl start your-service.service

检查服务状态

sudo systemctl status example.service

在每次重新启动时启用你的服务

sudo systemctl enable example.service

在每次重新启动时禁用你的服务

sudo systemctl disable example.service

开关机控制

禁用Ctrl+Alt+Del (Systemd)

systemctl mask ctrl-alt-del.target
systemctl daemon-reload

Grub加固

GRUB是入侵Linux系统最简单的方法!

1 .在忘记密码的情况下进入Linux 系统的第一个选项是在系统启动期间编辑内核引导文件(通常通过按“e”触发)。然后找到"ro"这一行, 在倒数第二行,把quiet 后面的参数修改为:quiet splash rw init=/bin/bash

2 .第二种选择是使用Recovery Mode

基于 Debian

禁用Recovery
root@debian:~# nano /etc/default/grub
....
# Uncomment to disable generation of recovery mode menu entries
GRUB_DISABLE_RECOVERY="true"
....
root@debian:~# update-grub
密码保护

为grub生成密码:

grub-mkpasswd-pbkdf2

系统将提示您为GRUB创建和验证密码

一旦完成,该命令将生成一个散列密码。散列将以grub开头,以一长串字符结尾。你需要把它复制下来。

sudo nano /etc/grub.d/00_header

在该文件的底部,粘贴以下内容:

cat << EOF
set superusers="admin"
password_pbkdf2 admin HASH
EOF

其中 HASH 是之前生成的哈希。

保存并关闭该文件。用以下命令更新GRUB:

sudo update-grub

重新启动系统。启动画面出现后不久,系统会提示您输入用户名。在上面的配置中,我们创建了admin用户,这将需要我们在grub-mkpasswd-pbkdf2命令中添加的密码。输入用户名后,按 Enter,系统将提示您输入密码。

成功输入密码后,您会发现自己处于单用户模式(如果您选择了该引导方法)或登录提示。

基于 Redhat 7

生成密码

grub2-mkpasswd-pbkdf2

输入密码,它会生成你的密码的hash

nano /etc/grub.d/10_linux

打开这个文件后,到文件的末尾,键入下面内容,并更改您想要给出的用户名,确保用户名已经在这个服务器系统中创建,并将密码放在username后面的位置,然后将[HASH]替换为您得到的hash。

cat << EOF
set superusers="root"
password_pbkdf2 root [HASH]
EOF

保存文件

基于 Redhat 8

grub2-setpassword

该命令生成一个哈希密码,存储在/boot/grub2/user.cfg文件中。

默认情况下user.cfg不存在。如果您之前已经使用命令grub2-setpassword生成了密码,那么该文件将存在,否则该命令将生成一个新文件。

使用cat命令查看生成的密码

cat /boot/grub2/user.cfg 

重新创建GRUB2配置文件

grub2-mkconfig -o /boot/grub2/grub.cfg

ok,我们已经成功设置了grub2密码

内核参数集

命名空间隔离

命名空间是在 Linux 内核版本 2.4.19 中引入的一项内核安全功能,可以追溯到 2002 年。命名空间允许进程拥有自己的一组计算机资源,而其他进程无法看到。当您可能有多个客户在同一台服务器上共享资源时,它们特别方便。每个用户的进程都有自己的命名空间。目前,有七种类型的命名空间:

**Mount (mnt): **这是最初的命名空间,它是在 Linux 内核 2.4.19 中引入的。当时,这是唯一的命名空间。这允许每个进程拥有自己的根文件系统,其他进程无法看到,除非您选择共享它。这是防止信息泄露的好方法。

UTS: UTS 命名空间允许每个进程拥有自己唯一的主机名和域名。

PID: 每个正在运行的进程都可以有自己的一组 PID 编号。PID 命名空间可以嵌套,以便父命名空间可以看到子命名空间的 PID。(请注意,子命名空间无法看到父命名空间。)

Network (net): 这允许您为每个进程创建一个完整的虚拟网络。每个虚拟网络都可以有自己的子网、虚拟网络接口、路由表和防火墙。

**Interprocess Communication (ipc): **防止两个进程共享相同的内存空间,从而防止数据泄漏。每个正在运行的进程都可以访问自己的内存空间,但是其他进程会被阻塞。

**Control group (cgroup): **此命名空间隐藏进程所属的cgroup的标识。

User : User命名空间允许用户在不同的进程上拥有不同级别的特权。例如,一个用户可以在一个进程上拥有根级别的权限,但在另一个进程上只有普通用户权限。

要查看这些命名空间,只需进入/proc文件系统中任意一个编号的目录,并查看ns目录的内容。

控制组 (cgroups)

控制组,通常称为cgroup,早在2010年Red Hat Enterprise Linux 6中就引入了。最初,它们只是一个附加功能,用户必须通过一些步骤手动创建它们。如今,随着systemd init系统的出现,cgroup已经成为操作系统中不可分割的一部分,默认情况下每个进程都在自己的cgroup中运行。

使用 cgroups,进程在它们自己的内核空间和内存空间中运行。如果需要,管理员可以轻松配置 cgroup 以限制进程可以使用的资源,可以对 cpu,内存等资源实现精细化的控制。这不仅有利于安全,也有利于调整系统性能。

它实际上只是为了特定目的而组合在一起的进程的集合。以下是你可以用cgroups做的事情:

设置资源限制:对于每个 cgroup,您可以设置 CPU 使用率、I/O 使用率和内存使用率的资源限制。

优化资源:可以对疯狂占用资源的用户设置限制。。

冻结、检查点和重新启动:这些功能便于故障排除。它们允许您停止进程、拍摄系统状态的快照以及从备份中恢复系统状态。

对进程设置资源限制

默认情况下,系统上的每个 cgroup 都没有定义的资源限制。定义它们的第一步是启用对 CPU 使用率、内存使用率和 I/O 使用率的控制。我们可以通过手动编辑我们想要限制的每个服务的 systemd 服务文件来做到这一点,但是只运行一个 systemctl 命令会更容易,如下所示:

sudo systemctl set-property httpd.service MemoryAccounting=1
CPUAccounting=1 BlockIOAccounting=1

该命令在 Ubuntu 机器上是相同的,只是我们将使用 apache2.service 而不是 httpd.service

当我们查看/etc/systemd/system.control目录时,我们会看到我们已经创建了一个 httpd.service.d 目录。在该目录中是打开我们的会计功能的文件:

当我们查看/etc/systemd/system。控制目录,我们将看到我们已经创建了一个httpd.service.d目录。在该目录中是打开我们的控制功能的配置文件:

现在我们已经启用了对 Apache 服务的控制,我们可以对其设置一些资源限制。(默认情况下,没有限制。)假设我们希望将 Apache 限制为仅 40% 的 CPU 使用率和 500 MB 的内存使用率。我们将使用以下命令设置这两个限制:

sudo systemctl set-property httpd.service CPUQuota=40% MemoryLimit=500M

此命令在/etc/systemd/system.control/httpd.service.d/目录中创建了另外两个文件:

我们可以以同样的方式将资源分配给其他服务。例如,如果这是一个Linux-Apache-MySQL/MariaDB-PHP (LAMP)服务器,我们可以将剩余CPU和内存资源的一部分分配给PHP服务,其余的分配给MySQL/MariaDB服务。

对用户帐户设置资源限制

sudo systemctl set-property user-1001.slice MemoryAccounting=1 CPUAccounting=1 BlockIOAccounting=1

sudo systemctl set-property user-1001.slice CPUQuota=20% MemoryLimit=500M

内核能力(Capabilities)

当您执行 ps aux 命令或 sudo ps aux 命令(如果您已使用 hidepid=1 或 hidepid=2 选项挂载 /proc)时,您将看到许多由 root 用户拥有的进程。这是因为这些进程必须访问某种非特权用户无法访问的系统资源。但是,让服务以完全 root 权限运行可能会带来一些安全问题。幸运的是,有一些方法可以缓解这种情况。

功能允许 Linux 内核将 root 用户可以执行的操作划分为不同的单元。即将root的特权分割成不同的能力,每种能力代表一定的特权操作

可以使用以下命令查看功能列表:

man capabilities

查看和设置文件的capabilities

getcap setcap

SECCOMP

Seccomp是一种安全机制,通过禁止在执行过程中进行的系统调用来帮助程序员将自己的程序沙箱化.

https://training.play-with-docker.com/security-seccomp/

进程隔离

阻止用户查看彼此的进程

默认情况下,用户可以使用ps或top等实用程序来查看其他人的进程以及自己的进程。

处理这个问题的最佳方法是使用hidepid选项挂载/proc文件系统。你可以通过在/etc/fstab文件的末尾添加以下行来做到这一点,就像这样:

nano /etc/fstab
proc    /proc   proc    hidepid=2   0   0

然后,像这样重新挂载/proc

sudo mount -o remount proc

现在,任何没有 sudo 权限的用户只能查看自己的进程。

hidepid 选项的三个值如下:

0:这是默认设置,允许所有用户查看彼此的进程。

1:这允许所有用户在 /proc 中查看其他用户的进程目录。但是,用户只能 cd 进入他们自己的进程目录。此外,他们只能使用 ps 或 top 查看自己的进程信息。

2:这隐藏了所有其他用户的进程信息,包括 /proc 中的进程目录。

限制核心转储(Core Dumps)

核心转储是可执行程序的内存。它通常用于确定程序中止的原因。它还可用于从核心文件中收集机密信息。系统提供了为核心转储设置软限制的能力,但是用户可以覆盖这一限制。

对核心转储设置硬限制可防止用户覆盖软变量。如果需要核心转储,请考虑为用户组设置限制。此外,将 fs.suid_dumpable 变量设置为 0 将防止 setuid 程序转储核心。

运行以下命令并验证输出是否匹配:

# grep "hard core" /etc/security/limits.conf /etc/security/limits.d/*
* hard core 0

# sysctl fs.suid_dumpable
fs.suid_dumpable = 0

# grep "fs\.suid_dumpable" /etc/sysctl.conf /etc/sysctl.d/*
fs.suid_dumpable = 0

执行以下命令,检查是否安装了system -coredump:

# systemctl is-enabled coredump.service

如果返回“enabled”或“disabled”,则安装了system -coredump

将以下内容添加到 /etc/security/limits.conf 或 /etc/security/limits.d/* 文件:

* hard core 0

在 /etc/sysctl.conf 或 /etc/sysctl.d/* 文件中设置以下参数:

fs.suid_dumpable = 0

运行以下命令设置内核运行参数:

sysctl -w fs.suid_dumpable=0

如果安装了 systemd-coredump:

编辑/etc/systemd/coredump.conf添加/修改以下行:

Storage=none
ProcessSizeMax=0

运行命令:

systemctl daemon-reload

启用漏洞缓解机制

ASLR

/etc/sysctl.conf/etc/sysctl.d/*文件中设置以下参数:

kernel.randomize_va_space = 2 

运行以下命令设置内核运行参数:

sysctl -w kernel.randomize_va_space=2

prelink是一种修改ELF共享库和ELF动态链接二进制文件的程序,其方式是使动态链接器在启动时执行重定位所需的时间显著减少。

预链接功能可能会干扰 AIDE(文件完整性检测) 的操作,因为它会更改二进制文件。如果恶意用户能够破坏公共库(例如 libc),则预链接还会增加系统的脆弱性

检查预链接是否安装。根据正在使用的包管理器不同,使用下面命令其中一个:

# rpm -q prelink
# dpkg -s prelink

运行以下命令将二进制文件恢复正常:

prelink -ua

使用适当的包管理器或手动安装卸载 prelink:

# yum remove prelink
# apt-get remove prelink
# zypper remove prelink

帐户和密码

用户和组

用户管理

创建用户
useradd [username]

# options
-g   Main user group (gid)
-d   User Home directory, by default located at /home/<UserName>
-m  Create Home directory in case it doesn’t exist.
-s   Assign a specific shell to the user, by default it is /bin/bash.
-M dont create home directory

# example:
useradd -g sector1 -d /home/nicolas -m -s /bin/bash nicolas
sudo useradd -G wheel -m -d /home/frank -s /bin/bash frank


adduser [username]

当命令 useradd 运行系统二进制文件时,命令 adduser 是与 useradd 交互的 perl 脚本。使用 adduser 命令,其优点是自动创建主目录。如果使用命令 adduser 我们需要指定 -m 选项。

添加root用户
useradd -ou 0 -g 0 [username]

添加用户到sudoers组

//usermod -aG [group] [username]
usermod -aG [group1,group2,group3,...] [username]
更改用户主目录
usermod -d [dir] [username]
Lock/Unlock用户
usermod -L [username]
usermod -U [username]
为用户设置新的 UID
usermod -u [username]
删除用户
userdel [username]
密码
set password
passwd [username]
列出当前权限可以运行的命令
sudo -l
sudo -ll
更改用户shell
chsh -s [shell ] [username]
chsh -s /bin/bash hesher
列出允许其他用户执行的命令
sudo -l -U user
sudo命令
Run as root:
sudo COMMAND

 Run as USER:
sudo -u USER COMMAND

Get a shell
sudo -s
sudo -s -u USER
账户Aging
sudo useradd -e 2022-12-31 naizi

可以设置密码过期的帐户被锁定的天数:

sudo usermod -f 5 naizi
帐户到期日期
  -I, --inactive INACTIVE       set password inactive after expiration
  -m, --mindays MIN_DAYS        set minimum number of days before password
  -M, --maxdays MAX_DAYS        set maximum number of days before password
  -W, --warndays WARN_DAYS      set expiration warning days to WARN_DAYS
  -d, --lastday LAST_DAY        set date of last password change to LAST_DAY

chage -M 20 john

chage -E 2020-12-31 charlie
默认账户Aging

仅适用于 Red Hat 或 CentOS。

/etc/default/useradd

# useradd defaults file
GROUP=100
HOME=/home
INACTIVE=-1
EXPIRE=
SHELL=/bin/bash
SKEL=/etc/skel
CREATE_MAIL_SPOOL=yes

Ubuntu也有useradd配置文件,但它不能工作。不管你怎么配置,Ubuntu版本的useradd都不会读取它。因此,关于该文件的描述只适用于Red Hat或CentOS。

登录/注销监控

最近登录信息

last
lastb
lastlog → last time a user has logged in
身份验证日志文件
/var/log/messages
/var/log/syslog
/var/log/secure
/var/log/auth.log

使用 pam 配置密码复杂性

基于 Debian

确保密码满足一定程度的复杂性同样至关重要,可以进一步阻止黑客使用密码暴力破解侵入系统的任何尝试。

一般来说,强密码应该由大写、小写、数字和特殊字符组合而成,长度至少为12-15个字符。

要在 Debian / Ubuntu 系统中加强密码复杂性,您需要安装libpam-pwquality软件包,如下所示:

sudo apt install libpam-pwquality

安装后,转到/etc/pam.d/common-password文件。在其中设置密码策略,默认情况下,文件显示如下:

找到如下行

password   requisite   pam_pwquality.so retry=3

将以下属性添加到该行:

minlen=12 maxrepeat=3 ucredit=-1 lcredit=-1 dcredit=-1 ocredit=-1 difok=4 reject_username enforce_for_root

让我们简述一下这些指令的含义:

retry=3:该选项会提示用户3次退出并返回错误。

minlen=12:这指定密码不能少于 12 个字符。

maxrepeat=3:这意味着密码中最多只能包含 3 个重复字符。

ucredit=-1:该选项要求密码中至少有一个大写字符。

lcredit=-1:该选项要求密码中至少包含一个小写字符。

dcredit=-1:这意味着密码最后应该有一个数字字符。

ocredit=-1:该选项要求密码中至少包含一个特殊字符。

difok=3:这意味着新密码中最多只能有 3 个字符的更改出现在旧密码中。

reject_username:如果密码以正常方式或反向包含用户名,则该选项拒绝密码。

enforce_for_root:即使是 root 用户配置密码,也能确保遵守密码策略。

基于 Redhat

对于 Debian 和 Ubuntu 系统,我们通过修改/etc/pam.d/common-password配置文件来强制执行密码策略。

对于CentOS 7和其他衍生版本,我们将修改/etc/pam.d/system-auth/etc/security/pwquality.conf配置文件。

因此,打开文件:

sudo vim /etc/pam.d/system-auth

找到如下行

password    requisite     pam_pwquality.so try_first_pass local_users_only retry=3 authtok_type=

在该行中附加选项

minlen=12 lcredit=-1 ucredit=-1 dcredit=-1 ocredit=-1 enforce_for_root

完成后,保存密码策略并退出文件。

以后,当您尝试使用不符合强制策略的弱密码创建用户时,您将遇到终端中显示的错误。

配置Root Access

通过将root的加密密码设置为或其他固定的任意字符串,可以完全禁用root登录。在Linux上,passwd -l通过在前面加上一个!加密后的密码,得到相同的结果。和!只是约定;没有软件明确地检查它们。它们的效果来自于它们无效的密码散列。因此,验证root密码的尝试会失败。

确保只有root用户的UID为0
awk -F: '($3 == "0")'  /etc/passwd
转换密码
pwconv - convert to shadow passwords.
pwunconv - convert from shadow passwords.
/etc/shadow 格式
Username
Hashed password
Days since epoch of last password change
Days until change allowed
Days before change required
Days warning for expiration
Days before account inactive
Days since epoch when account expires
Reserved

锁定/解锁密码

passwd -l account
passwd -u account 
将帐号shell设置为no login
/sbin/nologin

使用 chsh 命令
chsh -s SHELL ACCOUNT
chsh -s /sbin/nologin jason

手动添加用户

编辑/etc/passwd为新帐户添加新行。

同样,/etc/group如果您还需要创建新组,编辑它

使用 mkdir 创建用户的主目录。

复制文件/etc/skel到新的主目录。

使用 chown 和 chmod 修复所有权和权限。-R 选项最有用:

cd /home/newusername
chown -R username.group .
chmod -R go=u,go-w .
chmod go= .

使用 passwd 设置密码

Group管理

创建一个新组
groupadd [name]
更改组名称
groupmod -n [new name] [old name] 
更改组 ID
groupmod -q 4000 [group]
chmod g+rwx [group]
chown [user]:[group] [file]
设置 GID
chmod g+s [group]
更改primary group
usermod -g [group] [usename]
groupmod -g [gid] -n [new name] [oldname]
从组中删除用户
gpasswd -d [username] [groupname]
删除组
groupdel [name]
列出所有系统组
cat /etc/groups
列出当前用户组
groups
列出其他帐户的组
groups [username]
ip [username]

密码安全和 Sudoers

在 Linux 和其他类 Unix 操作系统中,只有root用户才能运行所有命令并对系统执行某些关键操作,例如安装和更新、删除软件包、创建用户和组、修改重要的系统配置文件等。

但是,担任root用户角色的系统管理员可以允许其他普通系统用户在sudo命令和一些配置的帮助下运行一些命令,以及执行包括上述操作在内的许多重要系统操作。

或者,也可以由系统管理员共享root用户密码(不推荐这样做),使系统普通用户可以通过su命令访问root用户。

Sudo允许被允许的用户以root(或其他用户)的身份执行命令:

  1. 它读取并解析/etc/sudoers,查找调用用户及其权限,
  2. 然后提示调用用户输入密码(通常是用户的密码,但也可以是目标用户的密码。或者可以使用 NOPASSWD 标签跳过),
  3. 之后,sudo 创建一个子进程,在其中调用setuid()切换到目标用户
  4. 接下来,它执行一个 shell 或在上面的子进程中作为参数给出的命令。

登录安全

限制 su 命令

su命令允许用户以另一个用户的身份运行命令或shell。该程序已被sudo所取代,sudo允许对特权访问进行更细粒度的控制。正常情况下,su命令可以由任何用户执行。通过取消 /etc/pam.d/su中的pam_wheel.so的注释,su命令只允许wheel组中的用户执行su。

将以下行添加到/etc/pam.d/su文件中:

auth required pam_wheel.so use_uid

在/etc/group文件的wheel语句中创建以逗号分隔的用户列表:

wheel:x:10:root,<user list>

密码安全

到期

将PASS_MAX_DAYS参数设置为符合/etc/login.defs中的site policy

PASS_MAX_DAYS 365

修改密码设置为匹配的用户:

chage --maxdays 365 <user>

您也可以直接在/etc/shadow中检查此设置。对于所有有密码的用户,第五个字段应该是365或更少。

值-1将禁用密码过期。此外,密码过期时间必须大于密码修改间隔的最短天数,否则用户将无法更改密码。

密码更改最低限额

/etc/login.defs中的PASS_MIN_DAYS参数允许管理员阻止用户修改密码,直到距离用户上次修改密码的最小天数过去。PASS_MIN_DAYS参数建议设置为7天及以上

/etc/login.defs中将 PASS_MIN_DAYS 参数设置为 7:

PASS_MIN_DAYS 7

修改密码设置为匹配的用户:

 chage --mindays 7 <user>
到期警告日

/etc/login.defs中的PASS_WARN_AGE参数允许管理员通知用户,他们的密码将在指定的天数内过期。PASS_WARN_AGE参数建议设置为7天以上。

PASS_WARN_AGE 7
chage --warndays 7 <user>
未激活帐户密码锁定

在一段时间内未激活的用户帐户可以被自动禁用。建议禁用密码过期30天内未激活的帐户。

找到这些帐户:

useradd -D | grep INACTIVE

将默认密码不活动时间设置为30天。

useradd -D -f 30

修改密码设置为匹配的用户:

chage --inactive 30 <user>
用户shell超时

编辑 /etc/bashrc 和 /etc/profile 文件(以及系统支持的任何其他 shell 的相应文件)并添加或编辑任何 umask 参数,如下所示:

TMOUT=900
限制 Root 登录到系统控制台

文件/etc/securetty包含可以直接以 root 身份登录的有效终端列表。

将以下行添加到/etc/pam.d/su文件中:

auth required pam_wheel.so use_uid

在/etc/group文件的wheel语句中创建以逗号分隔的用户列表:

wheel:x:10:root,<user list>
检查空密码字段

密码字段为空的帐户意味着任何人都可以在不提供密码的情况下以该用户身份登录。

执行以下命令,查看是否无输出。

awk -F: '($2 == "" ) { print $1 " does not have a password "}' /etc/shadow

如果/etc/shadow文件中有任何账户没有密码,执行以下命令锁定该账户,直到确定其没有密码的原因。

passwd -l <username>
检查根路径完整性

root 用户可以在系统上执行任何命令,如果PATH设置不正确,可能在无意中被欺骗执行程序。

在root的可执行路径中包含当前工作目录(.)或其他可写目录很可能使攻击者通过强迫以root身份操作的管理员执行特洛伊木马程序来获得超级用户访问权限。

运行以下脚本,确认没有返回结果:

#!/bin/bash
if [ "$(echo "$PATH" | grep ::)" != "" ]; then
 echo "Empty Directory in PATH (::)"
fi
if [ "$(echo "$PATH" | grep :$)" != "" ]; then
 echo "Trailing : in PATH"
fi
p=$(echo "$PATH" | sed -e 's/::/:/' -e 's/:$//' -e 's/:/ /g')
set -- $p
while [ "$1" != "" ]; do
 if [ "$1" = "." ]; then
 shift
 continue
 fi
 if [ -d "$1" ]; then
 dirperm=$(ls -ldH "$1" | cut -f1 -d" ")
 if [ "$(echo "$dirperm" | cut -c6)" != "-" ]; then
 echo "Group Write permission set on directory $1"
 fi
 if [ "$(echo "$dirperm" | cut -c9)" != "-" ]; then
 echo "Other Write permission set on directory $1"
 fi
 dirown=$(ls -ldH "$1" | awk '{print $3}')
 if [ "$dirown" != "root" ] ; then
 echo "$1 is not owned by root"
 fi
 else
 echo "$1 is not a directory"
 fi
 shift
done

给用户 Sudo 权限

基于 Debian
sudo usermod -aG sudo username

也可以使用 gpasswd 命令:

sudo gpasswd -a username sudo
基于 Redhat

在 CentOS 上,这通常是 wheel 组而不是 sudo 组:

sudo usermod -aG wheel username

或者,使用 gpasswd:

sudo gpasswd -a username wheel

编辑 sudoers 文件

sudo命令是通过位于/etc/sudoers的文件配置的

切勿使用普通文本编辑器编辑此文件!始终使用 visudo 命令!

因为 /etc/sudoers 文件中不正确的语法可能会使您无法获得提升的权限,所以使用 visudo 命令编辑文件很重要。

visudo 命令会像平常一样打开一个文本编辑器,但它会在保存时验证文件的语法。这可以防止配置错误阻止 sudo 操作。

visudo

如果您想更改编辑器,请执行以下命令:

sudo update-alternatives --config editor
默认行

第一行“Defaults env_reset”重置终端环境以删除所有用户变量。这是一种安全措施,用于清除sudo会话中潜在的有害环境变量。

第二行Defaults mail_badpass告诉系统将错误的sudo密码尝试通知发送到配置的mailto用户。默认情况下,这是root帐户。

第三行以“Defaults secure_path=…”开头,指定sudo操作将使用的PATH(操作系统将在文件系统中查找应用程序的位置)。这可以防止使用可能有害的用户路径。

用户权限行

第四行规定了root用户的sudo权限,这与前面几行不同。让我们来看看不同的字段是什么意思:

格式:

user host=(run_as_user : run_as_group) command

root ALL=(ALL:ALL) ALL

第一个字段表示规则将应用于的用户名(root)

demo ALL=(ALL:ALL) ALL

第一个“ALL”表示该规则适用于所有主机。

demo ALL=(ALL:ALL) ALL

这个“ALL”表示root用户可以作为所有用户运行命令。

demo ALL=(ALL:ALL) ALL

此“ALL”表示 root 用户可以作为所有组运行命令。

demo ALL=(ALL:ALL) ALL

最后一个“ALL”表示这些规则适用于所有命令。这意味着我们的 root 用户可以使用 sudo 运行任何命令,只要他们提供密码。

设置自定义规则

通过使用各种“别名”对事物进行分组,可以更轻松地组织 sudoers 文件。

例如,我们可以创建三个不同的用户组,具有重叠的成员:

User_Alias      GROUPONE = abby, brent, carl
User_Alias      GROUPTWO = brent, doris, eric
User_Alias      GROUPTHREE = doris, felicia, grant

组名必须以大写字母开头。然后,我们可以通过创建如下规则来允许 GROUPTWO 的成员更新 apt 数据库:

GROUPTWO    ALL = /usr/bin/apt-get update

如果我们没有像上面那样指定user/group,sudo 默认为 root 用户

我们可以允许 GROUPTHREE 的成员通过创建“命令别名”并在 GROUPTHREE 的规则中使用它来关闭和重新启动机器:

Cmnd_Alias      POWER = /sbin/shutdown, /sbin/halt, /sbin/reboot, /sbin/restart
GROUPTHREE  ALL = POWER

我们创建一个名为 POWER 的命令别名,其中包含关闭和重新启动机器的命令。然后我们允许 GROUPTHREE 的成员执行这些命令。

Run As

我们还可以创建“Run as”别名,它可以将指定用户执行命令的规则部分替换为:

Runas_Alias     WEB = www-data, apache
GROUPONE    ALL = (WEB) ALL

这将允许任何属于 GROUPONE 的成员以 www-data 用户或 apache 用户的身份执行命令。

sudo 没有密码

如果我们想让用户在不需要输入密码的情况下以root权限执行它,我们可以制定如下规则:

/user ALL=(ALL) NOPASSWD: ALL
GROUPONE    ALL = NOPASSWD: /usr/bin/updatedb
Tags

一个标签与规则的其余部分相关,除非后面被它的“孪生”标签推翻。

GROUPTWO    ALL = NOPASSWD: /usr/bin/updatedb, PASSWD: /bin/kill

另一个有用的标签是NOEXEC,可用于防止某些程序中的一些危险行为。

例如,某些程序,如“less”,可以通过在其界面中键入以下命令来生成其他命令:

!command_to_run

这基本上执行用户赋予它的任何命令,其权限与运行“less”的权限相同,这可能非常危险。

为了限制这一点,我们可以使用这样的一行:

username  ALL = NOEXEC: /usr/bin/less
禁用 sudo 计时器

为了设置一个与默认值(15分钟)不同的超时(全局),你可以编辑/etc/sudoers:

sudo visudo                                       # opens /etc/sudoers for editing
# change the following line:
# Defaults    env_reset
# to:
Defaults        env_reset,timestamp_timeout=30    # timeout in minutes

或者:

cd /etc/sudoers.d
sudo visudo -f username
Defaults        env_reset,timestamp_timeout=30    # timeout in minutes

特殊值:

  • -1: 没有超时
  • 0: 每次都会提示

访问控制和所有权

chmod

chmod 递归
chmod -R g+w mydir
从另一个文件复制权限
chmod --reference=filea fileb

Sticky Bit

限制重命名/删除文件

Sticky Bit是设置在文件或目录上的权限位,只允许文件/目录的所有者或根用户删除或重命名文件。没有其他用户被赋予删除其他用户创建的文件的权限。

现在,使用 chmod 命令的 +t 标志打开/关闭目录上的Sticky Bit

# turn on
chmod +t allAccess/

# turn off
chmod -t allAccess/

若要在具有数字权限格式的文件上设置Sticky Bit,请先指定1,然后再指定其他编号权限,如下所示。下面的示例将rwx权限授予用户、组和其他用户(还将Sticky Bit添加到目录中)。

chmod 1777 dir

chown & chgrp

更改用户/组所有权

chown 命令更改文件的所有权,而 chgrp 命令更改其组所有权。chown 和 chgrp 的语法反映了 chmod 的语法,只是第一个参数分别是新的所有者或组。

sudo chown -R matt ~matt/restore
sudo chgrp -R staff ~matt/restore

chown 可以使用以下语法一次更改文件的所有者和组

chown user:group file
sudo chown -R matt:staff ~matt/restore
创建共享目录
sudo mkdir marketing
sudo chown nobody:marketing marketing
sudo chmod 770 marketing

# or set SGID
sudo chmod 2770 marketing

# set sticky bit
sudo chmod 3770 marketing

drwxrws--T. 2 nobody marketing 30 Nov 13 16:03 marketing

UMASK

分配默认权限

您可以使用内置的 shell 命令 umask 来影响授予您创建的文件的默认权限。每个进程都有自己的 umask 属性;shell 的内置 umask 命令设置 shell 自己的 umask,然后由您运行的命令继承。

ACL(访问控制列表)

确保使用 ACL 支持挂载的文件系统
mount -o acl /path/to/dev /path/to/mount
tune2fs -o acl /path/to/dev

# check:
tune2fs -l /path/to/dev | grep options
ACL 的类型
Access:控制对特定文件或目录的访问。

Default:仅用于目录。没有访问规则的文件使用默认的ACL规则。不具有追溯力。可选的。
创建 ACL

setfacl和getfacl分别用于建立ACL和显示ACL。

setfacl -m ACL FILE_OR_DIRECTORY

用户和组可以通过名称或UID/GID进行标识。ACL可以包含的条目的确切数量因文件系统实现而异,但通常至少为32个。

User ACLs / Rules
tfacl -m u:jason:rwx start.sh
setfacl -m u:sam:xr start.sh
Group ACLs / Rules
g:gid:perms Sets the access ACL for a group.
setfacl -m g:sales:rw sales.txt
Mask ACLs / Rules
m:perms >>> Sets the effective rights mask.
setfacl -m m:rx sales.txt
Other ACLs / Rules
o:perms >>> Sets the access ACL for others.
setfacl -m o:r sales.txt
一次创建多个 ACL
setfacl -m u:bob:r,g:sales:rw sales.txt
默认 ACL
d:[ugo]:perms  >>> Sets the default ACL.
setfacl -m d:g:sales:rw sales
递归设置 ACL (-R)
setfacl -R -m g:sales:rw sales
删除 ACL
setfacl -x ACL FILE_OR_DIRECTORY
setfacl -x u:jason sales.txt
setfacl -x g:sales sales.txt
setfacl -b sales.txt
查看 ACL
getfacl sales.txt
备份启用 ACL 的文件
tar cJvf new_perm_dir_backup.tar.xz new_perm_dir/ --
acls

tar xJvf new_perm_dir_backup.tar.xz --acls
new_perm_dir/
检测带有acl的文件

demo commands:

#为用户添加权限
setfacl -m "u:user:permissions" /path/to/file
#为组添加权限
setfacl -m "g:group:permissions" /path/to/file
#允许所有文件或目录从它所在的目录继承 ACL 条目
setfacl -dm "entry" /path/to/dir
#删除特定条目
setfacl -x "entry" /path/to/file
#删除所有条目
setfacl -b path/to/file

文件属性

Linux定义了一组补充标志,可以在文件上设置这些标志以请求特殊处理。例如,a标志使文件只能追加,而i标志使其不可更改和不可删除

Linux使用lsattr和chattr命令来查看和更改文件属性

查看属性
lsattr /etc/motd
修改属性
+ adds attributes.
- removes attributes.
= sets the exact attributes.

chattr +a /var/log/messages
chattr -a /var/log/messages

文件系统安全

目录安全挂载选项

nodev选项

nodev挂载选项指定文件系统不能包含特殊设备。

/tmp

由于/tmp文件系统不支持设备,因此设置该选项以确保用户不能尝试在/tmp中创建块或字符特殊设备。

编辑/etc/fstab文件并添加nodev到 /tmp分区的第四个字段(安装选项)。

运行以下命令重新挂载/tmp

# mount -o remount,nodev /tmp
/var/tmp
mount | grep /var/tmp

编辑/etc/fstab文件,在第四个字段中添加nodev

# mount -o remount,nodev /var/tmp
/hom
mount | grep /home

编辑/etc/fstab文件,在第四个字段中添加nodev

# mount -o remount,nodev
dev/shm
mount | grep /dev/shm

编辑/etc/fstab文件,在第四个字段中添加nodev

# mount -o remount,nodev
可移动介质分区

运行以下命令,并验证在所有可移动介质分区上设置了nodev选项

mount

编辑/etc/fstab文件,在第四个字段中添加nodev

nosuid 选项

通过nosuid选项,可以阻止用户在光驱、软驱或者U盘上运行set-uid权限的程序

/tmp

如果/tmp存在分区,请运行以下命令并验证该nosuid选项是否设置为/tmp:

# mount | grep /tmp

编辑/etc/fstab文件并添加nosuid/tmp分区的第四个字段(挂载选项)运行以下命令重新挂载/tmp

#mount -o remount,nosuid /tmp

/var/tmp
mount | grep /var/tmp

编辑/etc/fstab文件并添加nosuid到第四个字段:

# mount -o remount,nosuid
/dev/shm
mount | grep /dev/shm

编辑/etc/fstab文件并添加nosuid到第四个字段:

# mount -o remount,nosuid /dev/shm
可移动介质分区

运行以下命令并验证是否nosuid在所有可移动媒体分区上设置了该选项

mount

编辑/etc/fstab文件并添加nosuid到第四个字段

noexec 选项

该挂载点里的文件(注意不是目录)即使给了x权限,都不能直接运行

/var/tmp
mount | grep /var/tmp

编辑/etc/fstab文件并添加noexec到第四个字段:

# mount -o remount,noexec /var/tmp
/dev/shm
mount | grep /dev/shm

编辑/etc/fstab文件并添加noexec到第四个字段:

#mount -o remount,noexec /dev/shm
可移动介质分区

运行以下命令并验证是否noexec在所有可移动媒体分区上设置了该选项

mount

编辑/etc/fstab文件并添加noexec到第四个字段

World-writable目录上的Sticky Bit

运行以下命令验证没有设置Sticky Bit的World-writable目录:

df --local -P | awk {'if (NR!=1) print $6'} | xargs -I '{}' find '{}' -xdev -type d \( -perm -0002 -a ! -perm -1000 \) 2>/dev/null

不应返回任何输出

运行以下命令设置所有World-writable目录的Sticky Bit

df --local -P | awk {'if (NR!=1) print $6'} | xargs -I '{}' find '{}' -xdev -type d -perm -0002 2>//dev/null | xargs chmod a+t

禁用自动挂载

执行以下命令检查是否开启了autofs:

systemctl is-enabled autofs

禁用 autofs:

systemctl disable autofs

文件系统完整性

创建审计数据库

安装AIDE:

apt install aide aide-common

启动数据库

aideinit

检查完整性

aide --check

如果有变化,我们将看到一个警告

检查aide DB后更新aide DB

/aide -c aide.conf --update

配置文件

conf file: /etc/aide.conf

log file: /etc/log/aide

db: /etc/lib/aid

scheduling

确定是否计划了一个cron作业来运行aide检查:

crontab -u root -e

将以下行添加到 crontab:

0 5 * * * /usr/bin/aide.wrapper --config /etc/aide/aide.conf --check

文件系统权限

/etc/passwd 的权限

chown root:root /etc/passwd
chmod 644 /etc/passwd

/etc/shadow 的权限

chown root:root /etc/shadow
chown root:shadow /etc/shadow
chmod o-rwx,g-wx /etc/shadow

/etc/group 的权限

chown root:root /etc/group
chmod 644 /etc/group

/etc/gshadow 的权限

chown root:root /etc/gshadow
chown root:shadow /etc/gshadow
chmod o-rwx,g-rw /etc/gshadow

/etc/passwd 备份文件的权限

chown root:root /etc/passwd-
chmod u-x,go-rwx /etc/passwd

World-writeable文件

执行以下命令,检查是否有文件返回

df --local -P | awk '{if (NR!=1) print $6}' | xargs -I '{}' find '{}' -xdev -type f -perm -0002

可以为每个分区手动运行以下命令

find [partition] -xdev -type f -perm -0002

检查Unowned 文件或目录

执行以下命令,检查是否有文件返回

df --local -P | awk {'if (NR!=1) print $6'} | xargs -I '{}' find '{}' -xdev -nouser

可以为每个分区手动运行以下命令

find [partition] -xdev -nouser

检查未分组的文件或目录

df --local -P | awk '{if (NR!=1) print $6}' | xargs -I '{}' find '{}' -xdev -nogroup
find [partition] -xdev -nogroup

审计 SUID/SGID 可执行文件

运行以下命令列出 SUID 文件:

df --local -P | awk '{if (NR!=1) print $6}' | xargs -I '{}' find '{}' -xdev -type f -perm -4000
df --local -P | awk '{if (NR!=1) print $6}' | xargs -I '{}' find '{}' -xdev -type f -perm -2000
find [partition] -xdev -type f -perm -4000
find [partition] -xdev -type f -perm -2000

添加/删除 SUID/SGID 属性

添加Setuid和Setgid属性

chmod ug+s /path/to/file
chmod 6755 /path/to/file

删除 Setgid 属性

chmod g-s /path/to/file
chmod 0755 /path/to/file

沙箱

chroot

chroot命令在Linux/Unix系统中用于更改根目录。Linux/Unix等系统中的每个进程/命令都有一个当前的工作目录,称为根目录。它更改当前运行的进程及其子进程的根目录。

在这种修改过的环境中运行的进程/命令不能访问根目录以外的文件。这种修改后的环境称为“chroot jail”或“jailed目录”。允许某些root用户和特权进程使用chroot命令。

基于systemv

首先,创建一个目录以将进程的文件系统设置为根目录:

<em>#mkdir /chroot</em>

接下来,在其中创建所需的目录。

<em>#mkdir /chroot/{lib,lib64,bin,etc}</em>

现在,最重要的一步是复制可执行文件和库。要在chroot中获取 shell ,您还需要/bin/bash

cp -v /bin/{bash,ls} /chroot/bin

要查看此脚本所需的库,运行以下命令:

#ldd /bin/bash
linux-vdso.so.1 (0x00007fff70deb000)
libncurses.so.5 => /lib/x86_64-linux-gnu/libncurses.so.5 (0x00007f25e33a9000)
libtinfo.so.5 => /lib/x86_64-linux-gnu/libtinfo.so.5 (0x00007f25e317f000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f25e2f7a000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f25e2bd6000)
/lib64/ld-linux-x86-64.so.2 (0x00007f25e360d000)
 
#ldd /bin/ls
linux-vdso.so.1 (0x00007fff4f8e6000)
libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007f9f00aec000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9f00748000)
libpcre.so.3 => /lib/x86_64-linux-gnu/libpcre.so.3 (0x00007f9f004d7000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f9f002d3000)
/lib64/ld-linux-x86-64.so.2 (0x00007f9f00d4f000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f9f000b6000)

现在,根据需要将这些文件复制到/chroot的**liblib64中。

复制完所有必要的文件后,就该进入chroot目录了。

sudo chroot /chroot/ /bin/bash

系统将提示您在虚拟环境中运行一个shell。在这里,除了ls,没有什么要运行的,但是它已经将这个进程的根文件系统更改为/chroot。

要获得功能更全的环境,您可以使用debootstrap实用程序来引导一个基本的Debian系统:

debootstrap --arch=amd64 unstable my_deb/

它将下载一个最小系统以在chroot下运行。您甚至可以使用它在 64 位系统上测试 32 位应用程序,或者在安装之前测试您的程序。要获得进程管理,请将proc挂载chroot ,并使home的内容在退出时丢失,将tmpfs挂载/home//

sudo mount -o bind /proc my_deb/proc
mount -t tmpfs -o size=100m tmpfs /home/user

要在内部获得Internet连接,请使用以下命令

sudo cp /etc/resolv.conf /var/chroot/etc/resolv.conf

之后,就可以进入环境了。

chroot my_deb/ /bin/bash

基于systemd

在基于systemd的系统上,chrooting 非常简单。只需要在进程单元文件上定义根目录

[Unit]
Description=my_chroot_Service
[Service]
RootDirectory=/chroot/foobar
ExecStartPre=/usr/local/bin/pre.sh
ExecStart=/bin/my_program
RootDirectoryStartOnly=yes

这里RootDirectory显示了foobar进程的根目录所在的位置。

在启动守护进程之前,会调用一个shell脚本pre.sh,其目的是根据需要设置chroot环境,例如,根据服务可能需要的内容,将/proc和类似的文件系统挂载到其中。您可以使用以下命令启动您的服务:

systemctl start my_chroot_Service.service

chroot Jail

创建 chroot jail 的基本命令如下:

chroot /path/to/new/root command
#OR
chroot /path/to/new/root /path/to/server
#OR
chroot [options] /path/to/new/root /path/to/server

为“bash”和“ls”命令创建一个mini-jail

创建一个目录作为命令的根目录。

mkdir jailed
cd jailed

为命令运行创建所有必要的目录。根据您的操作系统,所需的目录可能会发生变化。从逻辑上讲,我们创建所有这些目录是用来保留所需库的副本。

mkdir -p bin lib64/x86_64-linux-gnu lib/x86_64-linux-gnu

运行 which命令

运行 'which' 命令找到 ls 和 bash 命令的位置。运行 which 命令后,将这些二进制文件复制到我们 jail 的 'bin' 目录中。确保您没有任何这些命令的别名。

  $ unalias ls          # Required only if you have aliased ls command
  $ unalias bash        # Required only if you have aliased bash command
  $ cp $(which ls) ./bin/
  $ cp $(which bash) ./bin/

复制相应的库/对象

为了让 Jailed 目录中的可执行文件正常工作,我们需要在JAILED目录中复制相应的库/对象。默认情况下,可执行文件会查看以“/”开头的位置。要查找依赖项,我们使用命令“ldd”

$ ldd $(which bash)
    linux-vdso.so.1 =>  (0x00007ffc75dd4000)
    libtinfo.so.5 => /lib/x86_64-linux-gnu/libtinfo.so.5 (0x00007f6577768000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f6577564000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f657719a000)
    /lib64/ld-linux-x86-64.so.2 (0x000055979f3fd000)

运行以下命令以创建相应的目录

$ cp /lib/x86_64-linux-gnu/libtinfo.so.5 lib/x86_64-linux-gnu/
$ cp /lib/x86_64-linux-gnu/libdl.so.2 lib/x86_64-linux-gnu/
$ cp /lib/x86_64-linux-gnu/libc.so.6 lib/x86_64-linux-gnu/
$ cp /lib64/ld-linux-x86-64.so.2 lib64/

同样对于 ls

$ ldd $(which ls)
    linux-vdso.so.1 =>  (0x00007fff4f05d000)
    libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007f9a2fd07000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9a2f93e000)
    libpcre.so.3 => /lib/x86_64-linux-gnu/libpcre.so.3 (0x00007f9a2f6cd000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f9a2f4c9000)
    /lib64/ld-linux-x86-64.so.2 (0x000055e836c69000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f9a2f2ac000)
$ cp /lib/x86_64-linux-gnu/libselinux.so.1 lib/x86_64-linux-gnu/
$ cp /lib/x86_64-linux-gnu/libc.so.6 lib/x86_64-linux-gnu/
$ cp /lib/x86_64-linux-gnu/libpcre.so.3 lib/x86_64-linux-gnu/
$ cp /lib/x86_64-linux-gnu/libdl.so.2 lib/x86_64-linux-gnu/
$ cp /lib64/ld-linux-x86-64.so.2  lib64/
$ cp /lib/x86_64-linux-gnu/libpthread.so.0 lib/x86_64-linux-gnu/

Sudo chroot:运行此命令将根目录更改为 JAILED 目录,以及 shell 的路径。默认情况下,它将尝试加载 '/bin/sh' shell。

cd ..
sudo chroot jailed /bin/bash

网络

禁用不常见的协议

DCCP

在/etc/modprobe中编辑或创建一个文件。例如:vim /etc/modprobe.d/dccp.conf,增加如下一行

install dccp /bin/true

SCTP

在/etc/modprobe中编辑或创建一个文件。例如:vim /etc/modprobe.d/sctp.conf,增加如下一行

install sctp /bin/true

RDS

在/etc/modprobe中编辑或创建一个文件。例如:vim /etc/modprobe.d/rds.conf,增加如下一行

install rds /bin/true

TIPC

在/etc/modprobe中编辑或创建一个文件。例如:vim /etc/modprobe.d/tipc.conf,增加如下一行

install tipc /bin/true

禁用 IP 转发

在 /etc/sysctl.conf 或 /etc/sysctl.d/*文件中设置以下参数:

net.ipv4.ip_forward = 0
net.ipv6.conf.all.forwarding = 0

运行以下命令设置内核运行参数:

# sysctl -w net.ipv4.ip_forward=0
# sysctl -w net.ipv6.conf.all.forwarding=0
# sysctl -w net.ipv4.route.flush=1
# sysctl -w net.ipv6.route.flush=1

禁用数据包重定向

在 /etc/sysctl.conf 或 /etc/sysctl.d/* 文件中设置以下参数:

net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0

运行以下命令设置内核运行参数:

# sysctl -w net.ipv4.conf.all.send_redirects=0
# sysctl -w net.ipv4.conf.default.send_redirects=0
# sysctl -w net.ipv4.route.flush=1

丢弃源路由数据包

在正常路由情况下,来自Internet可路由地址的攻击者不能使用该系统作为到达私有地址系统的途径。然而,如果允许源路由数据包,它们就可以被用来访问私有地址系统,因为路由可以被指定,而不是依赖于不允许这种路由的路由协议。

今天,防火墙、路由器和交换机等网络设备默认情况下会在这些数据包到达您的系统之前丢弃这些数据包,但为了安全起见,建议设置这些规则。

在 /etc/sysctl.conf 或 /etc/sysctl.d/* 文件中设置以下参数:

net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
net.ipv6.conf.default.accept_source_route = 0

运行以下命令设置内核运行参数:

# sysctl -w net.ipv4.conf.all.accept_source_route=0
# sysctl -w net.ipv4.conf.default.accept_source_route=0
# sysctl -w net.ipv6.conf.all.accept_source_route=0
# sysctl -w net.ipv6.conf.default.accept_source_route=0
# sysctl -w net.ipv4.route.flush=1
# sysctl -w net.ipv6.route.flush=1

丢弃 ICMP 重定向

攻击者可以使用伪造的 ICMP 重定向消息来恶意更改系统路由表,并让它们将数据包发送到错误的网络并允许捕获您的系统数据包

在 /etc/sysctl.conf 或 /etc/sysctl.d/* 文件中设置以下参数:

net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0

运行以下命令设置内核运行参数:

# sysctl -w net.ipv4.conf.all.accept_redirects=0
# sysctl -w net.ipv4.conf.default.accept_redirects=0
# sysctl -w net.ipv6.conf.all.accept_redirects=0
# sysctl -w net.ipv6.conf.default.accept_redirects=0
# sysctl -w net.ipv4.route.flush=1
# sysctl -w net.ipv6.route.flush=1

记录可疑数据包

在 /etc/sysctl.conf 或 /etc/sysctl.d/* 文件中设置以下参数:

net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1

运行以下命令设置内核运行参数:

# sysctl -w net.ipv4.conf.all.log_martians=1
# sysctl -w net.ipv4.conf.default.log_martians=1
# sysctl -w net.ipv4.route.flush=1

忽略ICMP广播

Smurf 攻击依赖于攻击者发送大量带有欺骗源地址的 ICMP 广播消息。

在 /etc/sysctl.conf 或 /etc/sysctl.d/* 文件中设置以下参数:

net.ipv4.icmp_echo_ignore_broadcasts = 1

运行以下命令设置内核运行参数:

# sysctl -w net.ipv4.icmp_echo_ignore_broadcasts=1
# sysctl -w net.ipv4.route.flush=1

忽略虚假的 ICMP 响应

一些路由器(和一些攻击者)会发送违反 RFC-1122 的响应,并尝试用许多无用的错误消息填充日志文件系统。

在 /etc/sysctl.conf 或 /etc/sysctl.d/* 文件中设置以下参数:

net.ipv4.icmp_ignore_bogus_error_responses = 1

运行以下命令设置内核运行参数:

# sysctl -w net.ipv4.icmp_ignore_bogus_error_responses=1
# sysctl -w net.ipv4.route.flush=1

启用反向路径过滤

设置这些标志是阻止攻击者向您的系统发送无法响应的伪造数据包的好方法。该特性失效的一个实例是使用不对称路由。当在您的系统上使用动态路由协议(bgp、ospf等)时,就会发生这种情况。

在 /etc/sysctl.conf 或 /etc/sysctl.d/* 文件中设置以下参数:

net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1

运行以下命令设置内核运行参数:

# sysctl -w net.ipv4.conf.all.rp_filter=1
# sysctl -w net.ipv4.conf.default.rp_filter=1
# sysctl -w net.ipv4.route.flush=1

SYN flood攻击是指攻击者在没有完成三次握手的情况下,发送多个SYN报文,对系统进行拒绝服务攻击。这将很快耗尽内核的半开放连接队列中的插槽,并阻止合法连接成功。SYN cookie允许系统继续接受有效的连接,即使受到拒绝服务攻击

在 /etc/sysctl.conf 或 /etc/sysctl.d/* 文件中设置以下参数:

net.ipv4.tcp_syncookies = 1

运行以下命令设置内核运行参数:

# sysctl -w net.ipv4.tcp_syncookies=1
# sysctl -w net.ipv4.route.flush=1

丢弃 IPv6 路由器通告

建议系统不要接受路由器通告,因为它们可能会被诱骗将流量路由到受感染的机器。在系统内设置硬路由(通常是到受信任路由器的单个默认路由)可以保护系统免受不良路由的影响。

在 /etc/sysctl.conf 或 /etc/sysctl.d/* 文件中设置以下参数:

net.ipv6.conf.all.accept_ra = 0
net.ipv6.conf.default.accept_ra = 0

运行以下命令设置内核运行参数:

# sysctl -w net.ipv6.conf.all.accept_ra=0
# sysctl -w net.ipv6.conf.default.accept_ra=0
# sysctl -w net.ipv6.route.flush=1

iptables

内核配置

查看 IPv4 的所有可用网络相关内核配置

ls  /proc/sys/net/ipv4/ -l | cut -d " " -f 10

取消对广播icmp包的回应

echo "1" > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts

禁用源路由数据包

echo "0" > /proc/sys/net/ipv4/conf/all/accept_source_route

启用 TCP SYN Cookie 保护

echo 1 > /proc/sys/net/ipv4/tcp_syncookies

禁用 ICMP 重定向

echo "0" > /proc/sys/net/ipv4/conf/all/accept_redirects

不要发送重定向消息

echo "0" > /proc/sys/net/ipv4/conf/all/send_redirects

丢弃欺骗数据包

for f in /proc/sys/net/ipv4/conf/*/rp_filter; do echo "1" > $f; done

记录非法地址的数据包

echo "1" > /proc/sys/net/ipv4/conf/all/log_martians

默认情况下,内核中有三个包含规则集的表。

1.过滤表用于包过滤

2 .nat 表用于地址转换

3 .mangle 表可用于数据包的特殊处理

过滤表

包过滤不仅仅是包转发。数据包转发仅使用路由表进行决策,而数据包过滤使用规则列表。内核将检查数据包并根据这些规则决定如何处理每个数据包。

iptables中的过滤表有三个链(规则集)。INPUT链用于进入系统的任何数据包。OUTPUT链是针对离开系统的任何数据包的。FORWARD链用于通过系统转发(路由)的数据包

设置默认策略

最安全的防火墙策略是 DROP 一切,然后专门接受一些流量。丢弃的包将不会在任何链中继续,并且不会在任何地方发送警告或错误。

从所有链中删除任何现有规则

iptables  --flush

然后可以使用 -t 刷新特定表

iptables -t nat --flush
iptables -t mangle --flush

删除任何用户定义的链

iptables -X
iptables -t nat -X
iptables -t mangle -X

重置默认策略并停止防火墙

ipbles -P INPUT DROP
iptables -P OUTPUT DROP
iptables -P FORWARD DROP

允许环回访问

iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT

# see the results
iptables -n -L -v --line-number

允许 ICMP 回显 (ping)

ICMP types:

use --icmp-type 8 for echo request only
type 0 → echo reply
type 3 → destination unreachable messages
type 5 → redirect messages
type 8 → echo request
type 11 → time exceeded messages
type 12 → parameter problem messages
iptables -A INPUT -p icmp --icmp-type any -j ACCEPT
iptables -A OUTPUT -p icmp --icmp-type any -j ACCEPT

路由 Ping

前两行不允许其他计算机通过您的路由器路由 ping 消息,因为它只处理 INPUT 和 OUTPUT。

对于 ping 路由,您需要在 FORWARD 链上启用它。以下命令启用网络之间的 icmp 消息路由。

iptables -A FORWARD -p icmp --icmp-type any -j ACCEPT

允许建立&出站连接

以下命令将实施一个策略以允许所有出站连接和所有已建立的 TCP、UDP 和 ICMP 连接:

# iptables -A OUTPUT -p tcp -m state --state NEW,ESTABLISHED -j ACCEPT
# iptables -A OUTPUT -p udp -m state --state NEW,ESTABLISHED -j ACCEPT
# iptables -A OUTPUT -p icmp -m state --state NEW,ESTABLISHED -j ACCEPT
# iptables -A INPUT -p tcp -m state --state ESTABLISHED,RELATED -j ACCEPT
# iptables -A INPUT -p udp -m state --state ESTABLISHED,RELATED -j ACCEPT
# iptables -A INPUT -p icmp -m state --state ESTABLISHED,RELATED -j ACCEPT

拒绝欺骗数据包

拒绝伪装成来自外部接口 IP 地址的欺骗性数据包

iptables -A INPUT -i $INTERNET -s $IPADDR -j DROP

拒绝声称来自 A 类专用网络的数据包

iptables -A INPUT -i $INTERNET -s $CLASS_A -j DROP

拒绝声称来自环回接口的数据包

iptables  -A INPUT -i $INTERNET -s $LOOPBACK -j DROP

拒绝格式错误的广播包

iptables  -A INPUT -i $INTERNET -s $BROADCAST_DEST -j LOG
iptables -A INPUT -i $INTERNET -s $BROADCAST_DEST -j DROP
iptables -A INPUT -i $INTERNET -d $BROADCAST_SRC -j LOG
iptables -A INPUT -i $INTERNET -d $BROADCAST_SRC -j DROP

拒绝定向广播(用于映射网络和拒绝服务攻击)

iptables  -A INPUT -i $INTERNET -d $SUBNET_BASE -j DROP
iptables  -A INPUT -i $INTERNET -d $SUBNET_BROADCAST -j DROP

拒绝受限广播

iptables  -A INPUT -i $INTERNET -d $BROADCAST_DEST -j DROP

自定义规则

插入和替换规则

iptables -I/-R INPUT [line number] -s 59.45.175.10 -j ACCEPT

iptables -I INPUT 1 -s 59.45.175.10 -j ACCEPT
iptables -R INPUT 1 -s 59.45.175.10 -j ACCEPT

封锁IP

iptables -A INPUT -s IP-Address -j DROP

# works without ip tables
ip route add prohibit 192.168.30.83/32  

允许特定 IP

iptables -I INPUT -p tcp -s XXX.XXX.XXX.XXX -j ACCEPT
iptables -I OUTPUT -p tcp -d  XXX.XXX.XXX.XXX -j ACCEPT`

删除规则

iptables -D [chain name] [rule line number]
iptables -D INPUT 2

添加连接跟踪规则

iptables -A INPUT -j ACCEPT -m conntrack --ctstate ESTABLISHED,RELATED

iptables -A OUTPUT -j ACCEPT -m conntrack --ctstate ESTABLISHED,RELATED

允许特定端口

已建立的连接

iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

ssh

iptables -A INPUT -i eth0 -p tcp --dport 22 -j ACCEPT
iptables -A OUTPUT -o eth0 -p tcp --sport 22 -j ACCEPT

dns

iptables -A INPUT -p udp --sport 53 -j ACCEPT
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
iptables -A INPUT -p tcp --sport 53 -j ACCEPT
iptables -A OUTPUT -p tcp --dport 53 -j ACCEPT

http/https

iptables -A INPUT -p tcp --sport 443 -j ACCEPT
iptables -A OUTPUT -p tcp --dport 443 -j ACCEPT
iptables -A INPUT -p tcp --sport 80 -j ACCEPT
iptables -A OUTPUT -p tcp --dport 80 -j ACCEPT

允许从子网访问

iptables -A INPUT -i eth1 -s 10.1.1.0/24 -p tcp -j ACCEPT
iptables -A OUTPUT -o eth1 -d 10.1.1.0/24 -p tcp -j ACCEPT

日志记录

不要将日志记录规则作为第一条规则放在表的顶部,否则 iptables 将记录所有内容,如果您没有足够的资源来存储该数据,则会导致 DoS 。

最佳实践是在表的末尾添加日志记录规则作为最后一条规则,这样任何未被其他规则过滤的内容都将被记录下来。

iptables -A INPUT -j LOG
iptables -A OUTPUT -j LOG
iptables -A FORWARD -j LOG

流量限速

防御DDoS内核设置(sysctl.conf)

nano /etc/sysctl.conf

kernel.printk = 4 4 1 7 
kernel.panic = 10 
kernel.sysrq = 0 
kernel.shmmax = 4294967296 
kernel.shmall = 4194304 
kernel.core_uses_pid = 1 
kernel.msgmnb = 65536 
kernel.msgmax = 65536 
vm.swappiness = 20 
vm.dirty_ratio = 80 
vm.dirty_background_ratio = 5 
fs.file-max = 2097152 
net.core.netdev_max_backlog = 262144 
net.core.rmem_default = 31457280 
net.core.rmem_max = 67108864 
net.core.wmem_default = 31457280 
net.core.wmem_max = 67108864 
net.core.somaxconn = 65535 
net.core.optmem_max = 25165824 
net.ipv4.neigh.default.gc_thresh1 = 4096 
net.ipv4.neigh.default.gc_thresh2 = 8192 
net.ipv4.neigh.default.gc_thresh3 = 16384 
net.ipv4.neigh.default.gc_interval = 5 
net.ipv4.neigh.default.gc_stale_time = 120 
net.netfilter.nf_conntrack_max = 10000000 
net.netfilter.nf_conntrack_tcp_loose = 0 
net.netfilter.nf_conntrack_tcp_timeout_established = 1800 
net.netfilter.nf_conntrack_tcp_timeout_close = 10 
net.netfilter.nf_conntrack_tcp_timeout_close_wait = 10 
net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 20 
net.netfilter.nf_conntrack_tcp_timeout_last_ack = 20 
net.netfilter.nf_conntrack_tcp_timeout_syn_recv = 20 
net.netfilter.nf_conntrack_tcp_timeout_syn_sent = 20 
net.netfilter.nf_conntrack_tcp_timeout_time_wait = 10 
net.ipv4.tcp_slow_start_after_idle = 0 
net.ipv4.ip_local_port_range = 1024 65000 
net.ipv4.ip_no_pmtu_disc = 1 
net.ipv4.route.flush = 1 
net.ipv4.route.max_size = 8048576 
net.ipv4.icmp_echo_ignore_broadcasts = 1 
net.ipv4.icmp_ignore_bogus_error_responses = 1 
net.ipv4.tcp_congestion_control = htcp 
net.ipv4.tcp_mem = 65536 131072 262144 
net.ipv4.udp_mem = 65536 131072 262144 
net.ipv4.tcp_rmem = 4096 87380 33554432 
net.ipv4.udp_rmem_min = 16384 
net.ipv4.tcp_wmem = 4096 87380 33554432 
net.ipv4.udp_wmem_min = 16384 
net.ipv4.tcp_max_tw_buckets = 1440000 
net.ipv4.tcp_tw_recycle = 0 
net.ipv4.tcp_tw_reuse = 1 
net.ipv4.tcp_max_orphans = 400000 
net.ipv4.tcp_window_scaling = 1 
net.ipv4.tcp_rfc1337 = 1 
net.ipv4.tcp_syncookies = 1 
net.ipv4.tcp_synack_retries = 1 
net.ipv4.tcp_syn_retries = 2 
net.ipv4.tcp_max_syn_backlog = 16384 
net.ipv4.tcp_timestamps = 1 
net.ipv4.tcp_sack = 1 
net.ipv4.tcp_fack = 1 
net.ipv4.tcp_ecn = 2 
net.ipv4.tcp_fin_timeout = 10 
net.ipv4.tcp_keepalive_time = 600 
net.ipv4.tcp_keepalive_intvl = 60 
net.ipv4.tcp_keepalive_probes = 10 
net.ipv4.tcp_no_metrics_save = 1 
net.ipv4.ip_forward = 0 
net.ipv4.conf.all.accept_redirects = 0 
net.ipv4.conf.all.send_redirects = 0 
net.ipv4.conf.all.accept_source_route = 0 
net.ipv4.conf.all.rp_filter = 1

这些sysctl.conf设置有助于在DDoS下最大限度地提高服务器的性能以及iptables规则的有效性

IPtables Anti-DDoS规则

阻止非 SYN 的新数据包:

iptables -t mangle -A PREROUTING -p tcp ! --syn -m conntrack --ctstate NEW -j DROP

阻止不常见的 MSS 值:

iptables -t mangle -A PREROUTING -p tcp -m conntrack --ctstate NEW -m tcpmss ! --mss 536:65535 -j DROP

阻止带有虚假 TCP 标志的数据包:

iptables -t mangle -A PREROUTING -p tcp --tcp-flags FIN,SYN FIN,SYN -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags SYN,RST SYN,RST -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags FIN,RST FIN,RST -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags FIN,ACK FIN -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ACK,URG URG -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ACK,PSH PSH -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ALL NONE -j DROP

阻止来自私有子网的欺骗数据包:

iptables -t mangle -A PREROUTING -s 224.0.0.0/3 -j DROP 
iptables -t mangle -A PREROUTING -s 169.254.0.0/16 -j DROP 
iptables -t mangle -A PREROUTING -s 172.16.0.0/12 -j DROP 
iptables -t mangle -A PREROUTING -s 192.0.2.0/24 -j DROP 
iptables -t mangle -A PREROUTING -s 192.168.0.0/16 -j DROP 
iptables -t mangle -A PREROUTING -s 10.0.0.0/8 -j DROP 
iptables -t mangle -A PREROUTING -s 0.0.0.0/8 -j DROP 
iptables -t mangle -A PREROUTING -s 240.0.0.0/5 -j DROP 
iptables -t mangle -A PREROUTING -s 127.0.0.0/8 ! -i lo -j DROP

这些规则假设环回接口使用 127.0.0.0/8 IP。

仅这五组规则就已经阻止了许多以非常高的数据包速率进行的基于 TCP 的 DDoS 攻击。

使用上面提到的内核设置和规则,您将能够以线速过滤 ACK 和 SYN-ACK 攻击。

使用 SYNPROXY 缓解 SYN Floods

SYNPROXY 是 iptables 的新目标,已在 Linux 内核版本 3.12 和 iptables 1.4.21 中添加。CentOS 7 向后移植了该功能,并在其 3.10 默认内核中可用。

SYNPROXY 的目的是检查发送 SYN 数据包的主机是否真的建立了完整的 TCP 连接,或者在发送 SYN 数据包后什么都不做。

如果它什么都不做,它会以最小的性能影响丢弃数据包。

以下是有助于缓解绕过我们其他规则的 SYN 泛滥的 iptables SYNPROXY 规则:

iptables -t raw -A PREROUTING -p tcp -m tcp --syn -j CT --notrack 
iptables -A INPUT -p tcp -m tcp -m conntrack --ctstate INVALID,UNTRACKED -j SYNPROXY --sack-perm --timestamp --wscale 7 --mss 1460 
iptables -A INPUT -m conntrack --ctstate INVALID -j DROP

自定义Chains

/iptables -N ssh-rules
iptables -A ssh-rules -s 18.130.0.0/16 -j ACCEPT
iptables -A ssh-rules -s 18.11.0.0/16 -j ACCEPT
iptables -A ssh-rules -j DROP
iptables -A INPUT -p tcp -m tcp --dport 22 -j ssh-rules
iptables -X ssh-rules

持久化

当防火墙(重新)启动时,使用iptables save自动实现这些规则。

/etc/init.d/iptables save
or
iptables-save
iptables-save -f [output file]
iptables-restore [rules file]

重启后持久化:

sudo apt-get install iptables-persistent
iptables-save >/etc/iptables/rules.v4
ip6tables-save >/etc/iptables/rules.v6

iptables-save > /etc/iptables.conf
ip6tables-save > /etc/ip6tables.conf

pre-up iptables-restore < /etc/iptables.conf
pre-up ip6tables-restore < /etc/ip6tables.conf

NAT伪装

iptables -A FORWARD -m comment --comment "established traffic" -j ACCEPT -m conntrack --ctstate ESTABLISHED,RELATED

iptables -A FORWARD -j ACCEPT -i lan -o wan -m comment --comment "allow outbound traffic from lan"

iptables -t nat -L

iptables -t nat -A POSTROUTING -o wan -j MASQUERADE -m comment --comment "masquerade lan to wan" 

为 NAT 应用 ip 转发

echo 1 > /proc/sys/net/ipv4/ip_forward

端口地址转换

允许通过防火墙访问服务

iptables -t nat -A PREROUTING -p tcp --dport 22 -m comment --commnet "ssh PAT" -d [target ip] -j DNAT --to-destination [dest ip] 

iptabes -A FORWARD -p tcp --dport 22 -d [dest ip] -j ACCEPT -m comment "ssh into dest"

规则集

通用规则

### default drop policy ###
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT DROP

### # accept anything on localhost ###
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT

### # allow traffic once a connection has been made ###
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT


### HTTP / HTTPS ###
iptables -A INPUT -i eth0 -p tcp --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o eth0 -p tcp --sport 80 -m state --state ESTABLISHED -j ACCEPT
iptables -A INPUT -i eth0 -p tcp --dport 443 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o eth0 -p tcp --sport 443 -m state --state ESTABLISHED -j ACCEPT


### Allowing only SSH to a Network ###
iptables -A OUTPUT -o eth0 -p tcp -d 192.168.100.0/24 --dport 3306 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A INPUT -i eth0 -p tcp --sport 3306 -m state --state ESTABLISHED -j ACCEPT


### Allowing the Incoming MySQL port (3306) for TCP Traffic. ###
iptables -A INPUT -i eth0 -p tcp --dport 3306 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o eth0 -p tcp --sport 3306 -m state --state ESTABLISHED -j ACCEPT


### Allowing Incoming MySQL Port (3306) for a Specific Network ###
iptables -A INPUT -i eth0 -p tcp -s 192.168.87.0/24 --dport 3306 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o eth0 -p tcp --sport 3306 -m state --state ESTABLISHED -j ACCEPT


### Allowing Outgoing MySQL ###
iptables -A OUTPUT -o eth0 -p tcp --dport 3306-m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A INPUT -i eth0 -p tcp --sport 3306 -m state --state ESTABLISHED -j ACCEPT


### Allow Sendmail Traffic ###
iptables -A INPUT -i eth0 -p tcp --dport 25 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o eth0 -p tcp --sport 25 -m state --state ESTABLISHED -j ACCEPT


### Allowing IMAP & POP3 Ports ###
iptables -A INPUT -i eth0 -p tcp --dport 143 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o eth0 -p tcp --sport 143 -m state --state ESTABLISHED -j ACCEPT
iptables -A INPUT -i eth0 -p tcp --dport 110 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o eth0 -p tcp --sport 110 -m state --state ESTABLISHED -j ACCEPT


### Forward a Port to 5722 to 22(SSH) ###
iptables -t nat -A PREROUTING -p tcp -d 192.168.87.100 --dport 5722 -j DNAT --to 192.168.87.200:22


### Allowing Port 873 (rsync) for Backups ###
iptables -A INPUT -i eth0 -p tcp -s 192.168.87.0/24 --dport 873 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o eth0 -p tcp --sport 873 -m state --state ESTABLISHED -j ACCEPT


### Blocking an IP address ###
BLOCK_ADDRESS="192.168.87.100"
iptables -A INPUT -s "$BLOCK_ADDRESS" -j DROP
iptables -A INPUT -i eth0 -s “$ BLOCK_ADDRESS ” -j DROP
iptables -A INPUT -i eth0 -p tcp -s “$ BLOCK_ADDRESS ” -j DROP

Anti DDoS

### 1: Drop invalid packets ### 
/sbin/iptables -t mangle -A PREROUTING -m conntrack --ctstate INVALID -j DROP  

### 2: Drop TCP packets that are new and are not SYN ### 
/sbin/iptables -t mangle -A PREROUTING -p tcp ! --syn -m conntrack --ctstate NEW -j DROP 
 
### 3: Drop SYN packets with suspicious MSS value ### 
/sbin/iptables -t mangle -A PREROUTING -p tcp -m conntrack --ctstate NEW -m tcpmss ! --mss 536:65535 -j DROP  

### 4: Block packets with bogus TCP flags ### 
/sbin/iptables -t mangle -A PREROUTING -p tcp --tcp-flags FIN,SYN FIN,SYN -j DROP
/sbin/iptables -t mangle -A PREROUTING -p tcp --tcp-flags SYN,RST SYN,RST -j DROP
/sbin/iptables -t mangle -A PREROUTING -p tcp --tcp-flags FIN,RST FIN,RST -j DROP
/sbin/iptables -t mangle -A PREROUTING -p tcp --tcp-flags FIN,ACK FIN -j DROP
/sbin/iptables -t mangle -A PREROUTING -p tcp --tcp-flags ACK,URG URG -j DROP
/sbin/iptables -t mangle -A PREROUTING -p tcp --tcp-flags ACK,PSH PSH -j DROP
/sbin/iptables -t mangle -A PREROUTING -p tcp --tcp-flags ALL NONE -j DROP

### 5: Block spoofed packets ### 
/sbin/iptables -t mangle -A PREROUTING -s 224.0.0.0/3 -j DROP 
/sbin/iptables -t mangle -A PREROUTING -s 169.254.0.0/16 -j DROP 
/sbin/iptables -t mangle -A PREROUTING -s 172.16.0.0/12 -j DROP 
/sbin/iptables -t mangle -A PREROUTING -s 192.0.2.0/24 -j DROP 
/sbin/iptables -t mangle -A PREROUTING -s 192.168.0.0/16 -j DROP 
/sbin/iptables -t mangle -A PREROUTING -s 10.0.0.0/8 -j DROP 
/sbin/iptables -t mangle -A PREROUTING -s 0.0.0.0/8 -j DROP 
/sbin/iptables -t mangle -A PREROUTING -s 240.0.0.0/5 -j DROP 
/sbin/iptables -t mangle -A PREROUTING -s 127.0.0.0/8 ! -i lo -j DROP  

### 6: Drop ICMP (you usually don't need this protocol) ### 
/sbin/iptables -t mangle -A PREROUTING -p icmp -j DROP  

### 7: Drop fragments in all chains ### 
/sbin/iptables -t mangle -A PREROUTING -f -j DROP  

### 8: Limit connections per source IP ### 
/sbin/iptables -A INPUT -p tcp -m connlimit --connlimit-above 111 -j REJECT --reject-with tcp-reset  

### 9: Limit RST packets ### 
/sbin/iptables -A INPUT -p tcp --tcp-flags RST RST -m limit --limit 2/s --limit-burst 2 -j ACCEPT 
/sbin/iptables -A INPUT -p tcp --tcp-flags RST RST -j DROP  

### 10: Limit new TCP connections per second per source IP ### 
/sbin/iptables -A INPUT -p tcp -m conntrack --ctstate NEW -m limit --limit 60/s --limit-burst 20 -j ACCEPT 
/sbin/iptables -A INPUT -p tcp -m conntrack --ctstate NEW -j DROP  

### 11: Use SYNPROXY on all ports (disables connection limiting rule) ### 
# Hidden - unlock content above in "Mitigating SYN Floods With SYNPROXY" section

服务加固

vsftpd

启用本地用户帐户

要启用本地用户帐户进行FTP访问,需要对/etc/vsftpd.conf文件进行如下修改:

/etc/vsftpd.conf
anonymous_enable=NO
connect_from_port_20=NO
local_enable=YES
write_enable=YES

启用chroot Jail

打开/etc/vsftpd/vsftpd.conf并取消注释以下选项:

chroot_local_user=YES
chroot_list_enable=YES
chroot_list_file=/etc/vsftpd.chroot_list

该文件/etc/vsftpd.chroot_list 包含被jailed 用户的列表。

保存文件并重新启动您的服务。

systemctl restart vsftpd

匿名

如果您的文件想要可供没有任何密码或登录名的用户使用

打开/etc/vsftpd/vsftpd.conf 文件,并将以下选项更改为相应的值

listen=NO
listen_ipv6=NO
anonymous_enable=YES
local_enable=NO
write_enable=NO

然后我们需要创建一个非特权系统帐户来使用它进行匿名 FTP 类型的访问。

useradd -c " FTP User" -d /var/ftp -r -s /sbin/nologin ftp

重启服务:

service vsftpd restart

此用户在系统上没有权限,因此在访问 FTP 服务器时使用它会更安全。

使用 openssl 命令生成证书请求:

openssl genrsa -des3 -out FTP.key

然后我们生成一个证书请求

openssl req -new -key FTP.key -out certificate.csr

现在我们从密钥文件中删除密码:

cp FTP.key FTP.key.orig
openssl rsa -in FTP.key.orig -out ftp.key

生成我们的证书:

openssl x509 -req -days 365 -in certificate.csr -signkey ftp.key -out mycertificate.crt

现在我们将证书文件和密钥复制到/etc/pki/tls/certs

cp ftp.key /etc/pki/tls/certs/
cp mycertificate.crt /etc/pki/tls/certs

配置 vsftpd 以支持安全连接

打开/etc/vsftpd/vsftpd.conf 文件并添加以下行:

ssl_enable=YES
allow_anon_ssl=YES
ssl_tlsv1=YES
ssl_sslv2=NO
ssl_sslv3=NO
rsa_cert_file=/etc/pki/tls/certs/mycertificate.crt
rsa_private_key_file=/etc/pki/tls/certs/ftp.key
ssl_ciphers=HIGH
require_ssl_reuse=NO

重新启动服务使这些更改生效

尝试从任何系统(如Windows)上的任何客户端连接到FTP服务器,并选择安全连接或FTPS,您将成功看到您的文件夹

Nginx

禁用多余的模块

安装 nginx 时,它会自动包含许多模块。目前,您无法在运行时选择模块。要禁用某些模块,您需要重新编译 nginx。我们建议您禁用任何不需要的模块,因为这将通过限制允许的操作来最大程度地降低潜在攻击的风险。

为此,请在安装期间使用configure选项。在下面的示例中,我们禁用了自动生成目录列表的autoindex模块,然后重新编译 nginx。

# ./configure --without-http_autoindex_module
# make
# make install

禁用 nginx server_tokens

默认情况下,nginx中的server_tokens指令会显示nginx的版本号。它在所有自动生成的错误页面中都是直接可见的,而且也出现在所有HTTP响应中的Server报头中。

这可能会导致信息泄露——未经授权的用户可能会获得关于您使用的nginx版本的信息。你应该通过设置server_tokens off来禁用nginx配置文件中的server_tokens指令

清除Server标头

Nginx 服务器的默认状态在服务器响应或错误页面中返回类似于 Server: nginx/1.12.1 的内容。最好的方法是完全删除这个东西。为此,我们需要安装*nginx-extras*

对于 Debian/Ubuntu

sudo apt-get install nginx-extras

对于 RHEL

yum install nginx-plus-module-headers-more

安装并重新启动Nginx服务后,在Nginx .conf文件中添加以下行

         # /etc/nginx/nginx.conf
        http {
            # Basic Settings
            more_set_headers 'Server: ';

如果未指定值,则标头将显示为空。我们还可以创建自定义标头,如下所示。

 
        # /etc/nginx/nginx.conf
        http {
            # Basic Settings
            more_set_headers 'Server: 你在看你马';

要完全禁用服务器标头,在Nginx配置文件中找到server_token,并将其设置为server_tokens off(通过在Nginx .conf文件中去掉前面的#)。

控制和限制资源

为了防止对 nginx 的潜在 DoS 攻击,您可以为所有客户端设置缓冲区大小限制。您可以使用以下指令在 nginx 配置文件中完成此操作:

  • client_body_buffer_size – 使用此指令指定客户端请求体缓冲区大小。默认值为 8k 或 16k,但建议将其设置为1k
  • client_header_buffer_size – 使用此指令指定客户端请求标头的标头缓冲区大小。对于大多数请求,1k的缓冲区大小就足够了
  • client_max_body_size – 使用此指令指定客户端请求可接受的最大正文大小。1k指令应该足够了,但是如果你通过POST方法接收文件上传,则需要增加它
  • large_client_header_buffers - 使用此指令指定用于读取大型客户端请求标头的缓冲区的最大数量和大小。large_client_header_buffers 2 1k指令将缓冲区的最大数量设置为 2,每个最大大小为 1k。

禁用任何不需要的 HTTP 方法,建议您禁用任何不会使用且不需要在 Web 服务器上实现的 HTTP 方法。如果在 nginx 虚拟主机配置文件的 location 块中添加以下条件,服务器将只允许 GET、HEAD 和 POST 方法,并会过滤掉 DELETE 和 TRACE 等方法。

location / {
limit_except GET HEAD POST { deny all; }
}

另一种方法是向服务器部分(或服务器块)添加以下条件

if ($request_method !~ ^(GET|HEAD|POST)$ ) {
    return 444; }

设置访问和错误日志

nginx的访问和错误日志默认是启用的,分别位于logs/error.loglogs/access.log中。如果要更改位置,可以使用 nginx 配置文件中的error_log指令。您还可以使用此指令指定将根据其严重性级别记录的日志。例如,crit严重级别将导致 nginx 记录严重问题以及所有严重级别高于crit的问题。要将严重级别设置为crit ,请按如下方式设置error_log指令:

error_log logs/error.log crit;

你可以在nginx官方文档中找到error_log严重级别的完整列表

监控访问和错误日志

如果你持续监控和管理nginx日志文件,你可以更好地理解向你的web服务器发出的请求,并注意到任何遇到的错误。这将帮助您发现任何攻击尝试,并确定您可以做什么来优化服务器性能

您可以使用日志管理工具(例如 logrotate)来轮换和压缩旧日志,释放磁盘空间。此外,ngx_http_stub_status_module模块提供对基本状态信息的访问。如果你公司子弹够多,还可以购买nginx Plus,这是 nginx 的商业版,它提供对流量、负载和其他性能指标的实时活动监控。

包含安全标头

为了进一步强化您的 nginx Web 服务器,您可以添加几个不同的 HTTP 标头。以下是推荐的一些选项。

X-Frame-Options

您可以使用X-Frame-Options HTTP响应标头可以指示浏览器是否应该加载一个iframe中的页面。这可以防止点击劫持攻击。因此,我们建议在nginx 服务器启用此选项。

为此,在服务器部分的nginx配置文件中添加以下参数:

add_header X-Frame-Options "SAMEORIGIN";
Strict-Transport-Security

HTTP严格传输安全(HSTS)是网站用来声明它们只能通过安全连接(HTTPS)访问的一种方法。如果网站声明了HSTS策略,浏览器必须拒绝所有HTTP连接,并阻止用户接受不安全的SSL证书。要向nginx服务器添加HSTS头文件,你可以在服务器部分添加以下指令

add_header Strict-Transport-Security "max-age=31536000; includeSubdomains; preload";
CSP and X-XSS-Protection

内容安全策略(CSP)保护您的web服务器免受某些类型的攻击,包括跨站脚本攻击(XSS)和注入攻击。您可以通过添加以下示例Content-Security-Policy标头来实现CSP:

add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;

配置 SSL 和加密套件

nginx的默认配置允许你使用不安全的旧版本TLS协议(根据官方文档:ssl_protocols TLSv1 TLSv1.1 TLSv1.2)。这可能会导致诸如 BEAST 攻击之类的攻击。因此,我们建议您不要使用旧的 TLS 协议并更改您的配置以仅支持更新的、安全的 TLS 版本。

为此,请在 nginx 配置文件的 server 部分添加以下指令:

ssl_protocols TLSv1.2 TLSv1.3;

此外,您应该指定加密套件,建议将以下指令添加到server部分:

ssl_prefer_server_ciphers on;

使用 Gixy 检查配置

Gixy 是一个开源工具,可让您检查 nginx Web 服务器是否存在典型的错误配置。准备好 nginx 配置后,最好使用 Gixy 进行检查。

Apache

隐藏 Apache 版本和操作系统标识

当您使用source或yum等任何其他包安装程序安装Apache时,它会在Errors中显示安装在服务器上的Apache web服务器的版本和服务器的操作系统名称。它还显示了有关服务器中安装的Apache模块的信息

在上图中,可以看到 Apache 显示其版本以及您的服务器中安装的操作系统。这可能是对您的 Web 服务器以及 Linux 机器的主要安全威胁。为了防止 Apache 不向外界显示这些信息,我们需要对 Apache 主配置文件进行一些更改。用 vim 编辑器打开配置文件,搜索“ServerSignature”,默认是打开的。我们需要关闭这些服务器签名,第二行“ServerTokens Prod”抑制了操作系统、主要和次要版本信息。

# vim /etc/httpd/conf/httpd.conf (RHEL/CentOS/Fedora)
# vim /etc/apache2/apache2.conf (Debian/Ubuntu)

更改/添加这些行:

ServerSignature Off
ServerTokens Prod

重启服务:

# service httpd restart (RHEL/CentOS/Fedora)
# service apache2 restart (Debian/Ubuntu)

禁用目录列表

默认情况下,Apache 会在没有指定文件的情况下列出 Document 根目录的所有内容

我们可以通过在特定目录的配置文件中使用 Options 指令来关闭目录列表。为此,我们需要在httpd.conf apache2.conf文件中创建一个条目。

<Directory /var/www/html>
Options -Indexes
</Directory>

https://files.mdnice.com/user/31163/ea903478-d766-4dc7-871b-48d063ee32c4.png

定期更新 Apache

Apache 开发者社区一直致力于解决安全问题,并发布具有新安全选项的更新版本。因此,始终建议使用最新版本的 Apache 作为您的 Web 服务器。

检查 Apache 版本:您可以使用 httpd -v 命令检查当前版本。

# httpd -v
Server version: Apache/2.2.15 (Unix)
Server built:   Aug 13 2013 17:29:28

# yum update httpd
# apt-get install apache2

如果没有运行任何仅适用于特定操作系统或内核的特定应用程序,还建议将内核和操作系统更新到最新的稳定版本。

禁用不必要的模块

降低成为网络攻击受害者的几率总是好的。因此,建议禁用当前未使用的所有模块。您可以使用下面的命令列出web服务器的所有编译模块

grep LoadModule /etc/httpd/conf/httpd.conf

# have to place corresponding `LoadModule' lines at this location so the
# LoadModule foo_module modules/mod_foo.so
LoadModule auth_basic_module modules/mod_auth_basic.so
LoadModule auth_digest_module modules/mod_auth_digest.so
LoadModule authn_file_module modules/mod_authn_file.so
LoadModule authn_alias_module modules/mod_authn_alias.so
LoadModule authn_anon_module modules/mod_authn_anon.so
LoadModule authn_dbm_module modules/mod_authn_dbm.so
LoadModule authn_default_module modules/mod_authn_default.so
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule authz_user_module modules/mod_authz_user.so
LoadModule authz_owner_module modules/mod_authz_owner.so
LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
LoadModule authz_dbm_module modules/mod_authz_dbm.so
LoadModule authz_default_module modules/mod_authz_default.so
LoadModule ldap_module modules/mod_ldap.so
LoadModule authnz_ldap_module modules/mod_authnz_ldap.so
LoadModule include_module modules/mod_include.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule logio_module modules/mod_logio.so
LoadModule env_module modules/mod_env.so
LoadModule ext_filter_module modules/mod_ext_filter.so
....

上面是默认启用但通常不需要的模块列表:mod_imap, mod_include, mod_info, mod_userdir, mod_autoindex。要禁用特定模块,可以在该行的开头插入“#”并重新启动服务。

作为单独的用户和组运行 Apache

在默认安装下,Apache使用nobody或daemon用户运行其进程。出于安全考虑,建议在其自己的非特权帐户中运行 Apache。例如:http web。

创建 Apache 用户和组
groupadd http-web
useradd -d /var/www/ -g http-web -s /bin/nologin http-web

现在需要告诉 Apache 使用这个新用户运行,为此,我们需要进入/etc/httpd/conf/httpd.conf并重新启动服务。

使用 vim 编辑器打开/etc/httpd/conf/httpd.conf并搜索关键字“User”and “Group”,在那里指定要使用的用户名和组名。

User http-web
Group http-web

使用 Allow 和 Deny 限制对目录的访问

我们可以在httpd.conf文件中使用“Allow ”和“Deny ”选项来限制对目录的访问。在本例中,我们将通过在httpd.conf文件中设置以下内容来保护根目录

<Directory />
   Options None
   Order deny,allow
   Deny from all
</Directory>
  • Options “None” - 此选项不允许用户启用任何可选功能。
  • Order deny, allow - 这是处理“Deny”和“Allow”指令的顺序。这里它首先是“拒绝”,然后是“允许”
  • Deny from all - 这将拒绝所有人对根目录的请求,任何人都无法访问根目录。

使用 mod_security 和 mod_evasive 模块来保护 Apache

这两个模块“mod_security”和“mod_evasive”是Apache中非常流行的安全模块。

Mod_security

mod_security用作我们的 Web 应用程序的防火墙允许我们实时监控流量。它还帮助我们保护我们的网站或web服务器免受暴力攻击。您可以在默认软件包安装程序的帮助下简单地在您的服务器上安装mod_security 。

在 Ubuntu/Debian 上安装 mod_security

sudo apt-get install libapache2-modsecurity
sudo a2enmod mod-security
sudo /etc/init.d/apache2 force-reload

在 RHEL/CentOS/Fedora 上安装 mod_security

yum install mod_security
/etc/init.d/httpd restart
Mod_evasive

mod_evasive工作效率很高,它只需要处理一个请求,并且处理得非常好。mod_evasive的这一特性使其能够处理HTTP 暴力破解DosDDos攻击。该模块使用三种方法检测攻击。

  1. 假如非常多的请求在每秒几次的时间内出现在同一个页面上
  2. 如果任何子进程试图发出超过50 个并发请求。
  3. 如果任何IP在其暂时被列入黑名单时仍在尝试发出新请求。

mod_evasive可以直接从源安装。在这里,有这些模块的安装和设置指南,它将帮助您在 Linux 机器中设置这些 Apache 模块。

禁用Apache的符号链接

默认情况下,Apache遵循符号链接,我们可以通过带有FollowSymLinks 的Options指令关闭此功能。为此,我们需要在主配置文件中创建以下条目

Options -FollowSymLinks

后面如果有任何特定用户网站需要启用FollowSymLinks ,我们可以简单地在该网站的“ .htaccess ”文件中编写规则。

# Enable symbolic links
Options +FollowSymLinks

关闭服务器端包含和 CGI 执行

如果不需要,我们可以关闭服务器端包含(mod_include)和CGI执行,为此我们需要修改主配置文件

Options -Includes
Options -ExecCGI

我们也可以使用 Directory 标签对特定目录执行此操作。在此示例中,我们将关闭“ /var/www/html/web1 ”目录的include和 Cgi 文件执行。

<Directory "/var/www/html/web1">
Options -Includes -ExecCGI
</Directory>

以下是一些其他值,可以使用 Options 指令打开关闭。

  1. **Options All ** - 一次启用所有选项。这是默认值,如果您不想在 Apache conf 文件或 .htaccess 中显式指定任何值。
  2. Options IncludesNOEXEC - 此选项允许服务器端包含没有执行权限的命令或 cgi 文件。
  3. Options MultiViews – 允许使用 mod_negotiation 模块进行内容协商的多视图。
  4. Options SymLinksIfOwnerMatch – 类似于 FollowSymLinks。但是,只有当链接和链接到的原始目录之间的所有者相同时,才会出现这种情况。

限制请求大小

默认情况下,Apache对HTTP请求的总大小没有限制,即无限制,当你允许web服务器上的大型请求时,你可能会成为拒绝服务攻击的受害者。我们可以用directory标签和Apache 指令“LimitRequestBody”来限制请求大小

您可以将请求体中允许的值(以字节为单位)从0(无限制)设置为2147483647 (2GB)。根据你的网站的需要来设置这个限制。假设你有一个允许上传的网站,你想限制一个特定目录的上传大小。

在此示例中,user_uploads是一个目录,其中包含用户上传的文件。我们对此的限制是500K。

<Directory "/var/www/myweb1/user_uploads">
   LimitRequestBody 512000
</Directory>

防范DDOS攻击和加固

的确,无法完全保护网站免受DDos 攻击。但这里有一些指令可以帮助你控制它。

  1. TimeOut :此指令允许您设置服务器在失败之前等待某些事件完成的时间量。它的默认值为300 秒。在那些受到DDOS 攻击的网站上,最好将此值保持在较低水平。该值完全取决于您在网站上收到的请求类型。注意:这可能会对CGI脚本造成问题。
  2. MaxClients :此指令允许您设置同时服务的连接限制。在此限制之后,每个新连接都将排队。它适用于PreforkWorker两者MPM 。它的默认值为256
  3. KeepAliveTimeout :服务器在关闭连接之前等待后续请求的时间。默认值为5 秒
  4. LimitRequestFields :它可以帮助我们设置从客户端接受的 HTTP 请求标头字段的数量限制。它的默认值为100 。如果由于大量 http 请求标头而发生DDos 攻击,建议降低此值。
  5. LimitRequestFieldSize :它可以帮助我们设置 HTTP 请求标头的大小限制。

启用 Apache 日志记录

Apache 允许您独立于您的操作系统日志进行日志记录。启用 Apache 日志记录是明智的,因为它提供了更多的信息,例如与Web 服务器交互的用户输入的命令。

为此,您需要包含mod_log_config模块。Apache 提供了三个与日志记录相关的主要指令。

  1. TransferLog :创建日志文件。
  2. LogFormat :指定自定义格式。
  3. CustomLog :创建和格式化日志文件。

在VirtualHost部分中指定它。

<VirtualHost *:80>
DocumentRoot /var/www/html/example.com/
ServerName www.example.com
DirectoryIndex index.htm index.html index.php
ServerAlias example.com
ErrorDocument 404 /story.php
ErrorLog /var/log/httpd/example.com_error_log
CustomLog /var/log/httpd/example.com_access_log combined
</VirtualHost>

日志记录

重要的 Linux 日志文件

journalctl

日志捕获的系统消息存储在/run目录中。Rsyslog可以处理这些消息并将它们存储在传统日志文件中,或者将它们转发到远程syslog服务器。还可以使用journalctl命令直接访问日志

显示所有日志条目:

journalctl

查看实时日志:

journalctl -f

检查服务日志

显示服务的 systemd 日志

journalctl -u [service] 

显示来自特定二进制文件的最近100个日志条目

 journalctl -n 100 /usr/sbin/sshd

根据进程 PID 过滤日志

要根据进程 PID 查看 systemd 日志,我们可以使用 _PID,如下所示:

journalctl _PID=26730

根据优先级过滤日志

按消息优先级或优先级范围筛选输出。接受单个数字或文本日志级别(例如,在0/"emerg"和7/"debug"之间),或者以FROM..TO形式接受一系列数字/文本日志级别。即 "emerg" (0), "alert" (1), "crit" (2), "err" (3), "warning" (4), "notice" (5), "info" (6), "debug" (7).

过滤“emerg”级的日志:

journalctl -p 0

过滤介于 emerg(0) 和 critical(2) 之间的范围的日志:

journalctl -p 0..2

使用verbose模式查看日志

journalctl -o verbose

持久化Journald

大多数 Linux 发行版默认值为 auto 并且不附带 /var/log/journal 目录。因此,日志在默认情况下不会在重新启动之间保存,这是不幸的。您可以通过创建/var/log/journal目录或更新日志以使用持久存储并重新启动 systemd-journald 来修改此行为:

# mkdir /etc/systemd/journald.conf.d/
# cat << END > /etc/systemd/journald.conf.d/storage.conf
[Journal]
Storage=persistent
END
# systemctl restart systemd-journald

检查引导日志

journalctl --list-boots 
journalctl -b -1
journalctl -b a73415fade0e4e7f4bea60913883d180dc

可以使用 -b 选项将日志显示限制为特定的引导会话。例如,查看 SSH 在当前会话期间生成的日志:

journalctl -b 0 -u ssh

根据时间检查日志

显示从昨天到现在的所有消息

journalctl --since=yesterday --until=now

根据时间戳过滤 systemd 日志:

journalctl --since today
journalctl --since "2019-08-26 15:00:00"
journalctl --since "2019-08-26 15:00:00" --until "2019-08-27 15:00:00"
journalctl --since yesterday --until now

过滤内核消息

你可以使用(-k)。它等同于 (--dmesg)。在某种程度上,您还可以从内核查看 Linux引导消息。

journalctl -k

或者,您也可以使用 _TRANSPORT 过滤所有“kernel”匹配的日志

journalctl _TRANSPORT=kernel

Windows

windows加固命令

禁用与服务的远程交

reg add "HKLM\SYSTEM\CurrentControlSet\Control" /v DisableRemoteScmEndpoints /t REG_DWORD /d 1 /f

禁用与计划任务的远程交互

reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule" /v DisableRpcOverTcp /t REG_DWORD /d 1 /f

禁用 RDP 访问

reg add "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections /t REG_DWORD /d 1 /f 

禁用 DCOM

reg add "HKLM\SOFTWARE\Microsoft\Ole" /v EnableDCOM /t REG_SZ /d N /f

禁用管理员共享

reg add "HKLM\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters" /v "AutoShareWks" /t REG_DWORD /d 0 /f 
reg add "HKLM\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters" /v "AutoShareServer" /t REG_DWORD /d 0 /f

禁用Printer Spooler Service (PrintNightmare RCE & LPE 缓解)

Stop-Service -Name Spooler -Force
Set-Service -Name Spooler -StartupType Disabled
reg add "HKLM\SYSTEM\CurrentControlSet\Services\Spooler" /v Start /t REG_DWORD /d 4 /f

防止系统写入新的print DLL (PrintNightmare RCE & LPE 缓解)

$Path = "C:\Windows\System32\spool\drivers"
$Acl = (Get-Item $Path).GetAccessControl('Access')
$Ar = New-Object  System.Security.AccessControl.FileSystemAccessRule("System", "Modify", "ContainerInherit, ObjectInherit", "None", "Deny")
$Acl.AddAccessRule($Ar)
Set-Acl $Path $Acl

禁用远程打印(PrintNightmare RCE 缓解)

reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows NT\Printers" /v RegisterSpoolerRemoteRpcEndPoint /t REG_DWORD /d 2 /f

在 PointAndPrint 和 UAC 上启用警告(PrintNightmare LPE 缓解)

reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows NT\Printers\PointAndPrint" /v NoWarningNoElevationOnInstall /t REG_DWORD /d 0 /f
reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows NT\Printers\PointAndPrint" /v NoWarningNoElevationOnUpdate /t REG_DWORD /d 0 /f
reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" /v EnableLUA /t REG_DWORD /d 1 /f

拒绝脆弱的Netlogon连接 (防范ZeroLogon CVE-2020-1472)

reg add "HKLM\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters" /v FullSecureChannelProtection /t REG_DWORD /d 1 /f

需要注意的是,以下与此相关的系统事件应予以审查:

  • 如果 ZeroLogon 连接被拒绝,系统事件日志中的事件 ID 为 5827 和 5828。
  • 如果域控制器允许易受攻击的 Netlogon 安全通道连接,组策略允许 ZeroLogon 连接,则系统事件日志中的事件 ID 为 5830 和 5831。
  • 如果允许 ZeroLogon 易受攻击的 Netlogon 安全通道连接,则系统事件日志中的事件 ID 5829。

重命名 mshtml.dll(CVE-2021-40444 缓解)

以管理员身份运行 cmd.exe

takeown /F mshtml.dll icacls mshtml.dll /grant administrators:F move mshtml.dll mshtml2.dll cd ../SysWOW64 takeown /F mshtml.dll icacls mshtml.dll /grant administrators:F move mshtml.dll mshtml2.dll

删除管理员共享

注意:这可能会破坏某些应用程序通信和管理功能。它也可能是暂时的,因为Windows 会重新创建它们

C$ = 系统“C”驱动器上的默认共享

IPC$ = 默认进程间通信共享(由命名管道使用)

ADMIN$ = 用于远程管理的默认共享(由PsExec使用)

net share C$ /delete 
net share IPC$ /delete 
net share ADMIN$ /delete

禁用匿名访问命名管道

reg add "HKLM\SYSTEM\CurrentControlSet\Services\LanManServer\Parameters" /v "RestrictNullSessAccess" /t "REG_DWORD" /d 1 /f

禁用 OLE 对象

reg add "HKLM\SYSTEM\CurrentControlSet\Services\LanManServer\Parameters" /v "RestrictNullSessAccess" /t "REG_DWORD" /d 1 /f

AD 安全检查

一般加固建议

  • 管理本地管理员密码 (LAPS)。
  • 实施 RDP 受限管理员模式(根据需要)。
  • 从网络中删除不受支持的操作系统。
  • 监控敏感系统(DC 等)上的计划任务。
  • 确保定期更改 OOB 管理密码 (DSRM) 并安全存储。
  • 使用 SMB v2/v3+
  • 默认域管理员和 KRBTGT 密码应在每年和 AD 管理员离开时更改。
  • 删除不再需要的信任并根据需要启用 SID 过滤。
  • 所有域身份验证都应设置(如果可能):“仅发送 NTLMv2 响应,拒绝 LM 和 NTLM。”
  • 阻止 DC、服务器和所有管理系统的 Internet 访问。

保护管理员凭据

  • 管理员组中没有“用户”或计算机帐户。
  • 确保所有管理员帐户都是“敏感且不能被委派”。
  • 将管理员帐户添加到“受保护的用户”组(需要 Windows Server 2012 R2 域控制器、2012R2 DFL 用于域保护)。
  • 禁用所有非活动管理员帐户并从特权组中删除。

保护 AD 管理员凭据

  • 限制 AD 管理员成员资格(DA、EA、Schema Admins等)仅使用自定义委派组。
  • “分级”管理减轻凭证盗窃的影响。
  • 确保管理员仅登录经批准的管理员工作站和服务器。
  • 为所有管理员帐户利用基于时间的临时组成员身份

保护服务帐户凭据

  • 限制使用相同安全级别的系统。

  • 利用“(组)托管服务帐户”(或 PW >20 个字符)来减少凭证盗窃(kerberoast)。

  • 实施 FGPP (DFL =>2008) 以增加对 SA 和管理员的 PW 要求。

  • 登录限制 – 防止交互式登录并将登录功能限制在特定计算机上。

  • 禁用非活动 SA 并从特权组中删除。

保护资源

  • 分段网络以保护管理和关键系统。
  • 部署 IDS 以监控内部公司网络。
  • 在单独的网络上进行网络设备和OOB管理。

保护域控制器

  • 仅运行支持 AD 的软件和服务。
  • 具有 DC 管理员/登录权限的最小组(和用户)。
  • 确保在运行 DCPromo 之前应用补丁(尤其是 MS14-068 和其他关键补丁)。
  • 验证计划任务和脚本。

保护Workstations (&server)

  • 快速打补丁,尤其是提权漏洞。
  • 部署安全后端端口补丁 (KB2871997)。
  • 将 Wdigest reg 键设置为 0 (KB2871997/Windows 8.1/2012R2+):HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlSecurityProvidersWdigest
  • 部署工作站白名单 (Microsoft AppLocker) 以阻止用户文件夹中的代码执行 - 主目录和配置文件路径。
  • 部署工作站应用程序沙盒技术 (EMET) 以缓解应用程序内存漏洞(0-days)。

日志记录

  • 启用增强审核
  • “审核:强制审核策略子类别设置(Windows Vista 或更高版本)覆盖审核策略类别设置”
  • 启用 PowerShell 模块日志记录(“*”)并将日志转发到中央日志服务器(WEF 或其他方法)。
  • SIEM或类似工具可以集中尽可能多的日志数据。
  • 用于增强用户活动知识的用户行为分析系统(例如 Microsoft ATA)。
posted @ 2023-08-10 10:27  解放者-cracer  阅读(77)  评论(0编辑  收藏  举报