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

IDS13-J. ファイル入出力やネットワーク入出力の両端で互換性のある文字エンコーディングを使う

個々の Java 実行環境にはデフォルトの文字エンコーディングが定められている。使用可能な文字エンコーディングはJava SEのドキュメント「サポートされているエンコーディング」に列挙されている[Encodings 2006]。文字列とバイト列との間で変換を行う場合、変換内容を指示するために、文字エンコーディングを指定する必要がある。明示的に文字エンコーディングを指定しない場合は、デフォルトの文字エンコーディングが指定されているものとみなされる。文字列がなんらかのチャネルを通じて送られるとき、送信側では文字列データをバイト列に変換して送信し、受信側では受け取ったバイト列を再び文字列に変換する。このとき、送信側と受信側では、同一の文字エンコーディングを指定する必要がある。文字エンコーディングが一致しないと、データの破壊を招く。

Java API [API 2006] の String クラスの説明には以下のように記述されている:

新しい String の長さは文字セットによって変化するため、部分配列長と一致しないことがある。指定された文字セットで指定されたバイトが無効な場合、このコンストラクタの動作は指定されない。

有効な文字列に変換できることが分かっているバイナリデータについては、そのまま読み込んで文字列データに変換してもよい(「FIO11-J. バイナリデータを文字データとして読み込もうとしない」の例外 FIO11-EX0 により)。

違反コード

以下のコードはバイト列を読み込み、デフォルトの文字エンコーディングで String に変換している。デフォルトの文字エンコーディングがバイト列を生成したときの文字エンコーディングと異なると、正しい String オブジェクトは得られないだろう。入力のなかに、デフォルトのエンコーディングでは適切に表現できない値が含まれていると、未定義の動作を引き起こす。

try {
  FileInputStream fis = new FileInputStream("SomeFile");
  DataInputStream dis = new DataInputStream(fis);
  byte[] data = new byte[1024];
  dis.readFully(data);
  String result = new String(data);
} catch (IOException x) {
  // エラー処理
}
適合コード

以下のコードでは、String コンストラクタの第2引数に、意図した文字エンコーディングを指定している。

try {
  FileInputStream fis = new FileInputStream("SomeFile");
  DataInputStream dis = new DataInputStream(fis);
  byte[] data = new byte[1024];
  dis.readFully(data);
  String encoding = "SomeEncoding"; // たとえば "UTF-16LE"
  String result = new String(data, encoding);
} catch (IOException x) {
  // handle error
}
例外

IDS13-EX0: プラットフォームもデフォルトの文字エンコーディングも受信側と同じものを使用する Java アプリケーションでデータが生成され、かつ、そのデータがセキュアな通信チャネルを通じて送信されたのであれば、受信側における文字エンコーディングの指定は省略できる(「MSC00-J. セキュアなデータ交換には Socket クラスではなく SSLSocket クラスを使用する」を参照)。

リスク評価

ファイル入出力やネットワーク入出力を行う際に文字エンコーディングを指定しないと、データが破壊される可能性がある。

ルール 深刻度 可能性 修正コスト 優先度 レベル
IDS13-J P2 L3
自動検出

このガイドラインへの違反を適切に検出するのは難しい。

参考文献
[Encodings 2006]
翻訳元

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

IDS13-J. Use compatible encodings on both sides of file or network IO (revision 62)

Top へ

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