禁用 TCP 时间戳的优缺点

信息安全 网络 linux tcp 时间戳 核心
2021-08-27 00:08:28

所以,lynis 告诉我我应该 unset net.ipv4.tcp_timestamps我知道这是一件坏事,因为攻击者可以找出哪些更新需要重新启动我尚未应用的机器,或者他们可以使用它来找出我的更新计划并尝试在机器重新启动的短暂时间间隔内进行攻击,但是在防火墙上线之前,或者其他我没有想到的东西。

我知道这并不理想。

但是,根据RFC 1323(和this):

时间戳用于两种不同的机制:RTTM(往返时间测量)和 PAWS(防止包装序列)

这些看起来也不错,有用的东西。话虽如此,我的网络类中的 IIRC 认为 RTTM 方法绝对不是确定 RTT 所必需的,而且 TCP 的滑动窗口使得序列环绕问题不太可能发生,但由于这不是开玩笑的 RFC 之一,我假设他们有一个提出这些东西的充分理由和实施者有充分理由实施它们。

禁用此功能是否有任何(可能的)缺点/负面可用性或安全隐患?

此外,有什么方法可以让我既吃又吃蛋糕(例如,通过告诉内核用随机值初始化并将抖动引入时间戳更新的周期,或者用一些位初始化它)系统时钟,所以他们不能使用时间戳的突然大变化来告诉最近发生了重新启动)?

3个回答

缺点是 TCP 序列可以换行。这对超高速网络来说是一种风险。但是,正如您所要求的那样,您可以随机化初始时间戳。这是一个非常简单的补丁,因此任何拒绝都将是微不足道的修复。它要求已经应用了 grsecurity 补丁集。

来自https://grsecurity.net/~spender/random_timestamp.diff

diff --git a/grsecurity/Kconfig b/grsecurity/Kconfig
index 3abaf02..700e56c 100644
--- a/grsecurity/Kconfig
+++ b/grsecurity/Kconfig
@@ -925,6 +925,16 @@ config GRKERNSEC_RANDNET
      here.  Saying Y here has a similar effect as modifying
      /proc/sys/kernel/random/poolsize.

+config GRKERNSEC_RANDOM_TIMESTAMPS
+   bool "Add random offset to TCP timestamps"
+   default y if GRKERNSEC_CONFIG_AUTO
+   help
+     If you say Y here, a simple change will be made to TCP timestamp
+     behavior that will prevent the system from leaking the jiffies
+     value remotely to an attacker who has not been persistently
+     monitoring the system since boot.  The jiffies value can be used
+     to remotely determine system uptime.
+
 config GRKERNSEC_BLACKHOLE
    bool "TCP/UDP blackhole and LAST_ACK DoS prevention"
    default y if GRKERNSEC_CONFIG_AUTO
diff --git a/grsecurity/grsec_init.c b/grsecurity/grsec_init.c
index ae6c028..c7dbe97d 100644
--- a/grsecurity/grsec_init.c
+++ b/grsecurity/grsec_init.c
@@ -7,6 +7,11 @@
 #include <linux/percpu.h>
 #include <linux/module.h>

+#ifdef CONFIG_GRKERNSEC_RANDOM_TIMESTAMPS
+__u32 random_timestamp_base __latent_entropy;
+EXPORT_SYMBOL_GPL(random_timestamp_base);
+#endif
+
 int grsec_enable_ptrace_readexec;
 int grsec_enable_setxid;
 int grsec_enable_symlinkown;
diff --git a/include/net/sock.h b/include/net/sock.h
index b2948c0..ccbeda9 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -2296,4 +2296,8 @@ extern int sysctl_optmem_max;
 extern __u32 sysctl_wmem_default;
 extern __u32 sysctl_rmem_default;

+#ifdef CONFIG_GRKERNSEC_RANDOM_TIMESTAMPS
+extern __u32 random_timestamp_base;
+#endif
+
 #endif /* _SOCK_H */
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 44a58b0..fcdca06 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -684,7 +684,11 @@ void tcp_send_window_probe(struct sock *sk);
  * to use only the low 32-bits of jiffies and hide the ugly
  * casts with the following macro.
  */
+#ifdef CONFIG_GRKERNSEC_RANDOM_TIMESTAMPS
+#define tcp_time_stamp     ((__u32)(jiffies) + random_timestamp_base)
+#else
 #define tcp_time_stamp     ((__u32)(jiffies))
+#endif

 #define tcp_flag_byte(th) (((u_int8_t *)th)[13])

diff --git a/net/core/dev.c b/net/core/dev.c
index f3e28ec..8b1cf12 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -6986,6 +6986,10 @@ static int __init net_dev_init(void)

    BUG_ON(!dev_boot_phase);

+#ifdef CONFIG_GRKERNSEC_RANDOM_TIMESTAMPS
+   random_timestamp_base += prandom_u32();
+#endif
+
    if (dev_proc_init())
        goto out;

请注意,自发布以来,较新的内核已经集成了与此类似的东西。

linux:没有更多的内核补丁。

在较新的内核上,您可以使用 net.ipv4.tcp_timestamps = 1

启用 RFC1323 中定义的时间戳,并为每个连接使用随机偏移量,而不是仅使用当前时间

他们选择改变语义:在旧内核中,tcp_timestamps = 1启用由时间支持的时间戳。

现在要获得旧行为,您必须设置 tcp_timestamps = 2

我认为他们选择更改默认行为是因为对普通用户没有任何不利影响。

另一个优点是,根据 RedHat的说法,它减少了与时间戳生成相关的性能峰值。