Время выполнения пользовательских задач с точностью до секунды - PullRequest
5 голосов
/ 18 июля 2011

Я создаю веб-сайт, на котором мне нужно время для выполнения задач пользователей, показывать им время по мере его поступления и отслеживать, сколько времени им потребовалось для выполнения задачи. Таймер должен быть точным с точностью до секунды, а вся задача занимает около 3-4 часов.
Я также должен помешать пользователю подделать время завершения (деньги не задействованы, так что это не очень высокий риск, но есть некоторый риск).

В настоящее время я использую метку времени, чтобы отслеживать, когда пользователь начал, и в то же время инициализировать таймер на основе JS, когда пользователь заканчивает, я получаю уведомление, и я вычисляю разницу между текущим временем и начальной отметкой времени. - этот подход бесполезен, есть разница в несколько секунд между таймером пользователя и моей разницей во времени (то есть время, которое я рассчитал, потребовалось пользователю для выполнения задачи, обратите внимание: это было проверено только в моей среде разработки, так как я другого окружения пока нет ..).
Два других подхода, которые я рассмотрел:
1. Полностью полагаться на таймер на стороне клиента (т. Е. JS) и, когда пользователь завершает задачу, отправлять зашифрованное время (, таким образом, пользователь не может подделать время начала ). Это не кажется очень практичным, так как я не могу найти способ генерировать секретный ключ на стороне клиента, который действительно будет "секретным".
2. Полностью полагаться на таймер на стороне сервера и отправлять «галочки» каждую секунду. Это похоже на большую работу на стороне сервера по сравнению с двумя другими методами (машина, а не человек .. например, доступ к БД для каждого «тика», чтобы получить время начала), и я также не уверен это будет совершенно точно.

EDIT:
Вот что сейчас происходит в формулировке алгоритма:

  1. Пользователь запускает задачу - сервер отправляет пользователю идентификатор задачи и записывает время запуска в дБ, таймер на стороне клиента инициализируется.
  2. Пользователь выполняет задание, его таймер работает ...
  3. Пользователь завершает задачу, таймер останавливается, и ответ пользователя и идентификатор задачи отправляются на сервер.
  4. Сервер извлекает время запуска (используя полученный идентификатор задачи) и вычисляет, сколько времени потребовалось пользователю для выполнения задачи.

Проблема - время, рассчитанное сервером, и время, отображаемое на стороне клиента, отличаются.

Любое понимание будет высоко ценится.

Ответы [ 5 ]

2 голосов
/ 21 июля 2011

Если я правильно понял, проблема в том, что время сервера и клиента немного различается, и они всегда будут такими.

Поэтому я бы немного подправил вашу оригинальную последовательность следующим образом:

  1. Пользователь запускает задачу - сервер отправляет пользователю идентификатор задачи и записывает время начала в дБ, клиентский таймер инициализируется.
  2. Пользовательский клиент уведомляет сервер о времени запуска клиента;записывается в БД вместе с временем запуска сервера
  3. Пользователь выполняет задание, его таймер работает ...
  4. Пользователь завершает задание, таймер останавливается, и истекшее время пользователя , ответ иИдентификатор задачи отправляется на сервер.
  5. После получения сервер отмечает время входящего запроса, получает время запуска и рассчитывает, сколько времени потребовалось пользователю для выполнения задачи как для времени сервера (начало / окончание), так и для времени клиента.
  6. Сервер гарантирует, что значение клиента находится в допустимом диапазоне проверенного сервером времени, и использует время клиента.Если время клиента не находится в допустимом диапазоне (например, 30 секунд), используйте время сервера, как показано на рисунке.

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


Чтобы ответить на комментарий:

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

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

2 голосов
/ 18 июля 2011

Я думаю, это будет работать.Похоже, у вас проблема с синхронизацией, а также проблема с криптографией.Мое предложение состоит в том, чтобы обойти проблему синхронизации способом, невидимым для пользователя, при этом сохраняя безопасность.

Идея: вычислять и отображать тики на стороне клиента, но использовать криптографические методы, чтобы предотвратить отправку поддельным пользователемвремя.Пока сообщаемое пользователем время близко к измеренному времени сервера, просто используйте время пользователя.В противном случае запрос подделки.

  1. Клиент запрашивает у сервера задание.

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

  3. Клиент работает, пока не будет завершен.Тики записываются локально в JS.

  4. Клиент завершает работу и отправляет на сервер свой ответ, количество записанных тиков и зашифрованную метку времени, когда сервер впервые отправил его.

  5. Сервер расшифровывает метку времени и сравнивает ее с текущим местным временем, чтобы получить число тактов.

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

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

1 голос
/ 27 июля 2011

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

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

Однако вы можете убедиться, что задержки в сети не станут неожиданностью для пользователя. Ниже приведен простой подход, который полностью предотвращает мошенничество, при этом, учитывая некоторые умеренные предположения о тактовых частотах и ​​задержках в сети, время показа на стороне клиента при представлении результатов должно приблизительно соответствовать окончательному времени, рассчитанному на сервере:

  1. Клиент запускает таймер и запрашивает задание с сервера.
  2. Сервер записывает текущее время и отправляет задачу клиенту.
  3. Пользователь завершает задание.
  4. Клиент отправляет результат на сервер и (опционально) останавливает таймер.
  5. Сервер принимает результат и вычитает метку времени, сохраненную на шаге 2, из текущего времени, чтобы получить окончательное время.
  6. Сервер отправляет последнее время клиенту.

Хитрость в том, что клиентские часы запускаются до , когда задача запрашивается с сервера. Если предположить, что задержка односторонней передачи по сети между шагами 1 и 2 и шагами 4 и 5 примерно одинакова (и что часы клиента и сервера работают примерно с одинаковой частотой, даже если они не синхронизированы), время с шага 1 до 4, рассчитанного на клиенте, должно соответствовать времени, рассчитанному на сервере с шага 2 до 5.

С психологической точки зрения, возможно, было бы даже неплохо оставить клиентские часы включенными после шага 4, пока не будет получено последнее время от сервера. Таким образом, когда текущие часы заменяются последним временем, прыжок, скорее всего, будет обратным, что сделает пользователя счастливее, чем если бы время прыгнуло даже немного вперед.

0 голосов
/ 27 июля 2011

Синхронизация часов

Это то, что вы ищете, WikiPedia объяснение .

А вот и решение для JavaScript.

0 голосов
/ 27 июля 2011

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

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

Итог: Здесь будет некоторая неточность.Вы должны идти на компромисс, когда вам нужно удовлетворить так много требований.Надеемся, что это решение даст вам лучшие результаты.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...