Javaでは、文字データやバイナリデータを送信するときに、バイト配列がよく使われる。一方、バイナリデータを文字データとして読み込むと、正しく処理されない場合がある。なぜならば、バイナリデータのなかには、デフォルトあるいは指定されたエンコーディングの文字コードの範囲に収まらない値が含まれ、文字データとして扱えない場合があるからである。たとえば、暗号鍵データを、送信する際に単純に文字データに変換しようとすると、文字コードの範囲に収まらないバイト値が含まれるため、エラーになる。
違反コード
以下の違反コード例では、BigInteger を表現しているバイト配列を String に変換している。ところが、いくつかのバイト値は有効な文字を表さないため、結果として得られる String データでは、元のデータの情報が落ちてしまっている。この String データを BigInteger データに戻すと異なる値となる。
BigInteger x = new BigInteger("530500452766"); // x を String に変換 byte[] byteArray = x.toByteArray(); String s = new String(byteArray); // s から BigInteger に変換しなおす byteArray = s.getBytes(); x = new BigInteger(byteArray);
デフォルトの文字エンコーディングが US-ASCII である Linux 環境で実行すると、文字列 s は {?J?? となる。これは表示可能でない文字が含まれているためである。これを BigInteger に変換しなおすと、149830058370101340468658109 となる。
適合コード
以下の適合コードでは、まず BigInteger オブジェクトの String 表現を生成し、それから String オブジェクトをバイト配列に変換している。入力に対してはこの逆の処理が行われる。String オブジェクトのテキスト表現は BigInteger クラスによって生成されるため、有効な文字のみが含まれている。
BigInteger x = new BigInteger("530500452766"); String s = x.toString(); // 有効な文字データ try { byte[] byteArray = s.getBytes("UTF8"); // ns の中身は "530500452766" String ns = new String(byteArray, "UTF8"); // 元の BigInteger を作る BigInteger x1 = new BigInteger(ns); } catch (UnsupportedEncodingException ex) { // エラー処理 }
元の BigInteger を得ようとして String オブジェクトをバイト配列に変換してはいけない。変換して得られるバイト配列を BigInteger に変換すると、元とは異なった値になってしまう。
例外
FIO11-EX0: バイナリデータが文字データとして有効な値のみを含むのであれば、文字データとしての読み込みや文字列への変換を行ってもよい。このような処理をセキュアに行う方法については「IDS13-J. ファイル入出力やネットワーク入出力の両端で互換性のある文字エンコーディングを使う」を参照。 あわせて「IDS10-J. 一文字を構成するデータを分割しない」も参照。
リスク評価
バイナリデータを含むバイト配列を文字データとして読み込むと、予期せぬ結果を招く可能性がある。
ルール | 深刻度 | 可能性 | 修正コスト | 優先度 | レベル |
---|---|---|---|---|---|
FIO11-J | 低 | 低 | 中 | P2 | L3 |
参考文献
[API 2006] | Class String |
翻訳元
これは以下のページを翻訳したものです。
FIO11-J. Do not attempt to read raw binary data as character data (revision 59)