Ruby で防御的にプログラムするにはどうすればよいですか?
-
09-06-2019 - |
質問
問題の完璧な例を次に示します。 分類子 gem が Rails を壊す.
** 元の質問:**
セキュリティ専門家として私が懸念していることの 1 つは、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
解決
チェックアウト 不変 ギャリー・ドリー著。
個々のメソッドの再定義を防止できます。
他のヒント
これは心配ないと思います。
はい、神話上の「誰か」が MD5 の実装を安全でないものに置き換える可能性があります。しかし、それを行うには、神話上の誰かが実際に自分のコードを Ruby プロセスに取り込むことができなければなりません。そして、それができれば、おそらく自分のコードを Java プロセスに挿入することもできるでしょう。MD5 オペレーションのバイトコードを書き換えます。あるいは、キー押下を傍受するだけで、実際には暗号化コードをまったくいじることを気にしません。
典型的な懸念事項の 1 つは次のとおりです。私はこの素晴らしいライブラリを作成しています。このライブラリは次のように使用されることになっています。
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 で暗号コードを作成できるのは本当です private
そして final
そしてそうでないこと。ただし、誰かができる まだ 暗号化実装を置き換えてください。実際、誰かが実際に次のことを行いました。多くのオープンソース Java 実装では、OpenSSL を使用して暗号化ルーチンを実装しています。そしておそらくご存知のとおり、Debian には何年もの間、壊れた安全でないバージョンの OpenSSL が付属していました。つまり、過去数年間、Debian 上で実行されていたすべての Java プログラムは実際には した 安全でない暗号で実行してください!
Java は防御的なプログラミングのための他の多くのツールを提供します
最初は何について話しているのかと思いました 通常の防御プログラミング, 、アイデアは、プログラム(またはそのサブセットのサブセット、または単一関数)を無効なデータ入力から守ることです。
それは素晴らしいことなので、ぜひ皆さんもその記事を読んでみてください。
しかし、実際には「他のプログラマーからコードを守る」ことについて話しているようです。
私の意見では、これは完全に無意味な目標です。何をするにしても、悪意のあるプログラマはいつでもデバッガでプログラムを実行したり、 DLLインジェクション またはその他のあらゆるテクニック。
無能な同僚からコードを保護したいだけなら、これはばかげています。 同僚を教育するか、より良い同僚を獲得します。
いずれにせよ、そのようなことがあなたにとって大きな関心事であるなら、Ruby はあなたに適したプログラミング言語ではありません。モンキーパッチは設計上組み込まれており、これを禁止することは機能の本質に反します。
Rubyにはその機能があり、セキュリティ上の問題よりも価値があると思います。ダックタイピングも。
例えば。Ruby String クラスを拡張したりラップしたりするのではなく、独自のメソッドを Ruby String クラスに追加できます。
「同僚を教育するか、より良い同僚を獲得する」は、小規模なソフトウェア スタートアップにとっては効果的ですが、Google や Amazon のような大手企業にとっても効果的です。底辺の開発者全員が、小さな都市の診療所で小規模なカルテ アプリケーションを請け負っていると考えるのはばかげています。
最小公倍数を目指して構築すべきだと言っているわけではありませんが、最小公倍数が存在することを現実的に考える必要があります。 たくさん 世の中には、セキュリティには注意を払わず、仕事を遂行するためにあらゆるライブラリを取り込む平凡なプログラマーがいます。どうやって できた 彼らはセキュリティに注意を払っていますか?おそらくアルゴリズムとデータ構造のクラスを受講したでしょう。おそらく彼らはコンパイラのクラスを受講したのでしょう。彼らはほぼ確実に暗号化プロトコルのクラスを受講していませんでした。彼ら全員がシュナイアーやその他の実際に読まなければならない本を読んだことがないのは間違いありません。 懇願して懇願する 非常に優秀なプログラマであっても、ソフトウェアを構築する際にはセキュリティを考慮する必要があります。
これについては心配していません:
require 'evil_cracker_lib_from_russian_pr0n_site'
require 'awesome'
心配です awesome
必要とする foobar
そして fazbot
, 、 そして foobar
必要とする has_gumption
, 、 そして ...最終的に、これら 2 つが何らかの形で衝突し、セキュリティの重要な側面が台無しになります。
重要なセキュリティ原則の 1 つは「多層防御」です。これらの追加のセキュリティ層を追加すると、誤って足を撃たれることを防ぐことができます。それを完全に防ぐことはできません。何もできません。しかし、彼らは助けてくれます。
モンキー パッチが目的の場合は、Immutable モジュール (または同様の機能の 1 つ) を使用できます。
Why the Lucky Stiff の「Sandbox」プロジェクトを参照してください。安全でないコードが実行される可能性が心配な場合に使用できます。http://code.whytheluckystiff.net/sandbox/
例 (オンライン三目並べ):http://www.elctech.com/blog/safely-exposing-your-app-to-a-ruby-sandbox
ラガンヴァルトには、 最近の投稿 これについて。最終的に、彼は次のものを構築します。
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
パブリックメソッドとして Acronym
s、しかし内部の根性は維持します(fu
そして bar
) プライベートであり、外部ビューからヘルパー モジュールを隠します。
誰かがオブジェクトまたはモジュールにモンキーパッチを適用した場合は、次の 2 つのケースを確認する必要があります。彼は新しい方法を追加しました。このメソッドを追加するのが彼だけであれば (その可能性が非常に高いですが)、問題は発生しません。彼が唯一の人ではない場合は、両方の方法が同じことを行うかどうかを確認し、この深刻な問題についてライブラリ開発者に伝える必要があります。
彼らが方法を変更した場合は、なぜその方法が変更されたのかを調査し始める必要があります。エッジケースの動作によって変更されたのでしょうか、それとも実際にバグを修正したのでしょうか?特に後者の場合、モンキーパッチは多くの場所のバグを修正してくれるため、神聖なものです。
それに加えて、プログラマーがこの自由を賢明な方法で使用するという前提の下で、非常に動的な言語を使用しています。この思い込みを取り除く唯一の方法は、動的言語を使用しないことです。