【发布时间】:2012-01-28 13:45:42
【问题描述】:
当有人提到通过编写inspect 输出并通过eval 加载它来将信息保存到外部文件的想法时,我看到很多人会批评这个想法,而是建议使用 YAML。写inspect的输出有什么问题,为什么首选YAML?对于人类可读性,我认为 ruby inspect 或 pp 格式优于 YAML。
【问题讨论】:
标签: ruby file eval yaml inspect
当有人提到通过编写inspect 输出并通过eval 加载它来将信息保存到外部文件的想法时,我看到很多人会批评这个想法,而是建议使用 YAML。写inspect的输出有什么问题,为什么首选YAML?对于人类可读性,我认为 ruby inspect 或 pp 格式优于 YAML。
【问题讨论】:
标签: ruby file eval yaml inspect
假设没有任何东西覆盖inspect,这有什么用?:
#<Foo:0xa34feb8 @bar="wat">
与此相比:
--- !ruby/object:Foo
bar: wat
YAML 更有可能在非平凡的情况下产生有用的输出。它还具有可移植性,可用作在不同系统之间发送序列化数据的更可靠方式。
【讨论】:
安全是主要问题。因为eval 将运行传递给它的任何代码,恶意黑客可以将代码注入您的数据文件,并控制您的程序。这对于您自己的小型脚本可能并不重要,但在 ruby on rails 服务器中,安全性将很重要。假设我们有以下代码:
f=File.new("foobar.txt")
f.puts Foo.new.tap {|foo| foo.bar="bork"}.inspect
假设Foo 没有覆盖inspect,这将给出如下结果:
#<Foo:0xff456a5 @bar="bork">
显然,这不是有效的 Ruby 语法。奇怪的是,eval 没有抛出错误,而只是返回 nil。这只会使这个想法变得更糟,因为您希望成为Foo 的变量现在只是nil(臭名昭著的NoMethodError: undefined method 'bork' for nil:NilClass 错误)。
另一个大问题是安全性。假设您的代码将数据保存到一个文件中,比如说foo.txt,并将inspected 哈希映射bars 存储到它们各自的bazes。需要知道这些映射以计划 FOO 约定的不同程序读取并evals 这个文件。想象一下,这个文件位于黑客可以访问它的地方(仔细想想,它几乎在任何地方)。如果这些程序在同时存储所有 foo 财务数据的 RoR 服务器上运行,黑客可能会造成大规模混乱。如果这个黑客将代码注入foo.txt,也就是说,将恶意病毒下载到系统并安装它,但最后仍然留下原始程序的哈希,它就会被忽视执行。即便你eval数据带有$SAFE=4,黑客仍然可以通过抛出错误等方式破坏foo刨程序的稳定性。
总而言之,虽然inspect-eval 方法适用于Hash、String、Array 等基本类,但它取决于类来给出精确的自身的句法表示。对于大多数应用程序(如果不是所有应用程序)来说,使用inspect-eval 是个坏主意。 YAML 是首选,因为它为 data 定义了语法,这意味着混入的可执行代码会导致错误,而不是被盲目地执行。此外,许多开发人员使用inspect 进行调试,并且不希望对象提供自身的文件转储。
YAML 的其他好处是它可以轻松地序列化复杂的对象。使用 YAML 很容易实现 foos 和 bar 的复杂对象树,但使用 inspect 会产生巨大的复杂性。归根结底,这可以认为是JSON问题--因为使用了eval而执行的数据中的可执行代码。 inspect 可能适合您自己的小型实用程序,但绝不会用于生产代码,或向广大世界开放的代码。
【讨论】:
我推荐 YAML,因为:
【讨论】: