使用 knockd 实现端口敲门安全

作者:Federico Kereki

在处理计算机安全时,您应该假设黑客会尝试通过您的系统可能存在的任何可用入口进入,无论您可能采取了多少预防措施。根据密码允许进入的方法是一种经典且被广泛使用的方法。为了“打开一扇门”(意味着连接到您计算机上的端口),您首先必须指定正确的密码。这可以奏效(前提是密码足够强大以至于难以破解,并且您不会成为许多可能泄露密码的黑客攻击的受害者),但这仍然存在问题。仅仅知道一扇门存在就足以诱惑潜在的入侵者。

因此,可以将打开的端口视为一扇(可能)带有锁的门,其中密码充当钥匙。如果您正在运行某种公共服务(例如,Web 服务器),那么很明显您不能过度保护;否则,没有人能够使用您的服务。但是,如果您只想允许少数人访问,您可以向世界其他地方隐藏实际上存在通往系统的门这一事实。您可以通过不仅在门上安装锁,而且还隐藏锁本身来“敲走入侵者”!端口敲门是一种保护端口的简单方法,使其保持关闭状态且对外界不可见,直到用户提供秘密敲门,然后(且仅在此之后)端口才会打开,以便他们可以输入密码并进入。

端口敲门适用于需要访问非公开可用服务器的用户。服务器可以保持所有端口关闭,但在用户通过提供特定的敲门序列(一种密码)验证身份后,按需打开这些端口。端口打开后,通常的安全机制(密码、证书等)适用。这是一个额外的优势;受保护的服务不需要任何修改,因为额外的安全性是在防火墙级别提供的。最后,端口敲门易于实现,并且资源消耗非常少,因此不会对服务器造成任何过载。

在本文中,我将解释如何实现端口敲门,以便为您的系统安全增加另一层保护。

你安全吗?

潜在的黑客无法攻击您的系统,除非他们知道要尝试哪个端口。有很多端口扫描工具可用。检查您机器安全级别的一种简单方法是运行在线测试,例如 GRC 的 ShieldsUp(图 1)。图 1 中的测试结果表明,攻击者甚至不知道机器可以被攻击,因为所有端口查询都被忽略且未得到响应。

Implement Port-Knocking Security with knockd

图 1. 完全锁定的站点,处于“隐身”模式,不会向攻击者提供任何信息,攻击者甚至无法得知该站点实际存在。

另一个常用工具是 nmap,它是一个名副其实的扫描和检查选项的瑞士军刀。nmap -v your.site.url命令将尝试查找任何打开的端口。请注意,默认情况下,nmap 仅检查 1-1000 范围,其中包括所有“常用”端口,但您可以通过添加-p1-65535参数进行更彻底的测试。列表 1 显示了如何确信您的站点对外界是关闭的。因此,既然您知道自己是安全的,那么您如何打开端口,但又使其不被发现呢?

列表 1. 标准 nmap 端口扫描工具提供了另一个确认,即您的站点和所有端口对外界完全关闭。

$ nmap -v -A your.site.url

Starting Nmap 4.75 ( http://nmap.org ) at 2009-10-03 12:59 UYT
Initiating Ping Scan at 12:59
Scanning 190.64.105.104 [1 port]
Completed Ping Scan at 12:59, 0.00s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 12:59
Completed Parallel DNS resolution of 1 host. at 12:59, 0.01s elapsed
Initiating Connect Scan at 12:59
Scanning r190-64-105-104.dialup.adsl.anteldata.net.uy (190.64.105.104) 
 [1000 ports]
Completed Connect Scan at 12:59, 2.76s elapsed (1000 total ports)
Initiating Service scan at 12:59
SCRIPT ENGINE: Initiating script scanning.
Host r190-64-105-104.dialup.adsl.anteldata.net.uy (190.64.105.104) 
 appears to be up ... good.
All 1000 scanned ports on r190-64-105-104.dialup.adsl.anteldata.net.uy
 (190.64.105.104) are closed

Read data files from: /usr/share/nmap
Service detection performed. Please report any incorrect results 
 at http://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 2.94 seconds
秘密握手、轻敲和敲门

端口敲门背后的想法是关闭所有端口并监视连接到它们的尝试。每当识别出非常特定的尝试序列(敲门序列),并且仅在这种情况下,系统才能配置为执行某些特定操作,例如打开给定的端口,以便外部人员可以进入。敲门序列可以像您希望的那样复杂 - 例如,从一个简单的列表(如尝试 TCP 端口 7005,然后是 TCP 端口 7006,最后是 TCP 端口 7007)到一个仅使用一次的序列集合,一旦使用,将不再允许再次使用。这相当于“一次性密码本”,这是一种密码学方法,当正确使用时,可以提供完美的保密性。

在设置此项之前,让我解释一下为什么这是一个好的安全措施。有 65,535 个可能的端口,但在丢弃已使用的端口后(请参阅资源中已分配端口的列表),假设您只剩下“仅”50,000 个可用端口。如果攻击者必须猜测五个不同端口的序列,则他们应该尝试大约 312,000,000,000,000,000,000,000 种可能的组合。显然,暴力破解方法无济于事!当然,您不应假设盲目的运气是唯一可能的攻击,这就是为什么端口敲门不应该是您使用的唯一安全措施,而只是攻击者需要通过的另一层额外保护(图 2)。

Implement Port-Knocking Security with knockd

图 2. 潜在的攻击者(顶部)被防火墙简单地拒绝,但是当合法用户(中间)提供正确的“敲门”序列时,防火墙(底部)允许访问特定端口,以便用户可以与服务器一起工作。

在您要保护的机器上,安装 knockd 守护程序,它将负责监视敲门尝试。此软件包适用于所有发行版。例如,在 Ubuntu 中,运行sudo apt-get install knockd,在 OpenSUSE 中,运行sudo zypper install knockd或使用 YaST。现在您需要通过编辑 /etc/knockd.conf 文件来指定您的敲门规则,并启动守护程序运行。列表 2 显示了一个配置示例。注意:给定的 iptables 命令适用于运行标准防火墙的 OpenSUSE 发行版,其中 eth0 位于外部区域;对于其他发行版和设置,您将需要确定要使用的命令。

列表 2. 一个简单的 /etc/knockd.conf 文件,它需要连续敲击端口 7005、7007 和 7006 才能启用安全外壳 (SSH) 访问。

[opencloseSSH]
  sequence      = 7005,7006,7007
  seq_timeout   = 15
  tcpflags      = syn
  start_command = /usr/sbin/iptables -s %IP% -I input_ext 1
                  ↪-p tcp --dport ssh -j ACCEPT
  cmd_timeout   = 30
  stop_command  = /usr/sbin/iptables -s %IP% -D input_ext
                  ↪-p tcp --dport ssh -j ACCEPT

您可能可以推测出这会查找三个敲击的序列 - 7005、7006 和 7007(不是很安全,但只是一个示例) - 然后打开或关闭 SSH 端口。此示例允许输入敲门序列的最大超时时间(15 秒)和一个登录窗口(30 秒),在此期间端口将保持打开状态。现在,让我们测试一下。

首先,您可以看到,在不运行 knockd 的情况下,从远程机器登录的尝试只是失败

$ ssh your.site.url -o ConnectTimeout=10
ssh: connect to host your.site.url port 22: Connection timed out

接下来,让我们启动 knockd 服务器。通常,您会通过以下方式以 root 身份运行它knockd -d/etc/init.d/knockd start;但是,目前,为了让您看到发生了什么,让我们在调试模式下运行它,使用knock -D:

# knockd -D
config: new section: 'opencloseSSH'
config: opencloseSSH: sequence: 7005:tcp,7006:tcp,7007:tcp
config: opencloseSSH: seq_timeout: 15
config: tcp flag: SYN
config: opencloseSSH: start_command:
          /usr/sbin/iptables -s %IP% -I input_ext 1
                             -p tcp --dport ssh -j ACCEPT
config: opencloseSSH: cmd_timeout: 30
config: opencloseSSH: stop_command:
          /usr/sbin/iptables -s %IP% -D input_ext
                             -p tcp --dport ssh -j ACCEPT
ethernet interface detected
Local IP: 192.168.1.10

现在,让我们回到远程机器。您可以看到 ssh 尝试仍然失败,但在三个 knock 命令之后,您可以进入

$ ssh your.site.url -o ConnectTimeout=10
ssh: connect to host your.site.url port 22: Connection timed out
$ knock your.site.url 7005
$ knock your.site.url 7006
$ knock your.site.url 7007
$ ssh your.site.url -o ConnectTimeout=10
Password:
Last login: Sat Oct  3 14:58:45 2009 from 192.168.1.100
...

查看服务器上的控制台,您可以看到敲门正在进入

2009-09-03 15:29:47:
     tcp: 190.64.105.104:33036 -> 192.168.1.10:7005 74 bytes
2009-09-03 15:29:50:
     tcp: 190.64.105.104:53783 -> 192.168.1.10:7006 74 bytes
2009-09-03 15:29:51:
     tcp: 190.64.105.104:40300 -> 192.168.1.10:7007 74 bytes

如果远程敲门序列错误,则不会有可见的结果,并且 SSH 端口将保持关闭状态,没有人会知道。

配置和运行 knockd

配置文件 /etc/knockd.conf 分为多个部分,每个部分对应一个特定的敲门序列,还有一个特殊的通用部分 options 用于全局参数。让我们首先了解一下通用选项

  • 您可以使用LogFile=/path/to/log/file将事件记录到特定文件,或使用UseSyslog记录到标准 Linux 日志文件。注意:有时建议您避免此类日志记录,因为它为攻击者提供了额外的可能目标 - 如果他们掌握了日志,他们将拥有端口敲门序列。

  • 当 knockd 作为守护程序运行时,您可能需要检查它是否仍在运行。PidFile=/path/to/PID/file选项指定一个文件,knockd 的 PID(进程 ID)将存储在该文件中。一个有趣的点:如果 knockd 崩溃,您的系统将比以往任何时候都更安全 - 所有端口都将关闭(因此更安全),但完全无法访问。您可以考虑实现一个 cron 任务,该任务将定期检查 knockd PID,并在需要时重新启动守护程序。

  • 默认情况下,eth0 将是观察到的网络接口。您可以使用类似Interface=eth1的内容更改此设置。您不得包含设备的完整路径,只需其名称即可。

您要识别的每个序列都需要一个名称;示例(列表 2)仅使用一个,名为 openclosessh。选项及其参数可以用大写、小写或混合大小写书写

  • Sequence用于指定所需的敲门系列 - 例如,7005,7007:udp,7003。敲门通常是 TCP,但您可以选择 UDP。

  • One_Time_Sequences=/path/to/file允许您指定一个包含“一次性”序列的文件。每次使用序列后,它将被删除。您只需要一个文本文件,其中每行都有一个序列(以上格式)。

  • Seq_Timeout=seconds.to.wait.for.the.knock是完成序列的最大等待时间。如果您敲门时间过长,您将无法进入。

  • Start_Command=some.command指定在识别出敲门序列后必须执行的命令(单行或完整脚本)。如果您包含 %IP% 参数,它将在运行时被敲门者的 IP 替换。这允许您,例如,打开防火墙端口,但仅对敲门者而不是对任何人打开。此示例使用 iptables 命令打开端口(有关更多信息,请参阅资源)。

  • Cmd_Timeout=seconds.to.wait.after.the.knock允许您在启动命令运行后的一定时间后执行第二个命令。您可以使用它来关闭端口;如果敲门者没有及时登录,端口将被关闭。

  • Stop_Command=some.other.command是在第二次超时后将执行的命令。

  • TCPFlags=list.of.flags允许您检查传入的 TCP 数据包并丢弃那些与标志不匹配的数据包(FIN、SYN、RST、PSH、ACK 或 URG;有关更多信息,请参阅资源)。在 SSH 连接上,您应该使用TCPFlags=SYN,这样其他流量就不会干扰敲门序列。

对于此示例的目的(远程打开和关闭端口 22),您只需要一个序列,如列表 2 所示。但是,没有任何要求只有一个序列,而且,命令也不必打开端口!每当识别出敲门序列时,给定的命令将被执行。在示例中,它打开了一个防火墙端口,但它可以用于您可能想到的任何其他功能 - 触发备份、运行特定进程、发送电子邮件等等。

knockd 命令接受以下命令行选项

  • -c 允许您指定不同的配置文件,而不是通常的 /etc/knockd.conf。

  • -d 使 knockd 在后台作为守护程序运行;这是标准的工作方式。

  • -h 提供语法帮助。

  • -i 允许您更改要侦听的接口;默认情况下,它使用您在配置文件中指定的接口,如果未指定,则使用 eth0。

  • -l 允许查找日志条目的 DNS 名称,但这被认为是糟糕的做法,因为它会迫使您的机器失去隐身性并进行 DNS 流量,这可能会被监视。

  • -v 生成更详细的状态消息。

  • -D 输出调试消息。

  • -V 显示当前版本号。

为了发送所需的敲门,您可以使用任何程序,但 knockd 软件包附带的 knock 命令是通常的选择。上面显示了其用法的示例(knock your.site.url 7005),用于在端口 7005 上进行 TCP 敲门。对于 UDP 敲门,要么添加 -u 参数,要么执行knock your.site.url 7005:udp。-h 参数提供(简单)语法描述。

如果您位于路由器后面

如果您没有直接连接到互联网,而是通过路由器连接,则需要进行一些配置更改。您如何进行这些更改取决于您的特定路由器和您使用的防火墙软件,但一般来说,您应该执行以下操作

1) 将敲门端口转发到您的机器,以便 knockd 能够识别它们。

2) 将端口 22 转发到您的机器。尽管实际上,您可以将任何其他端口(例如,22960)转发到您机器上的端口 22,并且远程用户将不得不ssh -p 22960 your.site.url才能连接到您的机器。这可以被视为“通过混淆实现安全”——至少是对抗脚本小子的一种防御。

3) 配置您机器的防火墙以拒绝连接到端口 22 和敲门端口

$ /usr/sbin/iptables -I INPUT 1 -p tcp --dport ssh -j REJECT
$ /usr/sbin/iptables -I INPUT 1 -p tcp --sport 7005:7007 -j REJECT

然后,允许 SSH 连接的命令将是

$ /usr/sbin/iptables -I INPUT 1 -p tcp --dport ssh -j ACCEPT

并且,再次关闭它的命令将是

$ /usr/sbin/iptables -D INPUT -p tcp --dport ssh -j ACCEPT
结论

端口敲门不能成为您武器库中唯一的安全武器,但它可以帮助为您的机器增加额外的屏障,并使黑客更难在您的系统中立足。

资源

knockd 页面位于 www.zeroflux.org/projects/knock,您可以在 linux.die.net/man/1/knockd 找到 knockd 手册页文档,或者只需在控制台中执行man knockd即可。

有关端口敲门的更多信息,请查看 www.portknocking.org/view,特别是,请参阅 www.portknocking.org/view/implementations 以了解更多实现方式。此外,您还可以查看 www.linux.com/archive/articles/37888 上的评论以及 www.portknocking.org/view/about/critique 上的回复,以了解有关端口敲门的观点/反驳观点。

阅读 en.wikipedia.org/wiki/Transmission_Control_Protocol 了解 TCP 标志,尤其是 SYN。在 www.faqs.org/docs/iptables/tcpconnections.html,您可以找到一个很好的图表,显示了标志的使用方式。

端口号由 IANA(互联网号码分配机构)分配;有关列表,请参阅 www.iana.org/assignments/port-numbers

要测试您的站点,请在 nmap.org 获取 nmap,并访问 GRC(Gibson 研究公司)的站点 https://www.grc.com,并尝试 ShieldsUp 测试。

如果您需要复习您的 iptables 技能,请查看 www.netfilter.org

Federico Kereki 是一位乌拉圭系统工程师,在大学教学、进行开发和咨询工作以及撰写文章和课程材料方面拥有超过 20 年的经验。他使用 Linux 多年,并在多家不同的公司安装了 Linux。他对 Linux 盒子的更好安全性和性能特别感兴趣。

加载 Disqus 评论