IIUC Heartbleed 脆弱性は、OpenSSLのCソースコードのバグが原因で、短すぎるバッファからmemcpy()
を実行することにより発生します。 CまたはC++よりも高レベルのメモリ管理システムを備えた他の言語では、バグが自動的に防止されたのかと思います。
特に、私の理解は Go 、 [〜#〜] d [〜#〜] および Vala がそれぞれネイティブコードにコンパイルされることです。 VMを実行する必要はありません。C互換のバイナリインターフェイスを提供するネイティブライブラリの作成を許可する必要があります。
では、これらの言語を使用して、同じインターフェイスでOpenSSLライブラリを実装できますか。また、Heartbleedの脆弱性などのバグに対する保護を提供できますか?
実際、これらの言語はどれもバグを防ぐことはできませんでしたが、結果は少なくなりました。
OpenSSLのコードは、抽象的なマシンの観点からは無意味なことをしています。実際にバッファーにあるよりも多くのバイトをバッファーから読み取ります。 Cでは、読み取りは引き続き「機能」し、バッファーの後に残っているバイトを返します。より厳密な言語では、範囲外のメモリアクセスがトラップされ、例外がトリガーされます。バイトを読み取って送信する代わりに、問題のあるコードがクラッシュし、(Webサーバーのコンテキストでは)終了につながりますサーバーの他の部分を変更せずに、現在のスレッドとおそらく接続のクローズ。
したがって、まだバグですが、本当の脆弱性ではありません。
これには、自動メモリ管理との間接的な関係のみがあります。ここでの真の安全策は、アクセスに対する体系的な配列境界チェックです。その体系的なチェックは、厳密な型指定によって間接的にサポートされます(これにより、「バイトの配列」以外のものを「バイトの配列」として使用できなくなります)。厳密な型自体は、自動メモリ管理(GC)によって間接的にサポートされます。これにより、ぶら下がりポインタがなくなり、厳密な型指定に違反する解放後使用状態が防止されます。
最近の「ハートブリード」は、質的に新しいものではありません。 OpenSSLにはすでに、長年にわたってかなりの数のバッファオーバーフロー関連のバグがありました(その多くは、証明書の解析のためのASN.1処理コードに起因しています)。これはリストの別のものです。
バグを現在の構造の境界外から読み取ると考える場合、他の言語ではこれはおそらく防止されていました。なぜなら、メモリへのバインドされていないアクセスがなく、これらを異なる方法で実装する必要があるからです。
しかし、私はむしろこのバグをユーザー入力の検証が欠落しているものとして分類したいと思います。パケットで送信されるサイズは実際にはペイロードのサイズであると考えています。これらの種類のバグは、別の言語を使用して単純に修正されるわけではありません。
OpenSSLはシステムが提供するメモリアロケータではなく、独自のメモリアロケータを使用するであるため、残念ながらバグは防止されません。
悪名高いハートビートデータが読み込まれるバッファは、_ ssl/s3_both.c のfreelist_extract
という関数によって割り当てられます。この関数は、デフォルトで、OpenSSL独自の使用済み/未使用メモリのリストを管理し、最新の安全性チェックは行いません。
別の言語で記述されていたとしても、OpenSSLが独自のバッファアロケータを維持し続けていると想定すると、このバグはまったく同じように発生します。以前のバッファー構造を再利用することにより、プログラミング言語に関係なく、memcpy
または「バッファーコピー」関数の同等物は、エラーを発生させることなく同じことを行います。
最近のプログラミング言語では、これは次のようになります。
request = last_used_buffer;
/* I'm sure it doesn't actually read bytes like this, but you get the idea */
while (byte = read(connection)) {
request[i++] = byte;
}
/* ... some time later, in the heartbeat processing function */
output = new Buffer();
output.write(header);
output.write(request, start, len); /* dutifully copies from the request buffer,
but since end was not checked, it can copy
bytes from last_used_buffer */
代わりに、OpenSSLが独自のアロケーターではなくシステム(libc)malloc
およびfree
を直接使用していた場合、このバグは数年前に検出された可能性があります。多くのlibc実装では、割り当てられた/解放されたメモリの境界チェックがはるかに優れており、valgrindなどのツールでこのバグを簡単に見つけられる可能性があります。
ハートブリードバグの処理におけるOpenSSLのメモリアロケータのこの結果は、Ted Unangstが http://www.tedunangst.com/flak/post/heartbleed-vs-mallocconf で述べています。
Goで記述された暗号ライブラリの特定のケースについてこの質問に答えられると思います---スタンドアロンはすでに存在しているため、簡単であり、まったく仮説ではありません TLSパッケージ、crypto/tls
Goでは、外部のライブラリに依存していません。
典型的なバッファオーバーフローに関しては、慣用的なGoは従来のCよりもはるかに安全ですが、Goは鋭敏な開発者にそれを回避するための多くのオプションを提供します-Goを介してCのポインター計算を模倣するなど unsafe.pointer
=。重要なソフトウェアで脆弱なコードを使用しないことに同意できるかどうか疑問に思います。
もちろん、暗号はまさにそのような脆弱なコードを使用する種類のソフトウェアですが、それには正当な理由があります。結局のところ、Goパッケージに実装されている一定時間の比較 crypto.subtle
は実際に必要であり、同様に unsafe
からのものと同じように慎重に使用することについての警告があります。残っている唯一の問題は、実際には、そのような環境でバグがまだ存続できるかどうかです。
私の知る限り、Goは確かにハッシュ値の一定時間比較を正しく実装しています。私はS-boxを含む複雑なハッシュが一定時間で計算されるかどうかさえ気にしていません---subtle
のような名前のパッケージにそれらを入れたり、物事を分解するのがいかに簡単かについての警告をしたりする人はいません。疑わしいです。
私がチェックしたことは、Goで楕円曲線暗号がされていない一定時間で実装されていることです。だれも最小限にしようとは考えていなかったようです-実装は暗号化用に設計されていない多くの任意の長さの整数関数を呼び出し、実際には非一定時間アルゴリズムを使用しています。この種のタイミングサイドチャネルが最近1つのアーキテクチャのOpenSSL
でも発生することが示されたとき、それは 秘密キーの侵害を実証する論文 には十分でした。
すべてのアーキテクチャーにおいて、Goには同じ継続的な状況が存在します。そして、まあ、実際に暗号を動作させるような詳細について誰も気にしていないようです。焦点は可読性と速度にあります(まあ、カジュアルユーザーと一部のユニットテストがだまされているように機能していると思います)。結局のところ、言語がバッファオーバーフローを導入するほとんどの方法からすでに安全を確保している場合、および適切なアルゴリズムを選択するときに、TLSが計算的に安価になったというGoogleの主張を台無しにしてしまうリスクがあるのに、なぜ適切なアルゴリズムを選択する必要があるのでしょうか。皮肉はさておき、私たちのバグをキャッチするための言語を担当させることは、その言語が私たちのためにキャッチできないすべてのバグがまだ存在することを意味します。
最後に、OpenSSL
のようなライブラリには、タイムリーなバグ修正が合理的な可能性があるという利点があります。原則として同じことがGoパッケージにも当てはまりますが、TLSパッケージのようにGoのコアの一部になると、リリーススケジュールの影響を受けます。明らかに、バグ修正のタイムリーな展開を妨げる可能性があります。この夏の予定であるGo-1.3は、ECCタイミングの問題が重大な問題であると認識されていても、機能が凍結されていれば、間違いなく修正されないと思います。
データ汚染 は、インターネットのセキュリティの性質に関するかなり早期の認識に応じて Netscape JavaScript (ナビゲーター3およびEnterprise Serverのサーバー)に実装されました。フラグがクリアされていない限り、ユーザーからのすべての入力は汚染されていると見なされ、汚染フラグはデータの操作によって広がっています(したがって、データと汚染されたデータを組み合わせた結果は汚染されていると見なされます)。その結果、汚染されたデータを常にチェックすることができました。
これは10年以上前です。これが、JavaまたはC#(または、他の人のJavaScript実装)のような主流のマネージ言語に取り入れられていないこと)に驚いています。
コンパイル時のデータ汚染分析と安全なメモリモデル(マネージコード、または少なくとも検証可能)を組み合わせた場合でも、確かに論理バグは残りますが、攻撃のすべてのカテゴリを一気に排除できます。 、これに寄与する両方の要因を含みます。