「脆弱性の多いプログラミング言語」ランキング、C言語が大差で1位に 49
ストーリー by hylom
まあ色々なところで使われていますし 部門より
まあ色々なところで使われていますし 部門より
WhiteSourceによる脆弱性とプログラミングの関連性に関する調査では、もっとも脆弱性報告が多かったのはCで実装されたプロダクトという結果になったという(マイナビニュース)。
Cに続くのはPHP、Javaとなっている。Cが多いのは多くのプロダクトで使われているだけでなく、さらにLinuxカーネルやOpenSSLといった注目されやすいプロダクトで使われていることがこの理由として挙げられている。
また、記事では過去10年間に置ける脆弱性数の変化も提示されている。
言語と無関係な剤弱製 (スコア:4, すばらしい洞察)
記事では、関連する脆弱性が多いからといって必ずしもそのプログラミング言語がセキュリティに対して脆弱ということを意味するわけではないと説明。 [mynavi.jp]例えば、SQLインジェクションは開発言語には非依存な脆弱性だけど、そこらも考慮した上での統計なんでしょうか。
Re: (スコア:0)
CWE-79(XSSのこと)やCWE-20(不適切な入力チェックのこと)が多いとか書いてあるから考慮してないかもね
Re: (スコア:0)
C言語でXSSが多いというのはなんか違和感があるんだが? そんなにC言語で書かれたCGIがまだ多いのか? PHPとかが上位に来ている原因?
Re: (スコア:0)
高級言語のライブラリなんかが性能等の事情でネイティブモジュール呼び出しただったりするな。
脆弱性よりも (スコア:4, おもしろおかしい)
のランキングかと思ったよw
clausemitz
Re: (スコア:0)
そういう状況では品質も下がるだろうし、プロダクト数的にも品質的にも相関するんでね?
Re: (スコア:0)
精神に脆弱をもたらすという…
全能性と脆弱堅牢性(ポカヨケ)は両立しない (スコア:1)
インタプリタ言語とか、スクリプト言語とか、お釈迦様(アセンブラ、C、etc)の手の上で動いているわけで。
ハードウェア直に叩くようなネイティブに落ちる言語って全能なんだから
脆弱性持たざるを得ないというか、その、「保護機構を記述する言語」なんだから
やむを得ないというか、自明だと思う。
この言語は脆弱性に強くて堅牢です、なんていうその言語の処理系、自身で記述できるのかと。
解決したら(できたら)すごいとは思うが。
Re: (スコア:0)
最近の言語は基本的に自身で自身のコンパイラが作れるんですが
Re:全能性と脆弱堅牢性(ポカヨケ)は両立しない (スコア:1)
てかコンパイラって文字列処理とデータ構造の操作とファイルI/Oだけですからね。
言語仕様の脆弱性と言語処理系の脆弱性の話がごっちゃになってると思います。
Re: (スコア:0)
コンパイラなんて乱暴に言えばテキストファイルを読み込んでバイナリファイルを吐き出すだけのバッチフィルターでしょ。最近の言語どころかawkみたいな40年前のインタプリタでも難しくはないはず。
Re: (スコア:0)
保護機能を無効にするかライブラリを外だしするかでしょ。
昔からアセンブリ言語でアセンブラ作れるし。
Re: (スコア:0)
セルフホスティング・・・というかブートストラッピングの話ですかね?
Re:全能性と脆弱堅牢性(ポカヨケ)は両立しない (スコア:3, 興味深い)
元コメもだけど、この手の話、言語と実行環境の話がごっちゃになってて良くない。
それぞれの言語が、実行環境さえあれば何でも出来るのは自明。
元コメが主張したがってるのは、「その言語の標準的な実行環境が、コンピュータのあらゆる機能を叩けるように作られているかどうか」の話。
C言語の普通の環境なら、「メモリの0番地を書き換える」とか「パソコンの機能を直接呼び出していきなりリブートする」とか、なんでもできる。rootかAdministratorの権限は必要だけど。
JavaScriptの普通の環境では、まず不可能。Administrator権限で立ち上げたブラウザ上からでも普通は無理。
JavaScriptでCコンパイラを書くことは書ける。「いきなりリブート.c」をコンパイルして機械語の16進数の羅列をブラウザに表示したりはできても、その機械語に実行を移す事はできない。
どうしてもやるなら、JavaScript上から任意の機械語のコードを実行できるプラグインみたいな狂気の代物をブラウザにインストールしておく必要がある。
JavaScript用に、「メモリの任意の番地を書き換える、読み出す」とか「CPUのIOを直接叩く」とか…、みたいなライブラリ一式があったら、JavaScriptで書かれたJavaScriptコンパイラでOSを作る、みたいなことももちろん出来るけど、そんなライブラリ一式は無い(…と思う。ネタで作ってる奴が居るかも知れないけど、広く使われるようなのは無い)。
あとまあ、「そういうライブラリをその言語自体で書けるのか」という論点もあるのかな。スクリプト言語ではまず無理。C言語でも無理そうな気がするな。
Re:全能性と脆弱堅牢性(ポカヨケ)は両立しない (スコア:1)
うぇぶあせんぶりー
Re: (スコア:0)
あれも名前がカッコイイだけで、超早いJavaScriptでしかないからなぁ。ブラウザのサンドボックスからはみ出てパソコンのメモリを書き換えたりSSDを0で埋め尽くしたりはできない。無限にalertを出す兵庫県警レベルのイタズラ程度が関の山。
Re: (スコア:0)
WebAssembly ってポータブルなスタックマシンでしょ?
ホストCPUの機械語が実行できるわけじゃないよね?
Re: (スコア:0)
おおっと、LLVM 8.0の宣伝はそこまでだっ!
Re: (スコア:0)
ちょっとちがうけど、どうせ釣りなんでしょ。
Re: (スコア:0)
C#ならポインタがあるわけだしまあ何でもできるんでないの
所謂広義のインタプリタ系だが
Re:全能性と脆弱堅牢性(ポカヨケ)は両立しない (スコア:1)
「言語としてなんでもできる」と「処理系としてなんでもできる」のどちらの話なのかを区別しないと議論にならないけど、C#はどちらでもないんじゃないかな。
そもそも、「言語として」で言うと、C言語ですら「なんでも」はできない。
LinuxなんかのOSの全機能を呼び出したいなら、syscall [linuxjm.osdn.jp]関数ぐらいは使えないとダメだけど、これはUNIX系のOSのC言語環境になら入ってるけど、C言語の標準関数ではない。syscallを、その手のC言語としての非標準関数を使わずに呼び出そうとすると64bitのOS + C言語でライブラリを使わずにHello Worldをしてみた [qiita.com]のように、アセンブリ言語の力を借りる必要が出てくる。他にも、CPUのIN/OUT命令ぐらいは呼び出せないと「OSにすら依存しないコンピュータのあらゆる操作」とか「OSそのものの動作」とかは出来ないんだけど、これもC言語の範囲を逸脱する。
あと「なんでも」にも複数解釈の余地があって、「動作が遅くても結果的に出来ればOK」なのか「機械語レベルでCPUを思いのままに扱えないとOKとは言えない」なのか。後者だとすると、SIMD [wikipedia.org]演算をきっちり使って高速化しちゃおう、とか言い出すとC言語では無理。どんどん賢くなってるコンパイラが最適化で上手くやってくれるだろう、と期待するしかない。
で、言語ではなく「処理系」の話だとすると、C言語ではアセンブリ言語の力を借りるのに、アセンブラを使わずC言語の「処理系」だけでできなくもない。
C言語の標準には含まれないけど、色んなコンパイラにインラインアセンブラ [wikipedia.org]の拡張機能が付いているから、それを使うとか。
あるいは、あくまでC言語の標準機能のみでやるんだ、と言うなら、例えば、
char func_str[] = "ここに機械語で書いたサブルーチンを入れる";
void (*func)() = (void*)func_str;
func();
こういう風にすると、C言語の処理系だけで、機械語のコードを実行できる。未定義動作とかNXビット [wikipedia.org]とかあれこれ問題はあろうけど。とは言えこれは、バッチリ機械語を使っちゃってるので、「C言語処理系の標準準拠の部分のみ」を使ってるけど(未定義動作だから標準からはみ出してるじゃないか、というツッコミもあり得るかな)、「言語として全部純粋にC言語」と主張できるのかどうかは怪しい。
あとまあ、「メモリを自由に書き換えられるなら、適当な関数やらメソッドの中身を書き換えて、任意コードの実行が出来るぜ」という、言語仕様上の脆弱性を突くようなやり口で万能性を主張するというやり口もあり得るかな。
という所まで、掘り下げて何を主張したいのかを明らかにしないと、議論として迷走しかしない。
ということで、C#のポインタは、そこまで万能ではないんじゃないかな。「任意コードの実行」があるいはできるかも?ぐらいじゃないかと。メソッドにポインタからメソッドに変換するような方法があれば別だけど。
Re: (スコア:0)
ポカをしたプログラムに脆弱性があるのであって、Cに脆弱性があるわけではないと思う。
「脆弱性につながるポカをしやすい言語」と言うことなら納得だけれども。
Re: (スコア:0)
VBやPHPみたいなもんね
Re: (スコア:0)
そういうことを言い出すと最終的にはアセンブラ・Cも機械語の上で動いているだけとかそういう話に…
Re: (スコア:0)
さらには機械語もマイクロコードの上で動いているだけという話に
メモリアドレスだって仮想アドレスで物理的にどこ指してるか分からないし
標準設定の問題? (スコア:0)
C言語は標準設定で、ポインタ・配列の境界チェックをしたり、
セキュアな代替関数がある命令(snprintfとか)は、非セキュアなオリジナル命令を無効にするとか
すればいいとおもう
もちろん、コンパイルオプションや、コード内で明示的に指定することでそれらを無効にして、
高速なコードを書きたい人は書けるようにして
OSやlibc等速度が必要なコードはチェックを無効にしてビルド、
一般アプリはチェックを有効にしてビルドとか
Re:標準設定の問題? (スコア:4, すばらしい洞察)
多分、真面目に考え出すと別の言語を新たに作った方が楽と言うぐらいの変更になるので、JavaとかC#とかSwiftとかRustとかが出来たんだと思う。
配列の境界チェックぐらいまでなら、トリッキーな書き方は全面禁止、ポインタは指している先の有効なメモリの範囲も覚えておく、とかでなんとか実現出来そうだけど。
他にも、オブジェクトの寿命の管理が厄介で、ポインタが指している先がまだ存在するかどうかがC言語ではあやふやになってしまう。プログラマの注意に委ねられてる。
GCの付いてる言語は、ポインタが指している限りは指されているオブジェクトは開放されないという方針で寿命の問題を解決してる。
Rustだと、あらゆる変数の寿命を自明な場合を除いて明示することになっていて、それによって、指している対象よりも寿命の長いポインタの類を禁止していて、ポインタが指している先が存在しなくなっている、というトラブルを排除している。
C言語のコンパイラに似たようなチェックを行うオプションを付けるアイデアもあり得そうだけど、多分無理。「危なそうなコードは却下するよう安全寄りに倒して、ちょっとでも駄目そうな可能性のあるプログラムはエラー。あるルールに従った明らかに安全なコードだけが許されるから、既存のコードもちゃんとルール通りに書き直せ」という感じにできれば良いんだけど。Rustがそんな感じのノリの言語なんだけど、プログラマがしばしば、寿命チェッカが厳しすぎる、あちこちに非自明な寿命の定義を書き加えないとコンパイルが通らない、と嬉し涙を流している。ので、言語仕様上その手の事を書けないC言語のコンパイラにやらせようとすると、ごく限られた書き方だけを使った効率の悪いプログラムしかコンパイル出来ないような、残念なコンパイラになってしまう。
Re: (スコア:0)
何故今でもC言語を使う必要があるかというと、あえてそういうチェックを外す必要のある低レイヤーの実装に必要だからで、そんなお節介な仕様を標準化されても「C言語でなければならない人」にとっては迷惑なだけではないかと。
逆にそうした保護を言語仕様でやってもらわなければならない用途には、今や他の言語を選ぶべきなんじゃないですかね。
Re: (スコア:0)
トレードオフになるよね
Re: (スコア:0)
Cの利便性を保ったまま、ちょっとしたコーディング規則を設ければそこそこ安全で、
コンパイルオプションでセキュアの強制もできるというのは
すでにC++で実現されてるから、変な制約のついた変形C言語は今から作る必要はないだろ。
Re: (スコア:0)
昔はそういうチェックを自動でやってくれる言語(コンパイラがするか実行時チェックかは措くとして)がいろいろあったと思うが、今は猫も杓子もc言語、c言語を使わぬ者プログラマに非ず、という雰囲気でしてねえ。
K&Rの時代には、変数名関数名も極力短く(つまりはタイプ量を少なく)していたのが、その後はタイプ量など気にせず長い名前にするようになったし。
Re:標準設定の問題? (スコア:2)
今そんなにc流行ってんすか
あまりそんな気はしないですが、どこの業界なんでしょう
Re: (スコア:0)
というかCはもう流行ったりはしないけど、かといって無くなれば困るって存在。
自然言語に例えればラテン語みたいなもんだろ。
だいたいPythonやgoみたいな「流行りの言語」なんてのは結局Cの拡張だしね。
Re: (スコア:0)
K&Rの時代を引き合いに出してるってことは、「今」=「C89以降」なんじゃね?
Re: (スコア:0)
短い識別子はコンパイラとカリンカの制限のためでは
Re: (スコア:0)
snprintf は sprintf よりはセキュアだけど、サイズを間違えたらバッファオーバランする。
あと、strcpy とか strcmp とかの非セキュア関数の代替関数はどうしよう。
Re: (スコア:0)
Re: (スコア:0)
逆だったらCの評価も変わったんだろうな。
標準関数はセキュアだけど、非セキュアなことをやりたい時に代替関数を使えば低レベルなところも触れるみたいな。
Re: (スコア:0)
単なる例だと思うけれど、 snprintfで指定するサイズ間違える時点ですでに使い方がおかしい。
お作法無視して無頓着に簡略化してコード書くからおかしなことになるだけで
C言語の脆弱性はプログラマがそういう書き方しているからとしかおもわないんだよなー
C言語でのリソース管理はプログラマのお仕事ですよと。
セキュア関数って基本は、車輪の再開発程度にしか思えないんだけど
NUL終端してない文字列とかあそこまで意識する必要があるのかね。。
そういうのって文字列じゃなくてバイナリデータの扱いにするだけと思うのだけれど
Re: (スコア:0)
snprintf の n が何のためにあるのか知らない人がいるのですよ。
n に何を渡すか分かってないから、結果それで防止できるはずのバグが防止できないとかよくある。
Re: (スコア:0)
snprintfはsprintfの相対的なセキュア版でしかないからね。
意味がわからない方が良識的だと思う。
良い点でもあり悪い点でもある (スコア:0)
libcのパラメーターチェックを厳格化したりすれば多少はセキュアになるとは思うけど
ポインタで好き勝手する以上は根本的解決はできないだろうし
ポインタで好き勝手できなければC言語の価値が大きく減少するし
ポインタの存在>コンパイル言語>VM・インタープリター … という超えられない枠があるから
各枠内で比べたほうが実用的な情報になる気がします
Re: (スコア:0)
C#==ポインタの存在>コンパイル言語>VM・インタープリター
Re: (スコア:0)
プリティでキュアキュアなCCuredとかあるけどな
組み込み方面 (スコア:0)
新規のコードはまあいいんですが、古いコードだとK&R時代のプロトタイプ宣言すら
してないソースを書き換えながら(パッチを当てながら)使ってたりする場合もあります。
それもあってgccのバージョンも3とか普通の現役だったりします。
これがそれなりにCが分かる人が手を付けている場合は救いようもあるのですが
社内で手の空いている人に適当に振って修正する事もあってなかなか楽しい状況。
ドキュメントがないのは当たり前で、最新のソースすら判別不能だったりする事も。
そういう現場がC言語を悪者扱いしていたらごめんなさい。
鼻からshellcode (スコア:0)
そりゃ言語仕様で任意コード実行が認められているからな。いやチューリング完全なら任意コード実行できるだろという話じゃなくて。
未定義動作を踏んだときに何が起きてもいい(規格は関知しない)とはそういうこと。バッファオーバーランによる未定義動作が典型例。
もちろん未定義動作をすべてコンパイルエラーや(安全な)実行時エラーにしてもいいし実際そういう実装もいくつか存在するが、性能やABI互換上の理由により研究室のおもちゃの域を出ていない。
Re: (スコア:0)
タイトルに座布団一枚。
意図せず未定義・不定になってるぽい部分は置いとくにしても、
未定義動作で鼻悪魔の代わりにI/Oレジスタ召喚する「仕様」とか組み込みじゃ日常だしねぇ。
シェルコードっつか機械語を文字列リテラルで保持する例もままあるし。
アプリは (スコア:0)
Cではなくて、ほかの言語で書けということでは
守る側? (スコア:0)
かつて黎明期の使用者は「守る側」だったと思うのですが、いつのまにか「守られる側」の使用者増えたと。こうですか。