5

这是该问题的一个完美示例:分类器 gem 破坏 Rails

**原始问题:**

作为一名安全专家,我关心的一件事是 Ruby 没有与 Java 的包隐私类似的东西。也就是说,这不是有效的 Ruby:

public module Foo
  public module Bar
    # factory method for new Bar implementations
    def self.new(...)
      SimpleBarImplementation.new(...)
    end
    def baz
      raise NotImplementedError.new('Implementing Classes MUST redefine #baz')
    end
  end

  private class SimpleBarImplementation
    include Bar
    def baz
      ...
    end
  end
end

能够防止 Foo::BarImpl 的猴子补丁真是太好了。这样一来,依赖图书馆的人就知道没有人弄乱它。想象一下,如果有人在你身上更改了 MD5 或 SHA1 的实现!我可以调用freeze这些类,但我必须逐个类地进行,如果我对加载顺序不太小心,其他脚本可能会在我完成保护我的应用程序之前修改它们。

Java 为防御性编程提供了许多其他工具,其中许多在 Ruby 中是不可能的。(请参阅 Josh Bloch 的书以获得一个很好的列表。)这真的是一个问题吗?我是否应该停止抱怨并将 Ruby 用于轻量级的事情,而不是希望“企业就绪”的解决方案?

(不,核心类在 Ruby 中默认不被冻结。见下文:)

require 'md5'
# => true
MD5.frozen?
# => false
4

9 回答 9

9

我不认为这是一个问题。

是的,神话中的“某人”可以用不安全的东西代替 MD5 的实现。但为了做到这一点,神话中的某个人实际上必须能够将他的代码放入 Ruby 进程中。如果他能做到这一点,那么他大概也可以将他的代码注入 Java 进程,例如重写 MD5 操作的字节码。或者只是截取按键,而不是真正费心摆弄密码学代码。

一个典型的问题是:我正在编写这个很棒的库,它应该像这样使用:

require 'awesome'
# Do something awesome.

但是如果有人这样使用它怎么办:

require 'evil_cracker_lib_from_russian_pr0n_site'
# Overrides crypto functions and sends all data to mafia
require 'awesome'
# Now everything is insecure because awesome lib uses 
# cracker lib instead of builtin

简单的解决方案是:不要那样做!教育您的用户,他们不应在其安全关键应用程序中运行从晦涩来源下载的不受信任的代码。如果他们这样做,他们可能应得的。

回到您的 Java 示例:确实,在 Java 中您可以制作您的加密代码privatefinal而不能。但是,仍然有人可以替换您的加密实现!事实上,确实有人这样做了:许多开源 Java 实现使用 OpenSSL 来实现它们的加密例程。而且,您可能知道,多年来,Debian 都附带了一个损坏的、不安全的 OpenSSL 版本。因此,过去几年在 Debian 上运行的所有 Java 程序实际上使用不安全的加密方式运行!

于 2008-08-28T23:09:11.183 回答
4

Java 为防御性编程提供了许多其他工具

最初我以为您在谈论正常的防御性编程,其中的想法是保护程序(或您的子集,或您的单个函数)免受无效数据输入的影响。
这是一件很棒的事情,我鼓励大家去阅读那篇文章。

但是,您似乎实际上是在谈论“保护您的代码免受其他程序员的侵害”。

在我看来,这是一个完全没有意义的目标,因为无论你做什么,恶意程序员总是可以在调试器下运行你的程序,或者使用dll 注入或任何数量的其他技术。

如果你只是想保护你的代码免受不称职的同事的伤害,这是荒谬的。教育你的同事,或获得更好的同事。

无论如何,如果您非常关心这些事情,那么 ruby​​ 不是适合您的编程语言。Monkeypatching 是有意设计的,禁止它违背了该功能的全部要点。

于 2008-08-28T23:34:07.393 回答
1

我猜 Ruby 有一个特性——它比安全问题更有价值。鸭打字也是。
例如,我可以将自己的方法添加到 Ruby String 类中,而不是扩展或包装它。

于 2008-08-28T14:48:38.780 回答
1

“教育你的同事,或获得更好的同事”对于小型软件初创公司非常有用,对于谷歌和亚马逊这样的大公司来说也非常有用。认为每个卑微的开发人员都在一个小城市的医生办公室签约了一些小型医疗图表应用程序,这是荒谬的。

我并不是说我们应该为最小的公分母而构建,但我们必须现实的是,有很多平庸的程序员会拉入任何完成工作的库,而不注意安全性。他们怎么注意安全?也许他们上了一个算法和数据结构类。也许他们参加了编译器课程。他们几乎可以肯定没有参加加密协议课程。他们肯定没有读过 Schneier 或其他任何人,他们实际上不得不恳求甚至非常优秀的程序员在构建软件时考虑安全性。

我不担心这个:

require 'evil_cracker_lib_from_russian_pr0n_site'
require 'awesome'

我担心awesome要求foobarfazbotfoobar要求has_gumption,和......最终其中两个以某种模糊的方式发生冲突,从而消除了一个重要的安全方面。

一个重要的安全原则是“纵深防御”——添加这些额外的安全层可以帮助您避免意外地击中自己的脚。他们无法完全阻止它;没有什么可以。但他们有帮助。

于 2008-08-29T03:05:27.557 回答
1

看看Garry Dolley 的Immutable

您可以防止重新定义单个方法。

于 2008-10-02T07:57:17.693 回答
1

如果猴子补丁是您的想法,您可以使用不可变模块(或类似功能之一)。

不可变

于 2008-10-02T08:01:32.597 回答
1

您可以查看Why the Lucky Stiff 的“Sandbox”项目,如果您担心可能会运行不安全的代码,可以使用该项目。 http://code.whytheluckystiff.net/sandbox/

一个例子(在线井字游戏): http ://www.elctech.com/blog/safely-exposing-your-app-to-a-ruby-sandbox

于 2008-10-02T08:08:14.797 回答
1

Raganwald最近有一篇关于此的帖子。最后,他构建了以下内容:

class Module
  def anonymous_module(&block)
   self.send :include, Module.new(&block)
  end
end

class Acronym
  anonymous_module do
    fu = lambda { 'fu' }
    bar = lambda { 'bar' }
    define_method :fubar do
      fu.call + bar.call
    end
  end
end

fubar作为 s 上的公共方法公开Acronym,但保持内部胆量(fubar)私有,并从外部视图隐藏辅助模块。

于 2008-12-01T17:00:46.297 回答
0

如果有人猴子修补了一个对象或一个模块,那么你需要看两种情况:他添加了一个新方法。如果他是唯一添加此方法的人(很可能),则不会出现问题。如果他不是唯一的,您需要查看两种方法是否相同,并告诉库开发人员这个严重的问题。

如果他们改变了方法,你应该开始研究改变方法的原因。他们是因为某些极端情况的行为而改变了它,还是他们实际上修复了一个错误?特别是在后一种情况下,monkeypatch 是神器,因为它修复了许多地方的错误。

除此之外,您正在使用一种非常动态的语言,并假设程序员以理智的方式使用这种自由。消除这种假设的唯一方法是不使用动态语言。

于 2008-11-18T06:21:08.977 回答