金钱(警告)
状态: 被贬值
如果您目前正在运行运行 Ubuntu 12.04 的服务器,我们强烈建议升级或迁移到支持的 Ubuntu 版本:
原因: Ubuntu 12.04 已於 2017 年 4 月 28 日到達終止期 (EOL) 並不再收到安全性修補或更新。
相反,请参阅: 此指南可能仍然有用作为参考,但可能不会在其他Ubuntu版本上工作. 如果可用,我们强烈建议使用为您正在使用的Ubuntu版本编写的指南。
介绍
连接到互联网的服务器受到恶意用户、脚本和自动机器人的各种攻击和侦查行为,有时保护您的服务器免受攻击而不会影响您的服务和资源的合法访问。
某些类型的服务被认为是可见的和可供公共互联网使用的。一个例子是网页服务器。其他类型的服务通常只被系统管理员或某些个人使用,并且不被认为是公共资源。
一个被称为 port knocking 的概念是隐藏与后者描述相符的流程的一种方式。Port knocking通过覆盖防火墙背后的进程相关的端口,直到发生特定的,预先定义的网络活动序列。
在之前的文章中,我们讨论了 如何通过专门设计的端口敲击服务启用端口敲击。
这种方法不依赖于外部应用程序来改变防火墙规则,相反,iptables
防火墙可以利用一个名为最近
的状态跟踪模块来在防火墙规则内部完成所有这些操作。
我们将在Ubuntu 12.04上配置此功能,但任何类型的Linux服务器都应该以类似的方式运行。
注: _本教程涵盖IPv4安全. 在Linux中,IPv6安全是与IPv4分开维护的。例如,iptables
只维护IPv4地址的防火墙规则,但它有一个名为ip6tables
的IPv6对应,可以用来维护IPv6网络地址的防火墙规则。
如果您的 VPS 已配置为 IPv6,请记住用适当的工具保护您的 IPv4 和 IPv6 网络接口。 有关 IPv6 工具的更多信息,请参阅本指南: 如何在 Linux VPS 上配置工具使用 IPv6 _
Iptables 港口敲击概览
在我们进入实际配置之前,我们将描述最近的模块是如何工作的,以及它如何使我们能够创建一个端口打击系统。
Iptables 可以用 -m
旗号加载模块. 最近的模块可以跟踪连接状态. 我们可以用此来通过连接链的序列来传输我们的端口连接尝试,根据连接用户是否已经击中每个之前所需的端口。
我们将动态重新配置我们的防火墙,允许从我们的计算机SSH连接暂时,一旦一系列端口在序列中被打击
。
我们将在本教程中使用的序列是:
*1111 *2222 *3333
这些值不应该在实际配置中使用。
为了让用户正确身份验证,并让iptables将SSH大象暴露在他们的IP地址上,他们必须以序列击中每个端口,而不会在之间发送非序列流量。
Iptables 配置策略
为了实现上述设计,我们将使用几个不同的链条。
首先,我们将接受我们不希望受到端口敲击的所有流量,包括任何公共资源,如Web服务器,以及来自本地接口的已建立的连接和连接。
随后,我们将将所有未经以前的规则处理的流量重定向到一个新链,在那里我们将把大部分的规则放入。
我们将这个链子称为KNOCKING
。
最近的模块允许我们分类不同的流量类型,然后检查连接是否匹配以前设定的类别。
我们将使用此策略来标记发送包裹到第一个打击目标的IP地址,我们将有一个规则,它会检查第一个打击目标,并检查第二个打击目标是否被发送到第二个打击目标。
额外的链条使用相同的策略,检查相应的旗帜并通过它如果它继续在正确的道路上。最终,一旦最终的包被要求在序列中,SSH大象被暴露了很短的时间,只有成功打击的IP地址。
因此,基本上,如果我们认为我们的端口敲门规则是进入我们的服务的不同门户,我们将有三个门户来敲击我们的三次敲门,这意味着有四个不同的位置,请求IP地址可以在:
*初始状态 : 这是所有IP地址都在的状态,直到他们成功发送一个包到第一个敲击目标. 这不会被最近的模块所设定,而仅仅是一种指代没有设置旗帜的客户端的方法. *auth1状态 : 成功敲出第一个敲击目标的地址被标为"Auth1". 从这里开始,来自此主机的下包将决定地址是否会被放回初始状态或被移动到"Auth2"状态. *auth2状态 : 标有此状态的地址已成功按顺序敲击了第一和第二个目标. 此主机的下个数据包将决定主机是被放回初始状态还是被放回"Auth3"状态. *auth3状态 : 被标记为"Auth3"的地址已经成功敲倒了所有三个端口,按照分配的时间顺序排列. 如果标记为"Auth3"的地址试图现在访问服务(在所提供的窗口中),连接将被接受. 如果收到任何其他流量,地址会被扔回初始状态. .
除了这些状态,这些状态将是由最近的模块设置的旗帜,每个门口或决策点将作为一个链子实现。
*GATE1 :确定初始状态中的地址是否应当被标记为"Auth1". *GATE2 :确定"Auth1"状态中的地址是应该被处理为"Auth2",还是重新设置为"初始"状态. *GATE3 :确定"Auth2"状态中的地址是否应当被标记为"Auth3"以允许SSH连接,或者重置为"初始"状态. *PASSED :此链用于为成功敲门的客户端短暂打开SSH守护进程端口. 任何来自此链条中的客户端的流量,如果不指定给SSH守护进程,都会被放弃,导致状态再次被重置为"初始". .
正如你所看到的,我们在这里有许多决策点。在 KNOCKING 链和其子链中的任何类型的流量都应该被放弃(除了成功打击客户端的SSH大象的流量),无论它是否匹配正确的端口。
试图连接的人不应该收到关于他们在哪个阶段的过程的反馈,甚至如果这样的机制是存在的。
设置常规防火墙框架
我们将首先为我们的连接制定一个基本框架,我们上面谈到的策略将应用于INPUT链,该链处理所有接入连接。
我们将从清除现有的防火墙规则开始,以便我们可以从清洁的板块开始。在清除规则之前,始终建议重申空白表中的默认策略是接受
,以保持当前连接:
1sudo iptables -P INPUT ACCEPT
2sudo iptables -P FORWARD ACCEPT
3sudo iptables -P OUTPUT ACCEPT
4sudo iptables -F
这将确保我们从一个完全开放的防火墙开始,我们可以开始限制。
在我们开始限制之前,我们想添加我们将使用的额外链:
1sudo iptables -N KNOCKING
2sudo iptables -N GATE1
3sudo iptables -N GATE2
4sudo iptables -N GATE3
5sudo iptables -N PASSED
在这一点上,我们应该有八个不同的链条!我们将使用所有这些链条,除了OUTPUT和FORWARD链条,这些链条在这个背景下并不涉及我们。
首先,我们应该添加我们不想处理的端口点击到INPUT链上的流量,我们可以通过接受所有当前连接开始,这将允许我们的当前SSH连接保持不受影响:
1sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
我们还应该接受来自本地机器的所有连接,因为服务往往需要相互通信:
1sudo iptables -A INPUT -i lo -j ACCEPT
如果您有服务应该保持外部和公开可用,例如 Web 服务器,请添加规则以使用此格式允许此类型的连接:
sudo iptables -A INPUT -p protocol --dport port -j ACCEPT
在我们的示例中,我们将假设我们有一个 Web 服务器在默认端口 80 上运行,我们将允许此类流量:
1sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
现在我们已经配置了我们的基本允许连接,我们可以将上述规则中未处理的所有流量转移到我们的 KNOCKING 链,以执行实际的敲击逻辑:
1sudo iptables -A INPUT -j KNOCKING
配置第一扇门
当我们完成配置我们的门
,我们将把它们全部连接到 KNOCKING 链中,通过我们的逻辑测试来引导流量。
当客户端连接时,我们只需要看到他们是否向我们的第一个目标发送了包裹。如果他们是,我们将客户端标记为通过第一个测试并放弃连接。
我们将首先在正确的端口尝试上设置旗帜:
1sudo iptables -A GATE1 -p tcp --dport 1111 -m recent --name AUTH1 --set -j DROP
首先,它将一个规则附加到 GATE1 链上. 当使用的协议是tcp
时,这个规则将匹配,当它试图访问的端口是1111
,我们的第一个打击目标。
如果这是真的,最近的模块(称为)将请求的IP地址标志为AUTH1(使用)。
接下来,我们只会放下所有其他包,因为任何发送到这个链的信息只在这个时刻寻找匹配的第一包:
1sudo iptables -A GATE1 -j DROP
规则要么匹配并标记地址,如果需要正确的端口,要么没有采取任何行动,然后包就丢掉了。
配置第二扇门
第二個門的配置與第一個門相同,但它略有複雜。
首先,将流量发送到这个链条的逻辑将存在于主 KNOCKING 链条中. 这个链条不需要检查第一个网关设置的旗帜是否匹配,因为这已经发生了。
但是,它必须在开始处理之前删除任何旗帜. 如果它没有删除旗帜,那么一个地址可能会被标记为不同的名字,这可能会导致地址通过扫描您的端口三次成功打击。
我们将再次在初步规则中使用最近的模块,这次只是为了清除名称:
1sudo iptables -A GATE2 -m recent --name AUTH1 --remove
这是一个处理规则,所以我们不会做出任何决定或跳跃,我们只是删除当前的旗帜(允许流量进入这个链条的旗帜),并将其发送到下一个规则。
现在该地址已经超过了我们在这个链中的第一个规则,它处于清洁状态,没有旗帜。
1sudo iptables -A GATE2 -p tcp --dport 2222 -m recent --name AUTH2 --set -j DROP
我们简单地设置了AUTH2旗,表示请求地址通过了第二次测试,如果正确的端口被点击了。
下一个规则可能起初看起来有点奇怪。
1sudo iptables -A GATE2 -j GATE1
您可以假设在这一点上仅仅放弃包裹是逻辑的事情,然而,这会在某个特定情况下导致一个尴尬的局面。
如果我们在这里有一个放下所有
规则,并且此时发送的包匹配 first knock 目标,它将不会被注册为 knock 序列的开始。
例如,如果我们的客户端意外击中第一个端口两次,它将不会注册为正确的,因为防火墙会看到序列如下:
- 第一個端口打擊. 防火牆顯示第一個端口測試已經通過. 將檢查第二個端口接下來. * 第一個端口打擊. 不匹配第二個端口規則. 序列已重新設定. 將檢查第二個端口接下來. 未匹配第一個端口規則。
正如你所看到的,第一个,第二个,第三个序列已经完成,但防火墙已经对它应该检查的规则感到困惑。
为了避免这种情况,我们将不只是在这一点上放下包并完成它,而是将利用我们已经配置的GATE1链,正如我们上面所示,我们可以简单地将不匹配第二个打击目标的流量再次发送到第一个门口:
1sudo iptables -A GATE2 -j GATE1
这将导致客户端在序列中的位置以两种方式重置。如果请求是第一个端口,序列将作为成功的第一个打击重新启动。
设置第三个门
我们可以利用我们从第二个门口中学到的东西,以同样的方式实现第三个门口。
首先,我们要清除给我们的地址的所有旗帜,这样,通过链条的运行将设置正确的状态,而没有以前的旗帜:
1sudo iptables -A GATE3 -m recent --name AUTH2 --remove
接下来,我们将测试连接尝试是否匹配第三个打击目标。如果是,我们设置了AUTH3旗,这表明客户端成功完成了所有所需的打击。
1sudo iptables -A GATE3 -p tcp --dport 3333 -m recent --name AUTH3 --set -j DROP
從這裡,我們再次將不匹配第三個打擊目標的流量傳回第一個門口,看看它是否應算為成功的第一個打擊來重新啟動序列:
1sudo iptables -A GATE3 -j GATE1
在此时,已经完成正确的敲击序列的客户应该被标记为AUTH3,这将使我们能够在 PASSED链中轻松为他们打开服务。
配置过链
这个链被用来打开SSH大象30秒到客户端谁成功打正确的序列。
我们以与其他人相同的方式开始此操作. SSH DAEMON 仅在接下来的客户端发送的软件包要求时才可用,这就迫使那些随机尝试过击的用户在每个尝试之间尝试建立 SSH 连接。
首先,我们做通常的旗帜重置:
1sudo iptables -A PASSED -m recent --name AUTH3 --remove
接下来,我们接受了将其连接到这个链上的用户的SSH连接:
1sudo iptables -A PASSED -p tcp --dport 22 -j ACCEPT
再次,我们将所有不匹配的流量送回我们的第一个链,看看是否匹配第一个端口打击目标:
1sudo iptables -A PASSED -j GATE1
现在,我们已经配置了我们所有的子链,但我们的一般的 KNOCKING 链,将流量传入这些个别链。
配置敲击链
现在我们已经配置了所有子链,我们可以将它们连接到我们的总体 KNOCKING 链中,并创建如何传输流量的逻辑。
首先,我们将从成功完成所有打击的客户的流量直接传入 PASSED 链。
我们有一些选项,但我们可以实施一个时间限制,只给成功的客户端一个30秒窗口连接到戴蒙之后,规则将不再成功匹配。
1sudo iptables -A KNOCKING -m recent --rcheck --seconds 30 --name AUTH3 -j PASSED
接下来,我们将测试其他旗帜的每一个,从最限制的到最少的。我们可以添加10秒的时间限制,然后在之前的打击到期之前。
1sudo iptables -A KNOCKING -m recent --rcheck --seconds 10 --name AUTH2 -j GATE3
2sudo iptables -A KNOCKING -m recent --rcheck --seconds 10 --name AUTH1 -j GATE2
现在,我们想要像往常一样将所有尚未匹配的流量送回GATE1,这将捕捉任何第一次打击的尝试:
1sudo iptables -A KNOCKING -j GATE1
这将基本上为我们的 KNOCKING 链设置默认下降策略,即将 GATE1 逻辑添加到 KNOCKING 链的末尾。
在这一点上,我们有我们所有的敲击链位。我们添加了一些额外的结构来分区我们的逻辑.整个KNOCKING链结构及其子链都连接到我们的常规输入链。
此时,我们的端口敲击机制已配置,是时候进行测试了。
测试我们的港口打击
有许多实用程序可以用来生成我们需要的TCP包,我们将使用nmap
命令,因为它在大多数系统中默认存在。
Nmap 默认情况下使用 TCP 包,我们需要告诉它将默认行为的发现部分放到主机上,以便这些包不会干扰我们的打击,此外,我们希望我们的连接仅在一秒钟后结束,以便我们可以继续到下一个打击。
有了这些要求,一个单击可能会看起来像这样,我们将使用我们的第一击目标作为一个例子:
nmap -Pn --host_timeout 201 --max-retries 0 -p 1111 your_server
因此,我们整个敲击序列可以用这些命令来表示:
nmap -Pn --host_timeout 201 --max-retries 0 -p 1111 your_server nmap -Pn --host_timeout 201 --max-retries 0 -p 2222 your_server nmap -Pn --host_timeout 201 --max-retries 0 -p 3333 your_server
然后我们将有30秒的时间连接到我们的SSH客户端。
我们可以利用一些非常基本的bash脚本来自动化这一点,我们可以使用一个for
循环来迭代我们的端口序列,然后将其传递给SSH客户端:
for x in 1111 2222 3333; do nmap -Pn --host_timeout 201 --max-retries 0 -p $x your_server && sleep 1; done && ssh user@your_server
这会点击第一个端口,等待一秒钟,点击下一个端口,等等,直到序列完成。
我们可以把它放到一个文件中来清理一下,我们会称之为knock_client
。
nano knock_client
# !/bin/bah ports="1111 2222 3333" host="your_server" for x in $ports do nmap -Pn --host_timeout 201 --max-retries 0 -p $x $host sleep 1 done ssh user@${host}
保存并关闭文件。
使用此命令使文件可执行:
1chmod 755 knock_client
现在,我们可以通过键入连接到我们的服务器:
1./knock_client
现在我们已经验证了我们的规则按预期运作,我们可以通过在我们的服务器上下载单独的包来使我们的防火墙规则持久:
1sudo apt-get install iptables-persistent
我们可以通过启用此服务,在 boot 上应用我们的规则:
1sudo service iptables-persistent start
结论
到目前为止,你应该有一个完全可操作的端口打击系统,只使用 iptables 防火墙中包含的功能。这有几个优点。首先,iptables 是非常常用的,并且经常对安全问题进行审计。
这个配置提供的另一个优点,而不是一个单独的打击戴蒙,是打击服务没有失败的机会,并将您锁定在您的服务器上。