Ruby 有什么方法可以访问源代码?
有几种方法可以从需要/加载库的Ruby代码中访问库的源代码。在这些方法中,有些方法直接读取库文件并对其进行解析。其他人通过一些内置的方法访问源代码,这些方法提供源代码的信息(例如抽象语法树)。在我无法直接读取文件内容的情况下(如前所述),访问源代码的唯一方法是访问提供信息的内置方法。通过重新定义这些方法来做其他事情,我将完全失去对源代码的访问。最小的方法集是什么?如果我将它们重新定义为其他方法,我将完全失去对外部文件上库的源代码的访问权限Ruby 有什么方法可以访问源代码?,ruby,metaprogramming,Ruby,Metaprogramming,有几种方法可以从需要/加载库的Ruby代码中访问库的源代码。在这些方法中,有些方法直接读取库文件并对其进行解析。其他人通过一些内置的方法访问源代码,这些方法提供源代码的信息(例如抽象语法树)。在我无法直接读取文件内容的情况下(如前所述),访问源代码的唯一方法是访问提供信息的内置方法。通过重新定义这些方法来做其他事情,我将完全失去对源代码的访问。最小的方法集是什么?如果我将它们重新定义为其他方法,我将完全失去对外部文件上库的源代码的访问权限 重新表述问题 假设: 有一个用户可以在文件a中编写任
重新表述问题 假设:
- 有一个用户可以在文件a中编写任何Ruby代码
- 有一个由我编写的静态Ruby文件B,它加载文件a并调用a中定义的主例程,还定义了一些用户可以在a中使用的类/方法
- 用户对B没有+r(读)或+w(写)权限
如果您不知道完整答案,但知道某个特定库如何提取某个方法的源代码,那么这仍然会有帮助。如果您使用John Mair(Pry的制造商)的令人敬畏的“method\u source”gem,实际上非常简单: 该方法必须用Ruby(不是C)实现,并且必须从文件(不是irb)加载 下面是一个示例,显示Rails控制台中的方法源代码和方法源代码:
$ rails console
> require 'method_source'
# the following prints out the method code for #lookup in the Rails I18n Backend:
> I18n::Backend::Simple.instance_method(:lookup).source.display
def lookup(locale, key, scope = [], options = {})
init_translations unless initialized?
keys = I18n.normalize_keys(locale, key, scope, options[:separator])
keys.inject(translations) do |result, _key|
_key = _key.to_sym
return nil unless result.is_a?(Hash) && result.has_key?(_key)
result = result[_key]
result = resolve(locale, _key, result, options.merge(:scope => nil)) if result.is_a?(Symbol)
result
end
end
=> nil
显示的Ruby代码需要来自已加载的文件,
(显然,它必须可读),并且必须是原生Ruby代码(这不适用于编译/链接库)
另见:
- TL;DR:仅限Ruby的解决方案只能使用
源位置
,因此只需重新定义它以返回类似['/some/empty/file',1]
的内容即可。C对解释器的攻击不使用源位置
,但您可以通过阻止/white listrequire
和friends来防止使用C扩展
首先,要能够执行Ruby脚本,您必须能够读取它 但回到问题上来。我知道Sourcify除了在Proc上使用一个小方法和名为
source\u location
的方法外,没有使用任何神秘的方法,它给出了定义了方法/Proc时的文件名和行号。我从经验中知道,这种方法非常脆弱,需要编写某种解析器,而且有时只能在合法的情况下工作。因此,如果您在B中重新定义源位置
,以返回类似/dev/null的内容,第0行
,并让Sourcify抛出一个非Ruby源异常,那么Sourcify已经退出
从Pry的角度来看,Pry似乎使用了相同的源位置
方法,所以一箭双雕
现在,所有这些库都有另一种选择,那就是下拉到C并破解解释器来记录源代码。这几乎是完美的。但我们仍然可以用一种非常简单的方法避免危险。有人可以将Pry方法源代码的所有代码都包含在A中,但如果不需要C库,就不能包含内联C/C扩展。因此,解决方案显而易见:重新定义require
和require\u relative
和load
要么不起作用,要么只允许某些库。这样,你就可以避开C黑客
在MRI上,除了source\u location
之外,没有其他方法(从Ruby代码中)可以做到这一点。好了
编辑:根据@banister,从MRI 2.0+中,有一个内置的调用方绑定方法,可以替换源位置。也用核武器
警告:Ruby不是一种很好的语言。如果你能对它们进行元编程,它们可能会对你进行元编程,除非你处于不同的过程中 我认为您可以在Java中定义一些抽象类或类似于接口的东西,它们不实现任何东西。接口将从外部组件公开访问。然后,您可以继承抽象类以在内部实现它。在重新定义此类方法时,您可以使用
模块#alias_方法
确保您拥有要修改的原始方法的“副本”。必须禁用系统、backtick、fork/exec等。请稍候。你想加载一个“插件”(想不出更好的词),然后通过做一些疯狂的沙箱来阻止它读取应用程序的源代码?在另一个进程中对代码进行沙箱,使用内置的/C级操作系统沙箱功能(我知道Linux有这些功能),并执行一些IPC?s/sourcerer/sorcer?会不会更容易?谢谢。我终于得到了一个中肯的答案。通过取消源位置
,你认为我也可以避免访问抽象语法树(AST)吗?@sawa你想做的事情非常奇怪——但仅仅搞乱源位置是不够的。调用方的绑定和绑定评估(“文件”)等的组合将返回与源位置大致相同的信息。任何有足够智慧的人都可以使用ge