【问题标题】:How to get UTC time from internet in C#?如何在 C# 中从 Internet 获取 UTC 时间?
【发布时间】:2019-07-29 15:35:02
【问题描述】:

我正在开发家长控制 Windows 桌面应用程序。许多动作/事件取决于正确的系统时间。问题是我不能相信系统时间,因为它可以改变。所以只要有可能,我想以某种方式从互联网上获取时间。时间应该是 UTC,因为我希望它在不同的时区工作。解决方案不必是防弹的。我确信孩子们总会找到解决它的方法;-) 我至少想要一些不能用两次鼠标点击来欺骗的东西。

目前我正在考虑这些选项以获得时间:

  • 来自公共 NTP 服务器。但是我担心将来服务器可能会宕机。
  • 来自 google.com 等网站的 WebClient 响应标头 我认为响应时间不是UTC,我担心如果请求太频繁,Web 服务器可能会阻止请求。
  • 从我自己的 Web 服务器 API 获取服务器 UTC 时间。我认为这可能是我目前最好的选择。

如果我能够缓存时间,这样我就不必过于频繁地同步它,那也很棒。我不想每秒向时间服务器发送请求。

对于缓存部分,我正在考虑存储来自 Internet 的 DateTime 和上次同步的系统 DateTime 之类的东西。并根据这些值计算时间。

您认为从 Internet 获取和缓存正确 UTC 时间的最佳方法是什么?

非常感谢您的建议。

【问题讨论】:

  • 选择一个stratum 2 time server near you 和一个备份(是的,不要经常同步是很体贴的)。如果它们倒下,你会遇到更大的问题——比如觅食。
  • 谢谢,我会检查一下。和好笑话。 :-)
  • 您可以订阅SystemEvents.TimeChanged(当用户修改当前时间时触发)。如果引发事件,请通过 API 检查当前时间并在必要时进行更正。
  • 请注意@Jimi 推荐的SystemEvents.TimeChanged 事件往往会触发两次触发它的任何事件(实际用户启动时间已更改,更改“自动设置时间”)。
  • @TnTinMn 是的,这是真的。您将收到两次通知。但它很容易用秒表规避。如果您将事件处理程序设置为async,则可以在顶部添加[StopWatch].IsRunning 检查,引发自定义通知await Task.Delay(200).ConfigureAwait(false)(或更多),然后停止监视。当前时间也可以从www.google.com的Headers中提取。非常精确。

标签: c# wpf windows winforms


【解决方案1】:

限制Windows user from changing the clock 很容易。那时,攻击者必须做一些事情,比如在 BIOS/UEFI 中更改它。但是,如果攻击者拥有该级别的访问权限,那么您的微不足道的用户代码将无法真正阻止他们。

互联网上问“几点了?”的地方是NTP servers。确实,这些是 Windows 要求的人。也可以说是您的手机提供商。

计算机内部应该存储 UTC。你在右下角看到的那个显示的时钟?或者 DateTime.ToString() 给你什么?这只是基于 Windows 用户的文化和时区设置对 UTC 值的解释。它和其他字符串一样有很大的发言权。

【讨论】:

  • 谢谢。限制用户更改时钟是个好主意。你知道怎么做吗?有任何 Windows API 吗?还是我需要更改注册表中的某些内容?我还将更多地研究 NTP 服务器。
  • @VertexLooper 我不确定是否有一种方便的方法来设置这些值。我想“容易”在这里可能是一个非常错误的术语。如果您有一些管理经验,这充其量是相对容易的。对于您的程序,您必须跟踪寄存器值:stackoverflow.com/questions/1789434/… 此外,您的程序可能必须以管理员身份运行才能进行此类更改。看着它,只是询问NTP时间可能更容易。当然,无论如何您的应用程序可以做多少是值得怀疑的。毕竟它也是“唯一的用户代码”。
【解决方案2】:

您可以使用空闲时间 API 服务来获取真正的 UTC 时间。例如:“https://worldtimeapi.org/api/timezone/Europe”。此 API 端点支持 SSL,但仍然不安全,并且可以通过例如使用提琴手代理和更改本地计算机上的受信任根证书列表来更改响应。为了防止响应篡改,您可以手动检查 https://worldtimeapi.org 证书哈希:

 var req = WebRequest.CreateHttp("https://worldtimeapi.org/api/timezone/Europe");
 req.ServerCertificateValidationCallback += (sender, certificate, chain, errors) => certificate.GetCertHashString() == "<real_Hash_here>";
 var response = req.GetResponse();
 ///parse json response here

要获取证书的哈希值,您应该可以使用浏览器导航到目标 API 网站 (https://worldtimeapi.org/api/timezone/Europe),下载(导出)证书并使用一些 SSL 工具(如 OpenSSl)来获取哈希值。

我相信欺骗这种时间检查的唯一方法是对代码进行逆向工程。一些混淆工具将进一步提高安全性。

附注: 而不是手动证书哈希检查。您还可以将 HttpWebRequest 的 Proxy 属性设置为 null。这将隐藏您来自网络调试代理(如 fiddler 或 charles)的请求。这更容易实现,但不太安全,因为攻击者仍然有办法检查您的请求

【讨论】:

    【解决方案3】:

    只需简单地使用:

    DateTime utcDate = DateTime.UtcNow;
    

    【讨论】:

    • 感谢您的回复。我可以使用它,我正在使用它。问题是当用户更改系统时间时,它也会发生变化并且给出错误的值。这就是为什么我想从互联网上获取当前的 UTC 时间。
    • 试试这个解决方案:stackoverflow.com/questions/6435099/…
    猜你喜欢
    • 2013-04-03
    • 1970-01-01
    • 2011-05-21
    • 2012-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-02
    • 1970-01-01
    相关资源
    最近更新 更多