如何测量Java中不受系统时钟变化影响的时间?

时间:2009-12-21 00:25:17

标签: java clock

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

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

这是否有共同的解决方案?

修改

对不起,我应该详细说明原因。它不是要阻止恶意用户 - 就像客户端发起的空闲登出和常规客户端事件一样。

5 个答案:

答案 0 :(得分:5)

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

当然没有办法做到这一点,不能被颠覆。从根本上说,您受操作系统和JVM的支配,因为当前时间报告给Java应用程序的内容。可以修补其中任何一个或两个,以便Java代码最终获得伪造的时间戳值。您可以尝试防范此问题,但黑客需要做的就是修补您的应用以完全禁用许可证检查。

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

答案 1 :(得分:5)

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

如果你对正在运行的硬件有控制(或至少知识),并且可以确保这些时钟机制可用,那么你可能很幸运,nanoTime()也可以。

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

答案 2 :(得分:4)

如果您试图通过设置时钟来阻止人们破坏许可证方案,您需要存储到目前为止在某种加密和安全存储中看到的最长时间,然后禁用该程序要么时间少于你看到的最高时间(当然要考虑NTP时钟调整和DST更改),要么他们以某种方式篡改或删除安全存储。

答案 3 :(得分:2)

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

如果你真的需要防止时钟变化,你可以监视线程中的时钟。睡眠100毫秒或1000毫秒,然后调用currentTimeMillis()。如果时钟提前超过1000 + x或已经倒退,则可能时钟发生了变化(或者线程挂起了某些东西,这是可能的)。

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

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

答案 4 :(得分:1)

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

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

  • 带有clock_gettime()时钟ID的POSIX CLOCK_MONOTONIC功能。

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