首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

YAML:可能并不是那么完美

不要误解我的意思,并不是说 YAML 很糟糕 —— 它肯定不像使用 JSON 那么多的问题 —— 但它也不是非常好。

-- Martin Tournoij

致谢

译自 | arp242.net

作者 | Martin Tournoij

译者 | LCTT / MjSeven

我之前写过为什么将 JSON 用于人类可编辑的配置文件是一个坏主意

[1]

,今天我们将讨论 YAML 格式的一些常见问题。

默认情况下不安全

YAML 默认是不安全的。加载用户提供的(不可信的)YAML 字符串需要仔细考虑。

用 运行它,应该给你这样的东西:

许多其他语言(包括 Ruby 和 PHP1)默认情况下也不安全(LCTT 译注:这里应该说的是解析 yaml)。在 GitHub 上搜索 yaml.load会得到惊人的 280 万个结果,而yaml.safe_load只能得到 26000 个结果。

提个醒,很多这样的 都工作的很好,在配置文件中加载 通常没问题,因为它通常(虽然并不总是!)来自“可靠源”,而且很多都来自静态的 YAML 测试文件。但是,人们还是不禁怀疑在这 280 万个结果中隐藏了多少漏洞。

这不是一个理论问题。在 2013 年,正是由于这个问题,所有的 Ruby on Rails 应用程序都被发现易受

[4]

远程代码执行攻击。

有人可能会反驳说这不是 YAML 格式的错误,而是那些库实现错误的的问题,但似乎大多数库默认不是安全的(特别是动态语言),所以事实上这是 YAML 的一个问题。

有些人可能会反驳认为修复它就像用 替换 一样容易,但是很多人都没有意识到这个问题,即使你知道它,它也是很容易忘记的事情之一。这是非常糟糕的 API 设计。

可能很难编辑,特别是对于大文件

YAML 文件可能很难编辑,随着文件变大,这个难度会快速增大。

一个很好的例子是 Ruby on Rails 的本地化翻译文件。例如:

看起来不错,对吧?但是如果这个文件有 100 行怎么办?或者 1,000 行?在文件中很难看到 “where”,因为它可能在屏幕外。你需要向上滚动,但是你需要跟踪缩进,即使遵循缩进指南也很难,特别是因为 2 个空格缩进是常态而且制表符缩进被禁止

[5]

2。

不小心缩进出错通常不算错误,它通常只是反序列化为你不想要的东西。这样只能祝你调试快乐!

我已经愉快地编写 Python 长达十多年,所以我已经习惯了显眼的空白,但有时候我仍在和 YAML 抗争。在 Python 中,虽然没有那种长达几页的函数,但数据或配置文件的长度没有这种自然限制,这就带来了缺点和损失了清晰度。

对于小文件,这不是问题,但它确实无法很好地扩展到较大的文件,特别是如果你以后想编辑它们的话。

这非常复杂

在浏览一个基本的例子时,YAML 看似“简单”和“显而易见”,但事实证明并非如此。YAML 规范

[6]

有 23449 个单词,为了比较,TOML

[7]

有 3339 个单词,Json

[8]

有 1969 个单词,XML

[9]

有 20603 个单词。

我们中有谁读过全部规范吗?有谁读过并理解了全部?谁阅读过,理解进而记住所有这些?

例如,你知道在 YAML 中编写多行字符串有 9 种方法

[10]

吗?并且它们具有细微的不同行为。

是的 :-/

如果你看一下那篇文章的修订历史

[11]

,它就会变得更加有趣,因为文章的作者发现了越来越多的方法可以实现这一点,以及更多的细微之处。

它从预览开始告诉我们 YAML 规范,它表明(强调我的):

本节简要介绍了 YAML 的表达能力。预计初次阅读的人不可能理解所有的例子。相反,这些选择用作该规范其余部分的动机。

令人惊讶的行为

以下会解析成什么(Colm O’Connor

[12]

提供的例子):

结果为:

那么这个呢:

被识别为字符串,但 被识别为数字而不是字符串:

这个呢:

是蒂尔堡Tilburg的一个流行音乐场地,但 YAML 会告诉你错误答案,因为它被解析为八进制数字:

所有这一切,以及更多,就是为什么许多经验丰富的 YAMLer 经常会将所有字符串用引号引起来的原因,即使它不是严格要求。许多人不使用引号,而且很容易忘记,特别是如果文件的其余部分(可能由其他人编写)不使用引号。

它不方便

因为它太复杂了,它所声称的可移植性被夸大了。例如,考虑以下这个从 YAML 规范中获取的示例:

抛开大多数读者可能甚至不知道这是在做什么之外,请尝试使用 PyYAML 在 Python 中解析它:

在 Ruby 中,它可以工作:

这个原因是你不能在 Python 中使用列表作为一个字典的键:

而这种限制并不是 Python 特有的,PHP、JavaScript 和 Go 等常用语言都有此限制。

因此,在 YAML 文件中使用这种语法,你将无法在大多数语言中解析它。

这是另一个从 YAML 规范的示例部分中获取的:

Python 会输出:

然而 Ruby 输出:

原因是单个文件中有多个 YAML 文档( 意味开始一个新文档)。在 Python 中,有一个 函数来解析所有文档,而 Ruby 的 只是加载第一个文档,据我所知,它没有办法加载多个文档。

在实现之间存在很多不兼容

[13]

目标实现了吗?

规范说明:

YAML 的设计目标是降低优先级:

1. YAML 很容易被人类阅读。

2. YAML 数据在编程语言之间是可移植的。

3. YAML 匹配敏捷语言的原生数据结构。

4. YAML 有一个一致的模型来支持通用工具。

5. YAML 支持一次性处理。

6. YAML 具有表现力和可扩展性。

7. YAML 易于实现和使用。

那么它做的如何呢?

YAML 很容易被人类阅读。

只有坚持一小部分子集时才有效。完整的规则集很复杂 —— 远远超过 XML 或 JSON。

YAML 数据在编程语言之间是可移植的。

事实并非如此,因为创建常见语言不支持的结构太容易了。

YAML 匹配敏捷语言的原生数据结构。

参见上面。另外,为什么只支持敏捷(或动态)语言?其他语言呢?

YAML 有一个一致的模型来支持通用工具。

我甚至不确定这意味着什么,我找不到任何详细说明。

YAML 支持一次性处理。

这点我接受。

YAML 具有表现力和可扩展性。

嗯,是的,但它太富有表现力(例如太复杂)。

YAML 易于实现和使用。

结论

不要误解我的意思,并不是说 YAML 很糟糕 —— 它肯定不像使用 JSON 那么多的问题

[1]

—— 但它也不是非常好。有一些一开始并不明显的缺点和惊喜,还有许多更好的替代品,如TOML

[7]

和其他更专业的格式。

就个人而言,当我有选择时,我不太可能再次使用它。

如果你必须使用 YAML,那么我建议你使用StrictYAML

[14]

,它会删除一些(虽然不是全部)比较麻烦的部分。

反馈

脚注

1.

在 PHP 中你需要修改一个 INI 设置来获得安全的行为,不能只是调用像 这样的东西。PHP 想尽办法让愚蠢的东西越发愚蠢。干得漂亮! ↩

2.

不要在这里做空格与制表符之争,如果这里可以用制表符的话,我可以(临时)增加制表符宽度来使它更易读——这是制表符的一种用途。 ↩

via:https://arp242.net/weblog/yaml_probably_not_so_great_after_all.html

作者:Martin Tournoij

[18]

选题:lujun9972译者:MjSeven校对:wxy

本文由LCTT原创编译,Linux中国荣誉推出

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20190108B0F2E500?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券