脆弱性の歴史からみるWindows XPのウイルス感染過程

もうみなさんご存じでしょうが、2014年4月8日をもってWindows XPのサポートは終了しました。
先週、先々週あたりはXPから早くアップデートしろだの、XPは窓から投げ捨てろだの騒がしくなってましたね。

ニコニコ動画には、Windows XPサポート切れをあつかった自主制作アニメまで上がっていました。

ざっくりまとめてしまうと、社内のXPで怪しいソフトをインストールしてしまって大変なことに…。みたいなお話。XPユーザーはドキッとしてしまうような内容ですね。

でも、なんか違うんだよなー。

だって、怪しいソフトをインストールしちゃいけないのは、Windows8だろうと、Linuxだろうと変わらないじゃないですか。(いわゆるトロイの木馬ですね)

Windows XPが危ないって伝わったひとでも、実際のところどう危ないのかってことまではわかってないひとは多いんじゃないでしょうか。Windows XPを脅かす“脆弱性”とはどういうものなのか?これまでの脆弱性を振り返ることで見ていきたいと思います。

ここ半年のWindowsのセキュリティ情報をながめる

Windowsには毎月のように脆弱性が発見されています。これは、XPだけでなくVista, 7, 8でも同じことです。XPサポート終了が問題になるのは、この毎月のように発見されている脆弱性が修正されなくなるからです。

では、脆弱性というのはいったいどういうものなのでしょう?

脆弱性がどういうことものなのかを理解するのに手っ取り早いのは、これまでにあった脆弱性を知ることです。Windowsの修正ずみの脆弱性についてはマイクロソフトのサイトで公開されています。

マイクロソフト セキュリティ情報

以下に、2013年9月から2014年3月までに公表された脆弱性のうち深刻度「緊急」のものの一部を挙げていきます。

ぱっと眺めてみただけで、やばさはわかると思います。特に注目すべきことは以下のことです

  • 脆弱性のあるソフトウェアでは、ウェブページを閲覧したり、画像を閲覧したり、フォントを閲覧したり、メールを閲覧したりするだけで、ウイルスに感染させることが可能だということ
  • これらに、怪しいソフトウェアをインストールしたり、怪しいメールの添付ファイルを開くなどの危険とされる操作は必要ないということ
  • 脆弱性のうちいくつかは修正より前に公開されてしまって、だれでも攻撃ができる状態になってしまうこと
  • Windows8, 7, Vista, XPに共通する脆弱性は多いということ
  • Windows8, 7, Vistaの脆弱性にこれからも修正や情報公開をしていくが、XPの脆弱性は修正されないということ。つまり、Windows8, 7, Vistaの更新内容から、XPの持っている脆弱性がある程度推測できるということ

脆弱性があるということは「ちょっとした過失でウイルスに感染しうる」ことだと思っているひとは多いかもしれません。脆弱性があるということは「何の過失がなくてもウイルスに感染しうる」ということです。むしろ、「脆弱性の放置されたPCを使い続けること自体が、過失である」とも言えます。

攻撃者はどうやって悪意あるWebページを閲覧させるか

Windows XPの脆弱性をねらう攻撃としてありそうなものは、閲覧するだけでウイルスに感染するようなメールを送りつけることや、閲覧するだけでウイルスに感染するようなWebページに誘導するなどがあります。

ここでは、攻撃者が悪意あるWebページを閲覧させる方法を掘り下げてみます。怪しいWebページになんて見なければいいんだろうと思う人もいるかもしれませんが、そう簡単ではありません。

泥棒はスーツを着ている

空き巣にもっともポピュラーな服装はスーツであるという話があります。悪意ある人間と同じように、悪意あるサイトもいたって健全そうな見た目をしていることはよくあります。

ある攻撃サイトは、GoogleやYahoo検索の上位に上がるようなサイトをつくることで、ページの閲覧者を増やします。ある攻撃サイトは中古のドメインを利用して、例えばもともと映画の公式サイトがあったURLにサイトをつくります。FC2や、はてなブログ、Tumblrのようなフリーのブログサービスなどを攻撃に使うことも可能です。こういった手法をつかわれると、リンクをみて怪しいサイトかどうかを判断するのはほとんど不可能です。

それだけではありません。もっとメジャーなSNSから攻撃されることもありえます。

クロスサイトスクリプティングでTwitterやYoutubeから攻撃をする

不特定多数のユーザーに対してWebページを閲覧させる方法の1つは、XSS(クロスサイトスクリプティング)を使う方法です。このXSSに対する脆弱性というのは、いままでTwitter、YouTube、Facebook、Yahoo知恵袋にも見つかった脆弱性です。

XSS脆弱性があるユーザー投稿型のサービスでは、特定のテキストを投稿するとそのテキストを閲覧した人に対してJavaScriptを実行させることが可能になります。

例えば、SNSなどのユーザー名やタイトルに

<script>document.location = "http://google.com"</script>

というテキストを含めた投稿を行うと、タイトルやユーザーが表示されるはずの場所で、

document.location = "http://google.com"

というテキストがJavaScriptとして解釈されて、閲覧者は、Googleのトップページに飛ばせる場合があります。わかりやすいのが、Yahoo知恵袋の例です。

<script>alert("xss");</script> これであなたもおしまいです。 – Yahoo知恵袋

ただ、タイトルに <script>alert("xss");</script> という文字が含まれているだけの質問ですが、当時はこのページの閲覧後に他の質問を閲覧すると、画面上に”xss”というポップアップが表示されるようになっていました(現在は修正ずみ)。

上の質問では、ただ文字を表示するだけでしたが、alert(“xss”)の代わりに別のJavaScriptが使えば、悪意あるWebページを表示したり、アカウントのログインに必要な情報を盗んだりすることも可能な状態になっていました。

とても単純な脆弱性ですが、このような脆弱性はめずらしいものではなく多くの有名なWebサービスでも見つかっています。

XSS脆弱性があったサービス

その他の悪意あるWebページを閲覧させる方法

  • 審査の甘い広告サービスを利用した広告枠からの攻撃(マルバタイジング)
  • 中間者攻撃
    • 例えば、無料Wifiスポットに偽装したWifiスポットで、偽のWebページを閲覧させる。
  • DNSキャッシュポイズニング
    • google.comやyahoo.co.jpなどのドメイン名がどこのサーバーを指しているのかを解決するサーバー(DNSサーバー)の脆弱性を狙った攻撃。成功すれば、例えばhttp://www.yahoo.co.jpを閲覧しようとしている人に対して、偽のページを表示させることができる。

悪意あるWebページを表示させる手法はいろいろあります。

結論

Google検索しか使わなくても、Twitterしか使わなくても、Youtubeしか使わなくても、Facebookしか使わなくても、悪質なWebページを閲覧する危険性がある。

Windowsだから危険なのか?

Windowsの脆弱性についてばかり取り上げていますが、これは決してWindowsが他のOSに比べて脆弱性が多いという意味ではありません。例えば、Linuxなどにも同じように脆弱性は存在しています。

Linuxの安全性を語るときによくいわれるのは「オープンソースなので脆弱性が少ない」ということです。しかし、オープンソースであっても、ごく単純な脆弱性が発見されることなく放置されていた例というのはいくつもあります。

オープンソースのバグで記憶に新しいのはOpenSSLの、HeartBleedです。重大な脆弱性ですが、2年間も存在していました。長いものでは、X Windowの22年間放置されていたユーザーが昇格できる脆弱性というのもあります。

これらのバグを生んだソースコードは誰でも閲覧可能だったわけです。ソースを公開していないWindowsの脆弱性よりも、はるかに見つけやすかったはずです。オープンソースであることは、かえって攻撃しやすい原因にすらなります。

Linuxに対するウイルスは確かに、Windowsに対するものより少ないです。ただし、これはデスクトップPCのLinuxユーザーが少ないからという理由につきると思っています。スマートフォンのシェアの半数以上を握るAndroidは攻撃の的になっていますしね。

まとめ

サポート期限切れのソフトだと、メールをただ閲覧しただけ、いつものSNSやWebサイトを閲覧してるだけで、ウイルスに感染するよ!

ユーザーとしてできること

ソフトウェアを使う側としてできることって、当たり前なことを当たり前にやるってことぐらいしか思い浮かばないです。Linux、Windowsだの、Internet Explorer、Chromeだの関係なく以下のようなことはやっときましょう

  • OSはちゃんとアップデートしましょう
  • ブラウザやメールクライアントなどのソフトもアップデートしましょう
  • セキュリティソフトを使いましょう

脆弱性の話ばかりしたので、インターネットを利用することが怖く感じる人もいるかもしれません。ですが必要以上にインターネット自体を恐ろしく感じる必要は無いです。

悪意ある攻撃の話ばかりしてきましたが、実際のインターネットには善意があります。マイクロソフトのセキュリティ情報の謝辞の欄をみてください。ここには非公開の脆弱性をマイクロソフトに連絡してくれた方の名前がずらりと並んでいます。OSやブラウザの脆弱性を見つけるのは悪質なクラッカーだと思っている人は多いかもしれません。しかし実際には、善意をもった人たちが開発元への報告をしてくれたことで発見される脆弱性がほとんどです。

Internet ExplorerやWindows、Chromeなどの脆弱性は非公開で報告すれば多額の賞金が与えられます。大きな名誉も得られます。脆弱性を見つけたからといって、リスクを冒してそれを攻撃するメリットは大きくありません。

しかし、サポートの終了したソフトウェアは違います。公開されてしまった脆弱性で攻撃をすることができますし、それから守ってくれる人もいません。これが、サポートの終了したXPが危険な理由です。

開発者としてできること

じつは本当に言いたいことは、開発者に対しての話だったりします。安全なソフトウェアをつくるためにどうすべきかの話です。

Windowsのセキュリティ情報を読んでいると、「メモリ破壊による脆弱性」というものが多く出てきます。

メモリ破壊というのは、開発者が意図しないメモリへの書き込みが行われる脆弱性です。以下のバッファオーバーランなどがその代表例です。

IPA ISEC | バッファオーバーラン ~その1・こうして起こる~

メモリ破壊が不可能なことをメモリ安全であるといい、CやC++のような言語はメモリ安全でありません。メモリ安全でない言語では、ほんのちょっとした不注意によって非常に深刻な脆弱性が生まれてしまいます。

そして、C/C++のようなメモリ安全でない言語が、多数の脆弱性を生んできたというのは歴史的な事実です。

では、どうすればメモリ破壊による脆弱性を作らないことができるのか?これには単純で明快な解決策があります。

「メモリ安全な言語を使う」ということです。

ブラウザ、コーデック、メールクライアント、Webサーバー、バーチャルマシン、エディタ、動画・音楽プレーヤー、オフィスソフト。これらのソフトウェアは今でも多くがC/C++で作られていますが、これまでの脆弱性の歴史を考えればC/C++はこれらをつくるのに向いていません。

メモリ安全な言語を使用していればJPEG画像の閲覧などのプログラムで、任意のコードが実行可能な脆弱性の入り込む余地がありません。

C/C++と同様にネイティブコードを出力する言語であっても、D言語やGoはほとんどメモリ安全な言語です。

さらに、MozillaはC/C++を代替するためのメモリ安全な言語「Rust」の開発をしています。Mozillaはこの言語を使って、次世代のブラウザレンダリングエンジン「Servo」の開発にも取り掛かっています。

C/C++はもはや代替されるべき言語です。


ある程度の知識がある開発者がWindows XPを使用している人を見れば、「危険だ」「今すぐ新しいOSに変えた方がいい」「人にも迷惑がかかることだから自己責任では済まない」くらいのことは思うはずです。

しかし、メモリ安全でないCやC++でソフトウェアを作っている人を見て、「危険だ」「今すぐ新しい言語に変えた方がいい」「人にも迷惑がかかることだから自己責任では済まない」という人は、ほとんどいません。

不思議なことです。

メモリ安全でないCやC++を使い続ける人たちは、「気を付けて使えば大丈夫」「新しいことを覚えるのは大変なことだから」「コストがかかることだからそう簡単にはできない」と考えるのでしょうか。

でも、それってXPを使い続ける言い訳と何も変わらないように思えます。

2014/04/23: コメントより「メモリ安全」に関する記述を修正

脆弱性の歴史からみるWindows XPのウイルス感染過程」への11件のフィードバック

  1. boleros

    メモリ安全な言語であるというD言語やGoの処理系が何言語で書かれているか、またその理由を述べられる者だけがC++のメモリ安全性に石を投げなさい。

    返信
  2. shohei909 投稿作成者

    DとGoの主な処理系はCとC++ですね。
    ですが、Rustの処理系はRustです。(セルフホスティングされる前はOCamlでした)
    DにもDDMDというD言語で書かれた処理系があります。

    言語の処理系にCやC++が使われることに必然性なんてないですよ。

    逆にCやC++でも構わない理由ならありますね。コードのコンパイル時にメモリ破壊の脆弱性があったとしても、コンパイラをねらった攻撃が成立する場面はあまりないです。

    DやGoの処理系がメモリ安全でない言語で書かれているからといって、ブラウザやコーデックやメールクライアントなどなどの攻撃対象になりやすいプロダクトをメモリ安全でない言語で書くのが良い理由にはなりません。

    返信
  3. 南山まさかず

    C++でメモリ系の脆弱性を作るのってそんなに簡単じゃないような……あっ、もしかしてstd::vector使わず生配列使ったり生ポインタ使ったりdelete手書きしたりしてる人ですか、だったら仕方が無いですね

    返信
  4. 南山まさかず

    というジョークはさておいて、じゃあC/C++でなかったらいいのかと言ったらPHPやRubyなんかのevalのある言語だったらだいたい同じような問題(任意コード実行)が可能だし、メモリ安全だから安全というのはやや狭量な至高に思える
    「じゃあeval使わなかったらいいじゃないか」に対しては「「じゃあメモリ安全性の高いコードを書けばいいじゃないか」と同じ主張だよねそれ」と言えるし
    HaskellやOCamlで書け、というのならわかる、それなら諸手を上げて賛成する、なおFFIに関しては(ここで途切れている

    返信
  5. boleros

    まずC言語とC++を区別するところからはじめましょう。その二つは全く異なった別言語です。
    まずあなたが挙げたバッファオーバーランの問題だが、リンク先のサンプルにある strcpy はバッファの長さを考慮せず本質的にバッファオーバーランの危険がある。
    strncpy という代替はあるが、そもそも管理するバッファのポインタと長さを個別に管理すること自体が危険であるという指摘であれば、それは正しい。
    サポートの切れたWindows XPのように常に本質的な危険を持っていることに近くはある。
    以上はC言語の問題である。
    C++ はC言語との互換性のために非安全な機能を残しているが、モダンな C++ 実装では一切使われない。
    C++標準の文字列やコンテナライブラリは、あえて非安全な方法と組み合わせない限り、例示されたような古典的バッファオーバーランの問題は起きない。
    また、C++11以降の標準ライブラリやBoostライブラリでは、スマートポインタやRAIIといった、特定の問題に対して「常に安全な方法」を提供している。
    特にRAIIは、メモリのみならず一般のリソース管理手段として、記述性と例外安全性において特に優れた点を持っている。
    しかしC++11以前かつBoostの使えないような環境では、不十分で危険な機能を使わざるを得ないという指摘であれば、それは正しい。
    そもそもそれは「現在の」C++ではないのであって、遠い過去の規格をもとに言語を論ずるべきではない。
    かつてのPHP4.0.3がマルチバイト処理機能を持たなかったと言う理由で「PHPを使うべきでない」と主張するのが誤りであるのと同じだ。
    これに対する反論は自明だ。「新しいバージョンのPHPを使え」。C++も同じである。「現在のC++を使え」。

    「C++を使う理由はあるか?」という話に戻る。
    大きな三つの理由は資産利用とゼロ・オーバーヘッド原則、そして選択肢の広さだ。
    C++のようなメジャー言語には多くの資産がある。その中には、あなたの挙げた古典的バッファオーバーランの問題など存在しないモダンなライブラリも数多くある。
    ゼロ・オーバーヘッド原則は、「利用しない機能によるオーバーヘッドが無い」ことだ。
    この原則はC言語に対する実装のパフォーマンス比較で持ち出されることが多いが、一般にはガベージコレクションといったものまで含む。
    GCと非GCではそれぞれトレードオフなメリット・デメリットがあるが、GCを必要としない理由があればC++を選ぶしかない。
    またC++は、例えばカスタムアロケータといった低水準な最適化から、高水準なマルチパラダイムプログラミングまで、あらゆるレベルで広い選択肢を持つ。
    低水準な最適化はとうぜん潜在的な危険性を持つが、カスタムアロケータの利用は例えばD言語でも安全でないから、それが言語に由来する特有の危険でないことは明らかだ。

    改めて言うが、あなたの例示した「メモリ安全でない」ケースはすべてC言語のものだ。
    (互換性のために残されているレガシー機能を除いて)モダンなC++とは一切関係がない。
    「C++において、安全でないレガシー機能を使うべきでない」という主張であれば全面的に賛同する。
    しかしそれは、「C++を使うべきでない」と主張する論拠にはならない。
    あらゆる言語について、過去のバージョンのいまや使われていないレガシー機能を理由として、使うべきでないと主張するのが誤りであるのと同じく。
    「わざわざレガシー機能を避けるための学習コストが余分にかかる」という言い分もあり、尤もな部分もあるが、
    それには「新しいことを覚えるのは大変なことだから」という態度が知的に怠惰であるという、あなたの主張がそのまま反論となる。

    返信
  6. shohei909 投稿作成者

    >> 南山まさかずさま
    はい、Ruby, PHP, Java, C#などは、その言語自体がメモリ安全であっても、任意コードが実行可能な脆弱性は生まれる可能性があります。

    理由の一つは、おっしゃるとおりで、メモリ破壊以外による脆弱性です。例えば、ユーザー入力をevalやexecのような関数で使うとコードインジェクションやコマンドインジェクションによって任意コード実行可能になる場合があります。

    これらも危険な攻撃です。メモリ破壊とは別に、これはこれでとれる対策を十分にとるべきです。

    ただ、メモリ破壊は、起こりうる場面の多さ、実際にこれまでに起こった件数、起こったときの影響、すべてが大きいです。他の脆弱性を根絶できなくても、これを無くすことは非常に価値があります。脆弱性が0にならないからといって、脆弱性を10コも20コも減らせる対策をとらない理由にはなりません。

    またもう一つ、Java, C#, Rubyなどで任意コードが実行可能になる場合があります。

    これらの言語では、標準ライブラリに含まれるメモリ破壊の脆弱性を踏む場合があります。これは、標準ライブラリの一部がメモリ安全でない言語で実装されてるためです。なので、例えばJavaでブラウザを作ったとしてもあまり安全にはなりません。C++をJavaやC#で置き換えれば脆弱性の件数は減らすことができるかもしれませんが、これらの標準ライブラリに含まれる脆弱性は件数が多くなかったとしても、多くのソフトウェアに共通してしまうので攻撃されやすいです。

    ですから、私が主張したいのは、今すぐC++をJavaやC#で代替しろということではありません。JavaやC#よりももっと低いレイヤーにあるコードから、なるべく早くメモリ安全なもので代替するべきだ思っています。

    HaskellやOCamlのメモリ安全性についてよく知らないで記事には出しませんでしたが、ファイル圧縮とかファイルフォーマットの変換とかはむしろHaskellやOCamlが得意な領域であると思うので、(これらがメモリ安全なら)HaskellやOCamlは実際いい選択肢だと思います。

    >> bolerosさま
    内容の濃いコメントありがとうございますm(_ _)m

    ですが、まずひとつbolerosさんが誤解してることがあります。私が新しいことを学ぶべきだと主張してるのは、学ばないことが怠惰だからではありません。むしろまったくの逆です。

    プログラマにとって怠惰は美徳です。怠惰だからこそさまざまなことを自動化しようと考えます。メモリ安全な言語を使うべきだと主張する理由も、その方が怠惰だからです。メモリ安全な言語を使えば、コードの修正や、セキュリティアップデートの頻度も減らせます。ウイルスに感染して面倒に巻き込まれるユーザーを減らせます。長期的にみれば目先の学習コストよりも、後々の面倒のコストの方が高いから新しいことを学ぶべきだ。より怠惰に過ごすために、必要最低限の努力をすべきだという主張です。

    あと、記事内でセキュリティについてCとC++が同等であるように見えるのはよくないことでしたね。勉強になります。

    それでは、C++の話をします。C言語ではない、C++の話です。

    C++のセキュリティ面でよくない点は、まさにC言語のレガシーな機能との互換性をもってしまっていることです。

    残念なことにC++11(G++4.8.2の-std=c++11オプション)であっても、互換性のせいで、以下のようなレガシーで脆弱なコードがコンパイルできてしまいます。

    すべての人が、勤勉で、博識で、注意深ければC言語を書いても、脆弱性なんて生まれません。でも、実際はそうではないです。多くの人は、怠惰で、無知で、不注意です。だからこそ、怠惰や、無知や、不注意が理由で、脆弱性が生まれないような環境をつくることが重要です。

    たしかに、C++には多くの資産があります。しかし、その資産の多くはレガシーです。

    昔からあるOSSや、古い本、古いC++しか知らない人などからC++を学べば、モダンなC++の書き方を知らずにC++を書くことになります。あるいは組み込みなどのためにC言語をみっちり学んでいたひとが、PC向けのC++に転向してくれば、初めのうちは脆弱になりやすいコードを書くことになるでしょう。C++では無知や怠惰によって脆弱性が生まれます。

    C++に起こりうるメモリ破壊のコードの種類は多岐にわたっているので、レビューで検知するのも簡単ではありません。C++では、ちょっとした不注意で脆弱性が見逃されます。

    一方で、メモリ安全でない機能がunsafeで隔離されているような言語であれば、その言語を深く知らない人ほどメモリ安全でない機能に手を出しません。無知や怠惰によって脆弱性が生まれにくい構造があります。もし、無知によりコードにunsafeを使ってしまっても、レビューアはunsafeにさえ気をつかっていればそれに気づくことができます。つまり、不注意によって脆弱性が見逃されにくい構造があります。

    モダンなC++がレガシーなC言語と比べて、脆弱性を作りにくいのは事実でしょうが、初めからメモリ安全性を考えて設計された言語とくらべてC++11が脆弱性をはるかにつくりやすいのもまた事実でしょう。

    返信
  7. ツイ子

    “C/C++のようなメモリ破壊を許す可能性のある言語のことを、メモリ安全でない” と独自の定義を行いFUD を行っているので、ちょっとした不注意による記事の脆弱性が生まれてしまいます。

    返信
    1. boleros

      私のコメントへの反論への再反論として述べたいことがいくつかあるのですが、その前に一つだけ。
      「メモリ破壊が不可能な」言語は存在しません。
      「メモリ安全性を保証する個別の言語機能」は各々に存在します。
      当然C++にも、先に述べたように安全性を保証する機能があります。
      言語機能全てについてメモリ安全性が保証されている言語は、少なくとも私の知る限りの実用されている言語では存在しません。
      例えばD言語の@system属性関数は未定義動作を起こさないことを保証しません。
      (この未定義動作には、当然バッファオーバーフローを含みます)
      言語のメモリ安全性を評価するならば、具体的な要件に対して「より安全であるか」「より安全でないか」の尺度しかありません。
      具体的なプロジェクト案件について、要件とメンバーの能力を考慮して安全側に振るかどうかを決めるならば妥当ですが、一般に不正確な定義を流布するのは悪質な誤謬と言わざるを得ません。

      返信
  8. shohei909 投稿作成者

    >> bolerosさま

    コメントありがとうございます。
    こちらも、bolerosさんのコメントについて、いくつか言いたいことがあります。

    まず1つ目、”言語機能すべてについて”メモリ破壊が完全に不可能な言語ですでに実用されているものは、現在のところ存在しないというのは、確かにその通りかもしれません。

    ですが、スマートポインタやRAIIを指して、C++にメモリ安全性を保証する言語機能があるというのは完全な間違いです。

    C++11やBoostの安全性が改善された書き方を簡単にする機能と、Dの@safeのような危険な処理が使用されていないことを検証する機能はまったく違います。

    スマートポインタは、「メモリ破壊の1種である、メモリの2重解放や、解放後のメモリへのアクセスが起きにくい書き方」を提供しますが、メモリ安全性の”保証”はしてくれません。やむおえず、または間違ってdeleteやauto_ptrを使用すればメモリの破壊が起きます。

    RAIIについては機能ですらありません。ただのコードの書き方です。「常にRAIIをすれば、メモリ破壊は起きないよ」という主張は、「常にmemcpyを使う前にバイト数チェックすれば、メモリ破壊は起きないよ」という主張とあまり変わりません。前提条件を実現するのが難しい上に結論まで間違ってます。

    スマートポインタもRAIIも、メモリの2重解放や、解放後のメモリへのアクセスの対策として不完全ですし、その他のバッファオーバーラン、バッファオーバーリード、整数オーバーフロー、未初期化のポインタの参照、間違ったポインタ演算、書式指定文字列攻撃、配列の領域外アクセスなどに対してそれぞれにまた別の対策をとらなければなりません。

    bolerosさんはそれらの対策をすべて含むコードをモダンなC++というとてもシンプルな言葉で表現しているのだと思いますが、それらの対策は実際のところ複雑です。

    sprintf, strncpy, scanf, auto_ptr, 通常の配列などの危険な機能を自分ですべて把握して避ける必要がありますし。例えば、リストにstd::vectorを使っても[]演算子をつかえば、領域外のアクセスは検証されないなど、新しい機能であっても気をつけなければいけないことがあります。

    BoostはあなたにモダンなC++の書き方を提供してくれるかもしれませんが、あなたが書いたコードがモダンであることを保証してくれません。

    2つ目です。前のコメントのC++の利点についてです。「資産」と「ゼロ・オーバーヘッド」と「選択肢の広さ」がC++の利点だということには私も同意します。

    ですが、安全性のためにメモリ破壊が起こらないようなモダンなC++を書こうとすれば、これらの利益は受けられなくなってしまいます。C++11やBoostの資産はまだそれほど多くないです。スマートポインタや、オーバーフロー防止の機能には必ずオーバーヘッドが存在します。安全性のことを考えれば、カスタムアロケータや、strcpy、memcpyのような低水準な高速化は捨てなければなりません。

    bolerosさんはメモリ安全でないコードのことをモダンなC++とは一切関係がない。と切り捨ててしまいましたが、それは同時にこれらの利点をモダンなC++と一切関係がないものとして切り捨てることにもなります。

    3つ目です。「具体的なプロジェクト案件について、要件とメンバーの能力を考慮して安全側に振るかどうかを決めるならば妥当」、これについてもその通りだとおもいます。

    ただ、モダンなC++が書けるメンバーだから、脆弱性のあるコードを書かないと考えるべきではありません。また、開発メンバーは変わっていく可能性も高いです。企業のプロジェクトであれば、ずっと同じメンバーで開発することはあまりありません。オープンソースであれば、外部の開発者も入ってきます。

    そして、作ろうとしてるプログラムに安全性がいらないという判断は慎重に行うべきです。

    例えば、数学系のライブラリ。安全性とは関係ないように思いがちですが、そのアルゴリズムは、ファイル圧縮、画像描画、暗号化などに使われるものかもしれません。

    例えば、3Dのレンダリングエンジン。現在の用途ではあまり安全側に振らなくていいように思えます。ですが、10年後には3DプリンタやGoogleグラスやOculus Riftのような端末の普及によって、3Dモデルを端末で表示するのが一般的になるかもしれません。そうなったら当然安全性が必要になります。

    開発する言語を決めるのは開発の初期ですが、安全性が足りなかったことに気づくのは大抵そのプログラムが多くの人に使われるようになったときです。

    C++で大量のコードを書いた後に、もっと安全側に振っておくべきだったと気づくのは本当に最悪なことです。C++は静的な解析によって安全でない範囲を特定するのが難しいので、すべてのコードを精査しなおして、延々と脆弱性の修正のアップデートを続けることになります。

    ですから、開発したいものが安全性が求められるものや、広く使われる共通基盤なら、やはりCやC++を避けるべきです。

    返信
  9. SpaceHide

    OSやソフトのプログラムのことなど、ほとんど知らない、一人のパソコン・ユーザーとして、
    このお話の、筆者のご意見をまとめると、たぶん、以下の<総まとめ>のようなくくりになると思うが、
    自分の拙い理解は下記<最終結論>というか、まだよくわかっていないのである。

    <最終的結論>
    他方で、ウイルス対策ソフトのサポートが続けられて最新の状態に保たれていて、
    Windows XP 上でもセキュリティベンダーによって積極的にサポートがあるアンチウイルスソフトを同時に使用していても、
    OSのサポートの終了したXPでは、公開されてしまった脆弱性自体は攻撃を受けやすいし、
    それを守るすべもないから、他のOSのVista, 7, 8やLinuxの利用に比べると明らかに、
    OSのプログラムシステム本体に、いわゆる穴だらけの脆弱性自体があるWindows XPを使い続けるのは、危険度が高い・・・・・・
    ・・・ ということかあ。。。

    それでも、一応、上記アンチウイルスソフトを併用してても、OSのサポートの終了したXPを使っていると、   
    メールをただ閲覧しただけ、いつものSNSやWebサイトを閲覧してるだけで、ほぼ確実にウイルスに感染するのかなあ・・・
    現行でOSの脆弱性をサポートし続けている、他のOSのVista, 7, 8などを利用してたら、
    (もちろん、最新のアンチウイルスソフトを併用しつつであるが、)
    ウイルスに感染することはほとんどない、っていうことなのかなあ・・・・・
          
    ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー               

    <総まとめ>
    Windowsには毎月のように脆弱性が発見されています。これは、XPだけでなくVista, 7, 8でも同じことです。
    XPサポート終了が問題になるのは、この毎月のように発見されている脆弱性が修正されなくなるからです。

    脆弱性があるということは「ちょっとした過失でウイルスに感染しうる」というより、
    「何の過失がなくてもウイルスに感染しうる」ということです。
    むしろ、「脆弱性の放置されたPCを使い続けること自体が、過失である」とも言えます。

    結論として、Google検索しか使わなくても、Twitterしか使わなくても、Youtubeしか使わなくても、
    Facebookしか使わなくても、悪質なWebページを閲覧する危険性がある。

    Windowsの脆弱性についてばかり取り上げていますが、これは決してWindowsが他のOSに比べて脆弱性が多いという意味ではありません。
    例えば、Linuxなどにも「オープンソースなので脆弱性が少ない」ということだけであって、同じように脆弱性は存在しています。

    まとめ;
    サポート期限切れのソフトだと、メールをただ閲覧しただけ、いつものSNSやWebサイトを閲覧してるだけで、ウイルスに感染するよ!

    ユーザーとしてできること;
    ソフトウェアを使う側としてできることって、当たり前なことを当たり前にやるってことぐらいしか思い浮かばないです。
    Linux、Windowsだの、Internet Explorer、Chromeだの関係なく以下のようなことはやっときましょう
     ・ OSはちゃんとアップデートしましょう
     ・ ブラウザやメールクライアントなどのソフトもアップデートしましょう
     ・ セキュリティソフトを使いましょう

    但し、サポートの終了したソフトウェアは違います。
    公開されてしまった脆弱性で攻撃をすることができますし、それから守ってくれる人もいません。これが、サポートの終了したXPが危険な理由です。

    その他では、Windowsのセキュリティ情報を読んでいると、「メモリ破壊による脆弱性」というものが多く出てきます。
    では、どうすればメモリ破壊による脆弱性を作らないことができるのか?
    これには単純で明快な解決策があります。
    メモリ安全でないCやC++と違う「メモリ安全な言語を使う」ということです。
    メモリ安全でないCやC++を使い続ける人たちは、
    「気を付けて使えば大丈夫」「新しいことを覚えるのは大変なことだから」
    「コストがかかることだからそう簡単にはできない」と考えるのでしょうか。
    でも、それってXPを使い続ける言い訳と何も変わらないように思えます。

    <追記>
    じゃあC/C++でなかったらいいのかと言ったらPHPやRubyなんかのevalのある言語だったら
    だいたい同じような問題(任意コード実行)が可能だし、メモリ安全だから安全というのはやや狭量な至高に思える
    「じゃあeval使わなかったらいいじゃないか」に対しては
    「「じゃあメモリ安全性の高いコードを書けばいいじゃないか」と同じ主張だよねそれ」と言えるし
    HaskellやOCamlで書け、というのならわかる、それなら諸手を上げて賛成する、などなど。。。のフィードバック。

    返信

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です