【问题标题】:How can I measure time in Java not susceptible to System clock changes?如何在 Java 中测量不受系统时钟变化影响的时间?
【发布时间】:2009-12-21 00:25:17
【问题描述】:

我想在 Java 中测量经过的时间。但是System.currentTimeMillis() 和(我相信)System.nanoTime() 的差异可以通过外部更改来更改,例如某人(或系统)更改系统时钟。

使用网络调用不是一种选择,因为它可能需要非常频繁和快速的返回。

有没有通用的解决方案?

编辑

对不起,我应该详细说明原因。这不是为了阻止恶意用户 - 它是诸如客户端因空闲和常规客户端事件而发起的注销之类的事情。

【问题讨论】:

  • 这是有正当理由的 - 例如有时间限制的许可证,以及试图通过倒计时来阻止人们破坏许可证。
  • 或者例如获取可靠的 UID 时间。
  • 我问的原因是因为如果有人有能力操纵系统时钟,他们可以在本地系统上为所欲为,以颠覆您的应用程序。如果你不能信任System.currentTime,你就不能信任系统给你的任何时候,而远程源真的是唯一的选择。

标签: java clock


【解决方案1】:

这并不能真正回答您的问题,但bug #6458294 暗示在可能的情况下,Sun 的 nanoTime() 实现将使用真正单调的机制(Linux 上的 CLOCK_MONOTONIC,Windows 上的 QueryPerformanceFrequency/QueryPerformanceCounter)。只有当这些不可用时,它才会退回到易受系统时钟变化影响的机制。

如果您可以控制(或至少了解)正在运行的硬件,并且可以确保这些时钟机制可用,那么您可能很幸运,nanoTime() 会做得很好。

您可能还想阅读this blog post,其中更详细地讨论了 HotSpot-on-Windows 案例。

【讨论】:

  • 谢谢,这确实回答了我的问题。 Monotonic 也是搜索更多信息的好词。
【解决方案2】:

我认为没有办法做到这一点。

当然没有不能颠覆的方法。从根本上说,您受操作系统和 JVM 的支配,以决定向 Java 应用程序报告的当前时间。可以修补其中一个或两个,以便 Java 代码最终得到一个虚假的时间戳值。您可以尝试对此进行防御,但黑客所需要做的就是修补您的应用程序以完全禁用许可证检查。

为了记录,无论您是否使用 Java,此“漏洞”都适用。

【讨论】:

    【解决方案3】:

    如果您试图通过调回时钟来阻止人们破坏许可方案,您需要将迄今为止看到的最长时间存储在某种加密和安全的存储中,然后在出现以下情况时禁用该程序要么时间少于你所见过的最高时间(当然还有一些 NTP 时钟调整和 DST 更改的余量),要么他们以某种方式篡改或删除了安全存储。

    【讨论】:

      【解决方案4】:

      如果系统时钟发生变化,我不知道 nanoTime() 是否会发生变化,但我想这是可能的。 nanoTime() 也可能不准确。

      如果你真的需要防止时钟变化,你可以在一个线程中监控时钟。休眠 100 毫秒或 1000 毫秒,然后调用 currentTimeMillis()。如果时钟提前超过 1000 + x 或已经倒退,那么时钟可能发生了变化(或者线程被挂断了,这是可能的)。

      如果发生分离,您实际上可以进行网络调用进行检查。当然,网络时间有可能因为leap seconds的插入而改变。我曾经读过一些科学家的 Slashdot 评论,他们正在协调来自许多不同来源的天文数据。在他的实验过程中添加了闰秒,它基本上毁了它,因为有些网站插入了它,而另一些则没有。

      另一种可能性可能是使用低级别的本机 API 来获取其他一些系统计时器。例如校准 API 的系统或网络正常运行时间。 Windows 具有 getTickCount() 函数,该函数返回自启动以来的毫秒数。在 unix 系统上,您可以使用 uptime 命令进行粗略估计。您可以定期检查这些值以查看系统时钟是否已更改。

      【讨论】:

      • 这是有缺陷的。 Thread.sleep 不保证永远返回。使用 Object.wait
      【解决方案5】:

      如果您不介意在 Java 应用中添加一些本机代码,请使用:

      • QueryPerformanceCounter()QueryPerformanceFrequency() 在 Windows 上;或

      • POSIX clock_gettime() 函数与 CLOCK_MONOTONIC 时钟 ID。

      请注意,不鼓励在多处理器系统上使用 x86 TSC register,因此您最好使用上述 API。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-04-29
        • 1970-01-01
        • 2013-11-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-16
        相关资源
        最近更新 更多