博索纳罗的漏洞——巴西结束夏令时可能会影响您的系统
语境
更简单的系统
虫子
如何解决?
由 Mux 赞助的 DEV 全球展示挑战赛:展示你的项目!
由于博索纳罗总统武断地颁布法令取消夏令时,近期多款软件产品和应用程序出现了与巴西时区相关的漏洞。许多人仍在使用运行夏令时的浏览器。如果您在浏览器中使用 WhatsApp 或 Telegram,可能已经注意到这一点。在Peerdustry,我们也遇到了一个有趣的漏洞,我们戏称之为“博索纳罗漏洞”,值得详细探讨。
语境
在解释我们遇到的具体问题之前,让我先介绍一下我们系统的简化模型。Peerdustry 平台由 Rails API 后端和基于 EmberJS 的前端组成。
其中一项主要流程与报价流程相关。客户请求生产机械零件的报价,我们的合作厂商网络将对报价进行评估并作出答复。系统管理员会为每家厂商创建报价任务,从而选择合适的厂商。厂商必须在客户设定的截止日期前完成这些任务。
最近,一些厂商反映他们的任务会在截止日期前过期。此外,我们的管理员也报告说,他们在系统中发现了一些奇怪的日期和时间。我们立即想到这些错误可能是由于夏令时调整引起的。我们的判断是正确的!然而,这可能会影响系统的多个模块。处理日期和时间、时区以及不同的格式可能非常棘手,这阻碍了我们真正找出问题所在。
更简单的系统
为了简化问题,我们不妨考虑一个更简单的系统,其中只包含解决问题的最关键组件:一个由 Rails 后端和 EmberJS 前端组成的大学 Web 系统。在这个系统中,教授可以创建学生必须在指定截止日期前完成的任务,否则任务将过期。
教授在为学生创建任务时,通过Pikaday JS 组件选择日期来告知截止日期。
在将此数据发送到后端之前,前端会使用MomentJS 的 endOf 函数(该函数会考虑浏览器时区)将其格式化为所选日期末尾的时间戳属性。例如,如果教授选择 2019 年 11 月 15 日作为截止日期,则发送到后端的格式化数据将是15/11/2019 at 11:59:59 pm(或23h59m59s)。值得注意的是,每个时间戳属性都以ISO-8601 UTC格式格式化和存储。GMT格式仅用于 UI 显示。
每个学生都会被分配一项任务,该任务会在截止日期当天过期,之后将无法查看。为此,每当为学生创建任务时,后端都会安排一个Sidekiq异步任务在截止日期当天运行,如果任务尚未完成,则将其标记为已过期。
学生可以通过一个页面跟踪待办任务,该页面会列出所有任务及其截止日期。我们的截止日期以简单的巴西日期格式(例如:2019年11月24日)显示,因为这种格式隐含地表明任务在当天结束前仍然有效,如下图所示。
我们还使用MomentJS 库来显示此类日期,该库还会考虑浏览器的时区。
到目前为止,一切都很好。
虫子
在博索纳罗颁布法令后,我们确保服务器不会错误地使用夏令时,从而保证后端任务在正确的时间运行。鉴于后端使用正确的时区(UTC-3),且前端始终以 UTC 格式提供截止时间,后端将始终按照接收到的时间戳安排任务,使待处理任务过期。
然而,当教授或学生使用过时的浏览器访问平台,而这些浏览器仍然遵循巴西的夏令时时,问题就出现了。部分用户的浏览器可能使用 UTC-3(巴西的默认时区)或 UTC-2(巴西之前的夏令时时区),这导致了一些非常奇怪的情况。
假设一位教授需要创建一个任务,截止日期为 2020 年 1 月 1 日。我们有以下几种情况:
1. 当教授的浏览器正确运行在 UTC-3 时
在这种情况下,教授告知的截止日期是正确的,因为我们不再实行夏令时,而巴西的原始时区是 UTC-3。
如果教授输入的日期是 2020 年 1 月 1 日,前端会将 2020 年 1 月 2 日
02:59:59 UTC 发送到后端(2019 年 1 月 1 日 23:59:59 UTC-3)。由于后端的时区也正确,它会安排任务在教授预期的时间到期。
1.A. 当学生的浏览器正确运行在 UTC-3 时
在这种情况下,阅读此消息的学生不会感到困惑,因为 MomentJS 库使用了正确的时区来显示日期。换句话说,学生将看到01/01/2019正确的截止日期。
1.B. 当学生的浏览器错误地使用 UTC-2(夏令时)时
在这种情况下,MomentJS 库会将从后端收到的 UTC 格式的截止日期应用 UTC-2 时区,得到 02/01/2020 02 Jan 2020 00:59:59 UTC -2。由于我们只显示日期而隐藏时间,用户看到的截止日期将是 02/01/2020(巴西日期格式),而不是 01/01/2020,这会导致用户对正确日期产生误解。虽然学生认为他可以在 02/01/2020(巴西日期格式)之前完成任务,但实际上,该任务将在 02/01/2020 之后失效。
2. 当教授的浏览器错误地使用 UTC-2(夏令时)时
在这种情况下,无论学生使用什么浏览器,都会出现问题,因为提供给后端的截止日期不正确。
如果教授输入的日期是 2020 年 1 月 1 日,前端会将 2020 年 1 月 2 日
01:59:59 UTC 发送到后端(2019 年 1 月 1 日 22:59:59 UTC -3)。这意味着截止日期将比预期提前 1 小时到期。
2.A. 当学生的浏览器正确运行在 UTC-3 时
在这种情况下,即使MomentJS 库使用的时区与原始日期不同,学生也不会对日期感到困惑。将 UTC-3 应用于原始截止日期将产生结果01 Jan 2020 22:59:59 UTC -3。
因此,学生会看到截止日期为2020年1月1日,这是正确的。但是,他可能期望截止日期显示到晚上11:59:59,但这不会发生。
有人可能会认为,在系统中向学生显示日期和时间可以最大限度地减少这个问题:01/01/2020 22:59。但他很可能会忽略时间,因为他习惯于任务可以持续到 23:59。
2.B. 当学生的浏览器错误地使用 UTC-2(夏令时)时
虽然 MomentJS 库会使用与原始截止日期相同的时区
来显示日期,但我们仍然遇到一些问题。
将 UTC-2 应用于原始截止日期将得到 2020 年 1 月 1 日 23:59:59 --02:00。在这种情况下,学生会看到截止日期为 2020 年 1 月 1 日,这是正确的。但是,他将面临与 UTC-3 用户相同的问题,因为他期望截止日期持续到 23:59,但这实际上不会发生。更糟糕的是,我们无法像上一个例子那样向他显示时间,因为显示的时间是错误的(显示 23:59,但实际上截止日期是 22:59)。
如何解决?
有一些方法可以尽量减少博索纳罗漏洞的影响。但
对我来说,大多数方法都相当粗糙。
一般来说,如果您确保系统以 UTC 时间存储和处理日期/时间数据,那么您主要需要关注的是表示层。
在Peerdustry平台的具体情境下,制造商和客户这两个角色几乎从不在晚上7点(公司下班时间)之后使用该平台,这意味着主要问题是向制造商显示错误的截止日期(场景1.B)。因此,如果我们修改前端设置,使其在22:59:59 UTC -3将任务发送到后端之前始终将截止日期设置为正确的时间,制造商就能始终看到正确的日期。即使任务会比预期提前一个小时过期,但几乎不会对任何人造成影响。
这种方法根本不可能应用于大学体系 =D
也可以更改MomentJS使用的时区,以模拟巴西新的时区规则。但是,当用户分布在多个时区时,这种方法会带来很多麻烦,而且会影响系统的国际化。
我认为,针对类似博索纳罗漏洞的漏洞,最合适的解决方案是:
- 显示完成时间和截止日期
- 当用户的浏览器使用过时的时区信息时,会通知用户,警告他们可能存在的错误,并要求他们升级浏览器。
你呢?博索纳罗颁布法令后,你有没有遇到什么奇怪的bug?
封面图片来自 Fábio Rodrigues Pozzebom/Agência Brasil CC BY 2.0 via Wikimedia Commons
#ELENAO - 让我们继续前进吧! ;)
文章来源:https://dev.to/arthurmde/the-bolsonaro-s-bug-the-end-of-daylight- saving-time-in-brazil-may-affect-your-system-2e38

