STR04-J. JVM 間で文字列データを通信するときは互換性のある文字エンコーディングを使う
「文字エンコーディング」や「文字集合 (charset)」は、符号化文字集合のバイナリ表現を指定する。個々の Java 仮想マシン (JVM) にはデフォルトの文字集合が定められているが、標準的な文字集合でない可能性もある。デフォルトの文字集合は仮想マシンの起動時に決定され、典型的にはオペレーティングシステムで使われているロケールと文字集合に依存する [API 2014]。デフォルトの文字エンコーディングは、起動時に設定できる。以下にその例を挙げる。
java -Dfile.encoding=UTF-8 ... com.x.Main
使用可能な文字エンコーディングは Java SE のドキュメント「サポートされているエンコーディング」[Encodings 2014] に列挙されている。明示的な文字エンコーディングの指定がない場合、変換にはデフォルトの文字エンコーディングが使われる。文字列がバイト列として出力され、別の JVM に入力されて文字列に戻されるとき、互換性のある文字エンコーディングを使う必要がある。
Java API [API 2014] の String クラスの説明には以下のように記述されている。
指定された文字集合で指定されたバイト列が無効な場合、このコンストラクタの動作は未規定である。
文字エンコーディングが一致しないと、データの破損を招く。
違反コード
以下のコードはバイト列を読み込み、デフォルトの文字エンコーディングで String に変換している。バイト列が文字列を表現していない場合やデフォルトの文字エンコーディング以外でエンコードされた文字列を表現している場合、正しい String オブジェクトは得られないだろう。不正な入力やマッピング不可能な文字によるエラーは、未規定の動作を引き起こす。
FileInputStream fis = null;
try {
  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) {
  // エラー処理
} finally {
  if (fis != null) {
    try {
      fis.close();
    } catch (IOException x) {
      // ハンドラに処理を移す
    }
  }
}
適合コード
以下のコードでは、String コンストラクタの第2引数に、文字列の生成で使われた文字エンコーディング (この例では UTF-16LE) を指定している。UTF-16 の LE 形式では、リトルエンディアン (最下位バイトが先) でバイト列のシリアライズを行う。文字データが UTF-16LE でエンコードされていれば、正しくデコードされる。
FileInputStream fis = null;
try {
  fis = new FileInputStream("SomeFile");
  DataInputStream dis = new DataInputStream(fis);
  byte[] data = new byte[1024];
  dis.readFully(data);
  String result = new String(data, "UTF-16LE");
} catch (IOException x) {
  // エラー処理
} finally {
  if (fis != null) {
    try {
      fis.close();
    } catch (IOException x) {
      // ハンドラに処理を移す
    }
  }
}
プラットフォームもデフォルトの文字エンコーディングも受信側と同じものを使用する Java アプリケーションでデータが生成され、かつ、そのデータがセキュアな通信チャネルを通じて送信されたのであれば、受信側における文字エンコーディングの指定は省略できる (詳細は「MSC00-J. セキュアなデータ交換には Socket クラスではなく SSLSocket クラスを使用する」を参照)。
リスク評価
JVM 間で文字列データを通信するときに互換性のない文字エンコーディングを使うと、データが破損する可能性がある。
| 
         ルール  | 
      
         深刻度  | 
      
         可能性  | 
      
         修正コスト  | 
      
         優先度  | 
      
         レベル  | 
    
|---|---|---|---|---|---|
| 
         STR04-J  | 
      
         低  | 
      
         低  | 
      
         中  | 
      
         P2  | 
      
         L3  | 
    
自動検出
このガイドラインへの違反を適切に検出するのは難しい。
| Tool | Version | Checker | Description | 
|---|---|---|---|
| The Checker Framework | 
         2.1.3  | 
      Tainting Checker | Trust and security errors (see Chapter 8) | 
| SonarQube | 
         9.9 
       | 
      S1943 | Classes and methods that rely on the default system encoding should not be used | 
参考文献
| [API 2014] | 
         | 
    
| 
         [Encodings 2014]  | 
      
         | 
    
| [Seacord 2015] | 
翻訳元
これは以下のページを翻訳したものです。
STR04-J. Use compatible character encodings when communicating string data between JVMs (revision 123)
