有多种方法可以从需要/加载该库的 Ruby 代码中访问该库的源代码。其中,有的直接读取库文件并解析。其他人通过一些内置方法访问源代码,这些方法提供有关源代码的信息(例如抽象语法树)。在我无法直接读取文件内容的情况下(如前面的方式),访问源的唯一方法是通过访问提供信息的内置方法。通过重新定义这些方法来执行其他操作,我将完全放弃对源代码的访问。最少的方法集是什么,如果我将它们重新定义为其他内容,我将完全失去对外部文件上库源代码的访问?
To rephrase the question
Suppose:
- 有一个用户可以在文件 A 中编写任何 Ruby 代码。
- 有一个我写的静态Ruby文件B,它加载文件A并调用A中定义的主例程,并且还定义了用户可以在A中使用的一些类/方法。
- 用户对 B 没有 +r(读)或 +w(写)权限。
我必须重新定义(无效)或通过在文件 B 中写入来删除哪些(标准 Ruby)方法,以便用户无法访问文件 B 中写入的源代码(通过用户可以在文件 A 中写入的任何代码) )当我运行文件B时?
有一些库,如 sorcerer、pry,可以提取它有权访问的方法的源代码。这些库依赖于纯 Ruby 中的一些原始命令来访问源代码。有哪些方法可以使这种事情成为可能?
如果您不知道完整的答案,但知道特定的库如何提取某种方法的源代码,那么这仍然会有帮助。
TL;DR: Ruby-only 解决方案只能使用source_location
,所以只需重新定义它即可返回类似的内容['/some/empty/file', 1]
。对解释器的 C hack 不使用source_location
,但您可以通过阻止/白名单来阻止任何 C 扩展的使用require
和朋友。
其一,为了能够执行 Ruby 脚本,您必须能够读取它......
但回到问题。我知道Sourcify除了Proc和Method上的一个小方法之外没有使用任何神秘的方法source_location
,它给出了定义方法/过程的文件名和行号。我从经验中知道,这种方法非常脆弱,需要编写某种解析器,并且仅有时在合法情况下有效。所以,如果你重新定义,Sourcify 已经出局了source_location
在 B 中返回类似的东西/dev/null, line 0
并让 Source 抛出一个非 Ruby 源异常。
来自普里的source https://github.com/pry/pry/blob/master/lib/pry/method.rb#L551-L566,看来 Pry 使用的是相同的source_location
办法,于是二鸟同石。
现在,所有这些库都有另一个选择,即下降到 C 并破解解释器以记录源代码。这几乎是完美无缺的。但我们仍然可以通过一种非常简单的方法来避免危险。有人可以在 A 中包含 Pry 方法源的所有代码。但是如果不需要 C 库,则无法包含内联 C/C 扩展。所以,解决方案很明显:重新定义require
and require_relative
and load
要么不起作用,要么只允许某些库。这样,您就可以抵御 C 黑客攻击。
在 MRI 上,除此之外没有其他办法(来自 Ruby 代码)source_location
去做这个。那么就这样吧!
Edit:根据 @banister 的说法,从 MRI 2.0+ 来看,有一个binding_of_caller
可以替换源位置的内置方法。也核爆这个。 ;)
Warning: Ruby 不是一个很好的语言。如果您可以对它们进行元编程,那么它们也可能可以对您进行元编程,除非您处于不同的进程中。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)