Как я могу измерить время в Java, не подверженное изменениям системных часов?

StackOverflow https://stackoverflow.com/questions/1937619

  •  20-09-2019
  •  | 
  •  

Вопрос

Я хотел бы измерить прошедшее время в Java.Однако различия в System.currentTimeMillis() и (я верю) System.nanoTime() может быть изменен внешними изменениями, например, кем-то (или системой), изменяющим системные часы.

Использование сетевых вызовов не является вариантом, так как, возможно, требуются очень частые и быстрые возвраты.

Есть ли общее решение для этого?

Редактировать

Извините, я должен был подробнее рассказать о причине.Это делается не для того, чтобы остановить злоумышленников - это такие вещи, как инициированный клиентом выход из системы из-за простоя и обычные клиентские события.

Это было полезно?

Решение

На самом деле это не отвечает на ваш вопрос, но ошибка #6458294 подразумевает, что там, где это возможно, реализация Sun nanoTime() будет использовать механизмы, которые действительно монотонны (CLOCK_MONOTONIC в Linux, QueryPerformanceFrequency / QueryPerformanceCounter в Windows).Только если они недоступны, он вернется к механизму, который подвержен изменениям системных часов.

Если у вас есть контроль (или, по крайней мере, знания) над оборудованием, на котором вы работаете, и вы можете гарантировать, что эти часовые механизмы будут доступны, возможно, вам повезет, и nanoTime () справится.

Возможно, вам также понравится читать это сообщение в блоге, в котором более подробно рассматривается случай HotSpot-on-Windows.

Другие советы

Я не думаю, что есть способ сделать это.

Конечно, нет такого способа сделать это, который нельзя было бы ниспровергнуть.По сути, вы находитесь во власти операционной системы и JVM относительно того, что сообщается Java-приложению в качестве текущего времени.Любой из них или оба из них могут быть исправлены таким образом, чтобы Java-код в конечном итоге получал поддельное значение метки времени.Вы могли бы попытаться защититься от этого, но тогда все, что нужно сделать хакеру, это исправить ваше приложение, чтобы полностью отключить проверку лицензий.

Между прочим, эта "уязвимость" применима независимо от того, используете вы Java или нет.

Если вы пытаетесь помешать пользователям нарушать схему лицензирования, переводя часы вспять, вам нужно сохранить самое высокое время, которое вы видели на данный момент, в каком-либо зашифрованном и безопасном хранилище, а затем отключить программу, если либо время будет меньше самого высокого, которое вы видели (с некоторым учетом настроек часов NTP и изменений летнего времени, конечно), либо если они каким-то образом подделают или удалят безопасное хранилище.

Я не знаю, может ли nanoTime () измениться при изменении системных часов, но я полагаю, что это возможно.Также nanoTime() может быть неточным.

Если вам действительно нужно защититься от изменений часов, вы могли бы отслеживать часы в потоке.Спите в течение 100 мс или 1000 мс, затем вызовите currentTimeMillis().Если часы продвинулись более чем на 1000 + x или пошли назад, то, вероятно, часы изменились (или поток зациклился на чем-то, что возможно).

В случае дизъюнкции вы действительно можете выполнить сетевой вызов для проверки.Конечно, возможно, что сетевое время может измениться из-за вставки високосные секунды.Однажды я прочитал комментарий на Slashdot некоторых ученых, которые координировали астрономические данные из множества разных источников.Во время его эксперимента была добавлена високосная секунда, и это в основном все испортило, потому что некоторые сайты вставили ее, а другие нет.

Другой возможностью может быть использование низкоуровневого нативного API для получения некоторых других системных таймеров.Например, время безотказной работы системы или сети для калибровки API.В Windows есть функция GetTickCount(), которая возвращает количество миллисекунд с момента загрузки.В системах unix вы можете использовать команду uptime для получения приблизительной оценки.Вы можете периодически проверять эти значения, чтобы узнать, изменились ли системные часы.

Если вы не возражаете добавить немного собственного кода в свое Java-приложение, используйте:

  • QueryPerformanceCounter() и QueryPerformanceFrequency() в Windows;или

  • POSIX ( ПОЛОЖЕНИЕ ) clock_gettime() функция с CLOCK_MONOTONIC идентификатор часов.

Обратите внимание, что использование x86 Регистр TSC не рекомендуется использовать в многопроцессорных системах, поэтому вам лучше использовать вышеуказанные API.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top