セキュリティ : PHP

Pocket

PHPのセキュリティメモ。

PHPのセキュリティ設定

PHPのセキュリティ対策は各種設定ファイルによる対策とPHPコードによる対策のがある。

  • 設定ファイルを使ったセキュリティ対策
    PHP設定ファイル(php.ini)やApache設定ファイル(httpd.conf), htaccessで行なう。phpinfo関数でPHPの設定を確認できる[1]
  • PHPコードでのセキュリティ対策(本記事の内容)。

PHPコードでのセキュリティ対策

Webプログラミングのセキュリティーの問題の多くは外部からのプログラム作成者の意図していない(悪意のある)リクエストから発生する。
    プログラム作成者は常に下記のような外部リクエストの値($value)に悪意のあるデータが含まれている可能性を考える必要がある。

$value = $_GET['key'];
$value = $_POST['key'];

外部リクエストの値には有害なデータが含まれる可能性を考えてデータを出力するときにHTMLエンティティへエスケープする。

セキュリティの簡単な例

----- HTML -----
<textarea name="msg"></textarea>

----- PHP -----
$msg = $_POST['msg'];
print($msg);

----- テキストエリアの入力 ---
<script type="text/javascript">window.loacation.href="http://www.example.com";</script>

上記はテキストエリアにJavascriptを記述して送信しPHPは外部リクエストをそのまま出力する。
その結果、出力ページにアクセスしたユーザーはwww.example.comへリダイレクトされる。

PHPの簡単なセキュリティ対策の実例

入力データをPHPで処理してHTML出力する過程で施すべき基本的なセキュリティ対策をまとめる。

  • 出力のさいに<>&”‘をhtmlspecialchars関数でHTMLエンティティへエスケープする。
  • URLを出力するさいはhttp://またはhttps://で始まるときだけ許可するホワイトリスト方式をとる。
  • SQLインジェクション対策
    プリペアードステートメント
  • セキュリティの前提知識

    Webプログラミングのセキュリティーで必要になる知識を簡単にまとめている。

    リクエスト変数

    外部リクエスト変数(GET,POST,COOKIE)にはクライアント・サイド・スクリプトを埋めこむことができる。
    同様に$_SERVER[‘PHP_SELF’]等の一部のSERVER変数にもクライアント・サイド・スクリプトを埋めこむことができる。
    セキュリティー対策をしないで外部リクエストをそのまま出力(表示)することはScript Insertionの危険性がある。

    クライアント・サイド・スクリプト

    クライアント・サイド・スクリプトというときJavaScriptを指す。対策もJavaScriptを念頭に置く。
    JavaScriptはURLの転送やクッキーの送信を行うことがでクライアント情報を不正に外部へ送信する危険がある。

    サニタイズ

    サニタイズはデータの無効化・無害化を意味する。代表的なサニタイズとしてHTMLサニタイズとSQLサニタイズがある。

    HTMLサニタイズ

    HTMLサニタイズとはHTMLで特別な意味をもつ<>&”‘をHTMLエンティティHTML><&などにに変換することである。

    SQLサニタイズ

    SQLサニタイズはSQL文で文字列の区切り文字として使われる'(シングルクウォート)や”(ダブルクウォート)を\でエスケープすることである[2]
    外部リクエストをSQL文として利用する場面で対策を行う。[追記 2012.11.01 現在はプリペアードステートメントを使う。

    Javascriptの記述位置

    HTMLファイルにJavascriptを記述する方法は大きく2種類ある。

    • HTMLファイルのhead部やbody部に<script>Javascriptコード</script>と記述する。
    • HTMLファイルでURLが記述可能な場所にjavascript:擬似スキームで記述する。
      <a href=”javascript : Javascriptコード”>リンク</a>

    悪意のあるJavascriptへの基本的的な対策は出力の際に適切にエスケープを行う。

    1. htmlspecialchars($value, ENT_QUOTES, ‘UTF-8’)で<>&”‘はエスケープされる。
    2. http://, https://で始まるかをチェックするホワイトリスト。
    preg_replace('/javascript/i','',preg_replace('/[x00-x20x22x27]/','',$url));

    preg_replaceはPerl互換の正規表現置換関数であり、正規表現の16進数表記は\xで始まる。
    \x00~\x20は正規表現の16進数表記で制御コード(\x00はヌルバイト)を表す。
    \x22は”(ダブルクウォート),\x27は'(シングルクウォート) を表す。

    ヌルバイト

    \x00や\0をヌルバイトと呼ぶ。PHPはヌルバイトを文字列の終端とみなさないバイナリセーフな関数と、文字列の終端とみなすバイナリセーフでない関数が存在する。
    ヌルバイト攻撃とはバイナリセーフな関数とバイナリーセーフでない関数がPHPで混在して存在することより発生する。

    PHPのダブルクウォート文字列での16進数表記は\xではじまる。
    ヌルバイト\x00や\0をURLエンコーディングすると%00になる。

    ホワイトリスト法

    ホワイトリスト法とは外部リクエスト変数チェックで、指定した値のみを許可する方法。ブラックリスト法よりも厳しいチェックになる。

    $list = array("a","A");
    $v = $_GET['alphabet'];
    if(!in_array($v,$list)) {
    	exit;
    }

    a,Aのみ許可する。

    ブラックリスト法

    ブラックリスト法とは外部リクエスト変数チェックで、指定した値のみ禁止する方法。ホワイトリストよりも緩やかなチェックになる。

    
    $list = array("a","A");
    $v = $_GET['alphabet'];
    if(in_array($v,$list)) {
    	exit;
    }

    a,Aのみ禁止する。

    公開ディレクトリと非公開ディレクトリ

    公開ディレクトリと非公開ディレクトリを明確に分ける必要がある。
    インターネットに直接公開する必要のないファイルは非公開ディレクトリへ配置する。
    詳しくはURL(Uniform Resource Locator) : HTTPを参照。

    HTTPリクエスト,HTTPレスポンス

    WebプログラミングではHTTPを理解しておくと良い。HTTPについての詳細はHTTPの基礎事項を参照。

    eval関数

    eval関数は引数に与えられた文字列をPHPコードとして実行する。外部リクエストを引数として利用するようなコードはユーザーにあらゆるPHPコードを実行される可能性がある。
    できるかぎりeval関数は利用しないほうが良い。

    セキュリティ関連の関数

    必要になる関数の一覧をまとめています。

    htmlspechialchars関数

    ENT_QUOTESが設定されている場合は、シングルクオートとダブルクオートが共に変換されます。ENT_NOQUOTESが設定されている場合は、シングルクオートとダブルクオートは共に変換されません。
    変換対象となる文字は以下の通りです。
    ‘&'(アンパサンド)は’&amp;’になります。
    ENT_NOQUOTESが設定されていない場合、’"'(ダブルクォート)は’&quot;”になります。
    ENT_QUOTESが設定されている場合のみ、”'(シングルクオート)は’&#039;’になります。
    ‘<‘(小なり)は’&lt;’になります。’>'(大なり)は’&gt;’になります。

    strip_tags関数
    第一引数で指定した文字列の中から、第二引数で指定したタグ以外のHTMLタグを取り除く。第二引数が省略された場合は全てのタグを取り除く。
    どのようなHTMLタグにもJavascriptが含まれる可能性があるためHTMLサニタイズはstrip_tags関数ではなくhtmlspechialchars関数を使う。
    addslashes関数
    ",’,\,ヌルバイト(\x00,\0)をエスケープする。
    eval関数
    引数(文字列)をPHPコードとして実行する。
    preg_replace関数

    Perl互換正規表現置換関数
    mixed preg_replace ( mixed pattern, mixed replacement, mixed subject [, int limit] )

    pattern : 正規表現パターン ex) ‘/\d{4}.\d{2}.\d{2}/’など
    replacement : 置き換える文字列 \\nまたは$nによってマッチした文字列を参照できる
    subject : 置換対象文字列
    ※正規表現に関しては本ブログのテーマ『正規表現』を参照

    正規表現パターンのオプション
    e : 置換後の文字列をプログラムコードとみなす。
    s : ドット(.)を改行ともマッチさせる。

    PHP公式マニュアル
    から引用
    $string = "April 15, 2003";
    $pattern = "/(\w+) (\d+), (\d+)/i";
    $replacement = "\${1}1,\$3";
    echo preg_replace($pattern, $replacement, $string);

    出力結果 April1,2003

    ※\${1}1や\$3の\はダブルクウォート文字列内で変数展開を防ぐため$をエスケープしている。

    usort関数
    コールバック関数。第1引数で指定された配列を第2引数で指定した関数名で定義された関数によってソートする。
    call_user_func
    第1引数で指定したユーザー関数を呼び出す。第2引数以降の引数は第1引数で指定された関数に渡される。
    passhru関数
    引数で指定されたコマンドを実行する。

    PHPのセキュリティー対策リンク集

    総合

    クロス・サイト・スクリプティング

    クロス・サイト・リクエスト・フォージェリ

    [1] php.ini・htaccessの主なセキュリティ項目。register_global, allow_url_fopen, session.use_trans_idなど
    [2] DBの文字リテラルはシングルクォーテーション(‘)またはダブルクォーテーション(“)で囲む。多くのDBはどちらを用いても良い。慣用的にシングルクォーテーションを使う場合が多い。

コメント

No comments yet.

コメントの投稿

改行と段落タグは自動で挿入されます。
メールアドレスは表示されません。