PHP
セキュリティ
NULL

バイナリセーフってなんだよ!?

PHPの本を読んでいたらバイナリセーフって単語が出てきてバイナリセーフなんだよ!? っとなりました。
よくわからないので自分なりに調べてみました。

バイナリセーフな関数

バイナリデータを正しく扱うことができる関数

バイナリセーフでない関数

バイナリデータを正しく扱うことができない関数

そもそもバイナリデータとは?

コンピュータが扱えるよう2進法に則って0と1の羅列(ビット列)として表現されたデータうち、テキスト(文字)形式ではない任意のデータ形式のこと。
http://e-words.jp/w/%E3%83%90%E3%82%A4%E3%83%8A%E3%83%AA.html より引用

結局、気をつけることは何?

バイナリセーフでない関数を使用するとNULLバイト攻撃にあう

Nullバイト攻撃とは?

nullバイト(「\0」、「\x00」などの終端文字とされている文字列)を含めることでセキュリティチェックをくぐり抜けてしまう。
ロケールに基づく文字列比較の関数(strcoll、strcmp)を使用して確認してみる。
返り値はstr1 が str2 よりも小さければ < 0 を、str1が str2よりも大きければ > 0 を、 等しければ 0 を返します。 ※strcmpの公式リファレンスより

サンプルコード

<?php

// ロケールを日本語にする
// ※strcollはロケールが C または POSIX の場合、strcmpと等価なのでロケールの設定をする
setlocale (LC_COLLATE, 'ja_JP.UTF-8');

// 現在のロケールを表示する
echo setlocale(LC_ALL, 0) . PHP_EOL . PHP_EOL;

// 比較対象の文字列をセットする
$str1 = 'こんにちわ\x00ゴリラくん';
$str2 = 'こんにちわゴリラくん';

// strcoll ※バイナリセーフでない関数を使用
// 結果として、「2147483647」を返す(str1の方が大きいと判断している)
echo 'strcoll:' . strcoll($str1, $str2);

echo PHP_EOL;

// strcmp ※バイナリセーフな関数を使用
// 結果として、「-1」を返す(str2の方が大きいと判断している)
echo 'strcmp:' . strcmp($str1, $str2);

出力結果

LC_COLLATE=ja_JP.UTF-8;LC_CTYPE=Japanese_Japan.932;LC_MONETARY=C;LC_NUMERIC=C;LC_TIME=C

strcoll:2147483647
strcmp:-1

strcollの時は「\x00」が終末文字として認識されないため、str1が大きいと判断されるがstrcmpの時は「\x00」が終末文字として認識されるため、str2の方が大きいと判断される

気をつけないとNULLバイト攻撃された時にプログラムが意図しない挙動をしそうです。

上記コードはここにあります

参考サイト