高レベルのプログラミング言語から十分にテストされ、証明されたAPIを使用するのではなく、ハードウェアに密接に接触することから生じる多くのセキュリティリスクがあります。 Javaなどの言語よりもCでバッファオーバーフローを発生させる方がはるかに簡単です。
すべてのCプログラマーが知っておくべきリスクまたは脆弱性(バッファーオーバーフローなど)は何ですか(つまり、Cプログラマーに関連する脆弱性)?これらはどのような問題を引き起こす可能性がありますか?それらを回避する方法、およびプログラムでこれらを発生させる一般的な間違いは何ですか?
バッファオーバーフローは大きなものです。 Cではデフォルトで範囲チェックは行われないため、バッファを上書きするのは非常に簡単です。標準ライブラリ関数gets()
があり、バッファのオーバーフローを防ぐことはできず、使用することはほとんどありません。
ヒープブロックのスクランブルなど、悪用を妨げる実装レベルの手法はいくつかありますが、ローカルバッファでのバッファオーバーフローは阻止されません。これにより、関数が返すアドレスを変更するなど、興味深いことがよく行われます。
Cには適切な一般的な解決策はありません。多くのライブラリ関数には、書き込む量を制限するバージョンがあります。計算は面倒かもしれませんが。適切なテストが実行されている限り、テストでヒープバッファオーバーフローを検出できるソフトウェアがあり、スタックオーバーフローはテストでクラッシュとして表示されることがよくあります。それ以外は、注意深いコーディングとコードレビューの問題です。
関連する問題は、_'\0'
_ターミネーターが原因で、n文字長のC文字列がメモリにn + 1文字を必要とすることを忘れて、1文字が小さすぎるバッファーに書き込む問題です。攻撃者がターミネーターなしで文字列を格納できる場合、文字列を期待するすべてのC関数は、0バイトに到達するまで処理を続行します。これにより、必要以上の情報がコピーまたは出力される可能性があります(またはDOS攻撃の保護メモリに到達する可能性があります) )。ここでも、解決策は認識、ケア、およびコードレビューです。
printf()
ファミリには別のリスクがあります。 char * str; ... printf(str);
と書いたことがある場合、印刷時にstr
に '%'が含まれていると問題が発生します。 _%n
_フォーマットディレクティブを使用すると、printf()
がメモリに書き込むことができます。解決策はprintf("%s", str);
またはputs(str);
です。 (また、snprintf()
の代わりにC99 sprintf()
を使用してください。)
特にループインデックスとして符号なし整数を使用すると、問題が発生する可能性があります。小さな負の値を符号なしに割り当てると、大きな正の値が得られます。これは、何かのN個のインスタンスだけを処理したり、strncpy()
のような限られた関数で処理したりすることを損なう可能性があります。すべての符号なし整数を調べます。これらのうちの1つの大きな値はint
の大きな正の値に変換されるため、_unsigned short
_は避けたい場合があります。
Cの文字定数は実際にはint
であることを忘れないでください。 EOF
はchar
で表現できないため、char c; while((c = getchar()) != EOF) ...
のようなものを書くと簡単に失敗する可能性があります。
考えられるCの特徴的なミスはもっとたくさんありますが、これらはセキュリティ上の問題を引き起こす可能性があります。
C固有のリスクには、次のようなものがあります。 バッファオーバーフロー 、 フォーマット文字列攻撃 および 整数オーバーフロー 。
これは、修正に数時間かかる問題を引き起こす可能性のある見逃しやすいリスクです。
問題なくコンパイルできる次のコードを検討してください。
if(lpstr_current_state = CONST_EMERGENCY_STATE_HOLY_CRAP)
{
do_warn_joint_chiefs_of_staff_of_nuclear_attack();
}
lpstr_current_state
がCONST_EMERGENCY_STATE_HOLY_CRAP
にあるかどうかを確認するときに、実際に割り当てています。常に定数変数を左側に置くことをお勧めします。定数を左側に置くと、変数に値を割り当てることができないため、コンパイラーは失敗します。
if(CONST_EMERGENCY_STATE_HOLY_CRAP = lpstr_current_state)
{
do_warn_joint_chiefs_of_staff_of_nuclear_attack();
}
次に、コードを修正して読みながら、「ひどいことだった」と簡単に言うことができます。
if(CONST_EMERGENCY_STATE_HOLY_CRAP == lpstr_current_state)
{
do_warn_joint_chiefs_of_staff_of_nuclear_attack();
}
ただoneセキュリティリスクがあります。ソフトウェアの脆弱性を発見し、自分の利益のためにそれを悪用するために最善を尽くす人が外部にいるという事実。他のすべてはそこから続きます。
したがって、「彼らの正しい心の中に誰もいないだろう...」と思ったら、すぐに「他の人のコンピュータにハッキングしたい人がそれをすることを除いて」と考える必要があります。
最大の結果は、外部からのイベントに反応するとき(たとえば、外部から配信されたデータを処理することによって)は常に、このデータが最悪の敵の制御下にあると想定する必要があるということです。