JPCERT コーディネーションセンター

MSC09-C. 文字の符号化 - 安全対策のために ASCII のサブセットを使用する

C99 のセクション 5.2.1「文字集合」は以下のように規定している。

ソースファイルでプログラムの記述に用いる文字集合[ソース文字集合(source character set)]、及び実行環境で解釈する文字集合[実行文字集合(execution character set)]の二つの文字集合の定義、並びにそれらの文字集合に関する文字の大小順序の定義がなければならない。ソース文字集合及び実行文字集合のそれぞれは、更に、次の二つの集合に分けられる。基本文字集合(basic character set)と(基本文字集合の要素ではない)0 個以上の文字圏固有の要素[拡張文字(extended character)]の集合。これら二つの集合の和を拡張文字集合(extended character set)という。実行文字集合の要素の値は、処理系定義とする。

ASCII 文字には国ごとにいくつかのバリエーションがあり、オリジナルの ASCII は US-ASCII と呼ばれることが多い。ISO/IEC 646-1991 は、US-ASCII に類似の文字集合を定義しているが、US-ASCII 文字 @[]{|} に対応するコード位置を 国別使用位置(national use positions) として使っている [ISO/IEC 646-1991]。また、文字 #$^`&~ については自由度を持たせている。ISO 646 では、国ごとに異なる ASCII 文字を定義しており、国別使用位置に異なる文字や記号を割り当てている。したがって、国別使用位置にある文字は、US-ASCII にある文字も含め、国際間のデータの送受信においては可搬性に欠ける。国ごとに異なることが原因で、一部の文字は他の文字よりも可搬性が低く、送受信や解釈が正しく行われない場合がある。

可搬性があるのは、英字("A" から "Z" までと "a" から "z" まで)、数字("0" から "9" まで)、空白文字、および以下の文字だけである。

% & + , - . : = _

ファイル、変数、その他のオブジェクトに名前を付ける場合は、これらの文字だけを使用するべきである。このレコメンデーションは「STR02-C. 複雑なサブシステムに渡すデータは無害化する」に関連している。

ファイル名

特定の文字を含むファイル名は問題を起こしやすく、予期せぬ動作を引き起こして、潜在的な脆弱性につながることがある。ユーザがファイルの作成時に名前を付けたり、ファイル名を変更したりできるプログラムの場合は、次の文字やパターンを無効とするような特定の検査を行うべきである。

また、句読点文字の多くは可搬性があるが、ファイル名に使用するときは無条件で安全というわけではない。

これらの文字やパターンの多くは、主としてスクリプトや自動解析に対しては問題となるが、頻繁には使われないため、使用を控えて潜在的な問題を減らすことが最善である。OS によってこの種のファイル名の処理方法が異なるため、相互運用性の問題もある。

MS-DOS の影響により、xxxxxxxx.xxx の形式のファイル名(ここで x はアルファベット文字を示す)は、現在のシステムでは一般に使用できる。プラットフォームによっては、ファイル名の大文字小文字が区別される場合と、区別されない場合がある。VU#439395 は、大文字小文字の問題に適切に対処しなかったために発生した脆弱性の一例である[VU#439395]。

違反コード: ファイル名

以下のコード例では、安全ではない文字がファイル名の一部に使用されている。

#include <fcntl.h>
#include <sys/stat.h>

int main(void) {
   char *file_name = "»£???«";
   mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;

   int fd = open(file_name, O_CREAT | O_EXCL | O_WRONLY, mode);
   if (fd == -1) {
      /* エラー処理 */
   }
}

処理系は、「安全」でない文字を処理系独自の文字に対応するように定義してもよい。たとえば、Red Hat Linux でこの違反コードをテストすると、ファイル名は次のようになる。

??????
適合コード: ファイル名

前述した ASCII のサブセットのみを含む、説明的なファイル名を付けよう。

#include <fcntl.h>
#include <sys/stat.h>

int main(void) {
   char *file_name = "name.ext";
   mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;

   int fd = open(file_name, O_CREAT | O_EXCL | O_WRONLY, mode);
   if (fd == -1) {
      /* エラー処理 */
   }
}

違反コード (ファイル名)

以下のコード例は「FIO30-C. ユーザからの入力を使って書式指定文字列を組み立てない」から抜粋しているが、fgets() が改行も含めて入力を取得するという前提で改行を削除している。

char myFilename[1000];
const char elimNewLn[] = "\n";

fgets(myFilename, sizeof(myFilename)-1, stdin);
myFilename[sizeof(myFilename)-1] = '\0';
myFilename[strcspn(myFilename, elimNewLn)] = '\0';

ファイル名に対して、問題になりやすい文字を避けるための検査が行われていない。このコードがプログラム内でファイルの作成や名前変更に使われていることと、そのファイルが後でスクリプトや自動化プロセスで使われる可能性があることを攻撃者が知ったとすると、出力されたファイル名の特定の文字を選び、悪用目的でその後のプロセスを混乱させることができる。

適合コード (ファイル名)

以下のコードでは、プログラムは安全な文字を選択するための指針に反するファイル名を拒否している。

char myFilename[1000];
const char elimNewln[] = "\n";
const char badChars[] = "-\n\r ,;'\\<\"";
do {
  fgets(myFilename, sizeof(myFilename)-1, stdin);
  myFilename[sizeof(myFilename)-1] ='\0';
  myFilename[strcspn(myFilename, elimNewln)]='\0';
} while ( (strcspn(myFilename, badChars))
           < (strlen(myFilename)));

同様に、信頼できない入力源から得られたファイル名について、含まれる文字をすべて検証し、安全な文字だけが含まれることを保証する必要がある。

リスク評価

正しく機能することが保証されている ASCII のサブセットだけを使用しなかった場合、データが誤って解釈されるおそれがある。

レコメンデーション 深刻度 可能性 修正コスト 優先度 レベル
MSC09-C P4 L3
自動検出

LDRA tool suite V 7.6.0 はこのレコメンデーションの違反を検出できる。

参考情報
翻訳元

これは以下のページを翻訳したものです。

MSC09-C. Character Encoding - Use Subset of ASCII for Safety

Top へ

Topへ
最新情報(RSSメーリングリストTwitter