はじめに
皆さんこんにちは。JPCERTコーディネーションセンターという組織でセキュアコーディングに関する取り組みに携わる筆者らが、これからこの連載を担当させていただくことになりました。どうぞよろしくお願いします。なお、JPCERTコーディネーションセンターは、情報セキュリティインシデントへの対応支援や、ソフトウエアの脆弱性(いわゆるセキュリティホール)に関する製品開発者間における公開日の調整や関連情報の公開なども行っています。
この連載では、バッファーオーバーフロー等の脆弱性をうっかり作り込んでしまったがために、数千万円ものコストをかけて、ユーザに告知し、製品を回収して、工場でファームウェアをアップデートする事態に陥ったり、あるいは脆弱性を放置してユーザを危険にさらし、それが明るみに出て「世間を騒がす」ことになったりしなくても済むように、そもそもの製品開発時からセキュアなプログラムを書くために必要なノウハウをお伝えする予定です。そんな「悲劇」が自分の身に降りかからないとも限らない、ということを実感していただければ幸いです。
本連載のベースになっているのは、当組織も参加しているプロジェクトが公開している「CERT C セキュアコーディングスタンダード」(以下、CERT C)というドキュメントです。CERT Cは、米国カーネギーメロン大学SEI/CERTのスタッフを中心に世界中のCのプロフェッショナルが作成したCのコーディング規約集で、wikiを使って作成されており、現在もなお更新され続けています。
数あるコーディング規約の中でCERT Cが特徴的なのは、セキュリティの観点から、どのようなコーディングが脆弱性を作り込んでしまうのかをまとめているという点にあります。バグがプログラムの不具合につながるのに対し、脆弱性には単なる不具合にとどまらず、外部の攻撃者が脆弱性を突いてユーザを危険にさらすリスクがあります。実際に脆弱なコードの多くは、「よくあるコーディングエラー」が原因で作り込まれています。そのようなコーディングエラーを特定し、正しくコーディングする方法をまとめたものが CERT C のルールとレコメンデーションという形で提供されています。
言語仕様が落とし穴になる
Cには言語仕様に複雑あるいは曖昧な規定が少なからず存在します。複雑な規定の代表は、オペレータの優先順位や整数の型変換に関するルールです。プログラマはこれらのルールを正しく理解した上でコーディングできることが求められています。曖昧な規定の代表は「未定義の動作」です。C99 Annex. Jには約190もの未定義の動作がまとめられています。プログラマがある環境での動作を想定して書いたコードが「未定義の動作」に該当する場合、そのコードが実行される環境によっては、プログラマの想定とは異なる動作をする可能性があります。これが脆弱性を作り込む原因になることがあるのです。
一般に、Cは実行時エラーチェックが手薄な言語です。それは、現在のC言語の仕様が、「Cの精神」(the spirit of C) に基づいて作られているためでもあります。その精神は次の言葉に表されています(JIS X 3010から引用)。
- プログラマを信頼する
- プログラマが必要である事柄を行おうとすることを妨げない
信頼されたプログラマ、つまり言語仕様上の「落とし穴」を正しく理解したプログラマであればその穴に陥らずにプログラムを書けるはずである、また、プログラムに現れない余計な動作は極力行わない、という設計思想に基づいて作られた言語がCなのです。しかし実際には、落とし穴の理解不足がたたり、現実に脆弱性が作り込まれてしまった例は枚挙にいとまがありません。
CERT Cはこのような言語仕様上の「落とし穴」を把握するための参考資料として活用することができます。言語仕様書を読む機会はあまりないかもしれませんが、本連載をきっかけに興味をもって頂き、CERT Cを通じてC言語仕様の理解を深めていただければと思います。
次回以降の本連載の構成は、14のカテゴリーに分類された CERT Cのルールから、ポインタ演算、動的メモリ管理、文字列操作、型変換などのトピックを選んで解説しつつ、セキュアコーディングに活用できるツールの紹介やセキュアなプログラム開発全般の話題も折り混ぜていく予定です。お楽しみに。