PHP を安全に使うため、気を付けるべきポイントについて書いています。
目次
- 1. ユーザーによる入力値の検証
- 2. クロスサイトスクリプティング(XSS)対策
- 3. SQLインジェクション対策
- 4. クロスサイトリクエストフォージェリ(CSRF)対策
- 5. OSコマンド・インジェクション対策
- 6. ディレクトリ・トラバーサル対策
- 7. 安全でないデシリアライゼーション (Insecure Deserialization) 対策
- 8. XML外部実体参照(XXE) 対策
- 9. メールヘッダインジェクション対策
- 10. HTTPヘッダ・インジェクション対策
- 11. オープン・リダイレクト対策
- 12. セッション管理の不備への対策
- 13. ファイルアップロード
- 14. パスワードの保存方法
- 15. アクセス制御や認可制御の欠落
- 16. PHPの設定値
- 17. WordPress
- 18. その他のメモ
- 19. 参考
- 関連
1. ユーザーによる入力値の検証
- mb_check_encoding関数で文字エンコーディングが正しいかチェックする。
- 制御文字を入力不可としてよい場合は、正規表現等でチェックする。
2. クロスサイトスクリプティング(XSS)対策
1) HTML テキストの入力を許可しない場合の対策
- 表示の際に文字列をHTMLエスケープすることを徹底する。
- 信頼できない値を出力する場所(コンテキスト)によって、エスケープ方法が異なる。
置かれている場所 説明 エスケープの概要 要素内容(通常のテキスト) タグと文字参照が解釈される。「<」で終端 「<」と「&」を文字参照に 属性値 文字参照が解釈される。引用符で終端 属性値を「”」で囲み、「<」と「”」と「&」を文字参照に 属性値(URL) 同上 URLの形式を検査してから属性値としてのエスケープ イベントハンドラ 同上 JavaScriptとしてエスケープしてから属性値としてのエスケープ script要素内の文字列リテラル タグも文字参照も解釈されない。「</」により終端 JavaScriptとしてのエスケープおよび「</」が出現しないよう考慮
要素内容(通常のテキスト)
このコンテキストの例
<div> ...ここに出力したい... </div>
エスケープ方法
htmlspecialchars($str, ENT_QUOTES, $charset)
- 第三引数をちゃんと指定すること。但し、PHP 5.6.0 以降では、デフォルト値として default_charset の値が使用される。
- 参考:PHP: htmlspecialchars – Manual
属性値
このコンテキストの例
<input id="foo" name="foo" value="...ここに出力したい... "/>
- 文字参照が解釈されることに注意する。
エスケープ方法
- 必ずダブルクォートで囲む。
- その上で以下のようにエスケープする。
htmlspecialchars($str, ENT_QUOTES, $charset)
属性値(URL)
href や src 属性に指定する値
このコンテキストの例
<a href="...ここに出力したい... "/>foo</a>
<iframe src="...ここに出力したい... "/>
- エスケープ処理と共に、ドメインのチェックも必要。
- 文字参照が解釈されることに注意する。
エスケープ方法
- URL Scheme をチェックする。
- 例えば、”http” or “https” or “/” が先頭にあればOKとする。
- URLの各パラメータ値に信用できない値を指定する場合は、この値の部分を URLエンコードする。
$param1 = rawurlencode($_POST['param1']); $url = "http://example.com/?param1=" . $params1;
- charset が UTF-8 や UTF-16 の場合は、この処理は必要ない。
- 参考
- HTML Standard – 4.6.2 Links created by a and area elements
- URL Standard – 4.3. URL writing
- valid URL string → (relative-URL-with-fragment string or an absolute-URL-with-fragment string) → URL-fragment string → URL units → (URL code points と percent-encoded bytes) と定義を辿っていける。
- Infra Standard – 4.3. Code points
A code point is a Unicode code point and is represented as a four-to-six digit hexadecimal number, typically prefixed with "U+".
- 参考
- charset が UTF-8 や UTF-16 の場合は、この処理は必要ない。
- 通常は
rawurlencode()
を使用する。- 過去の互換性を考慮する必要等がある場合にのみ、
urlencode()
の使用を検討する。 - 参照
- 過去の互換性を考慮する必要等がある場合にのみ、
- URL全体を以下のようにHTMLエスケープする。
$param1 = rawurlencode($_POST['param1']); $param2 = rawurlencode($_POST['param2']); $url = "http://example.com/?param1=" . $params1 . "¶m2=" . $param2; $url_escaped = htmlspecialchars($url, ENT_QUOTES, $charset); // この $url_escaped を href や src の値としてセットする。
- 属性値(URL)のエスケープで文字列はどう変化するか?の例を以下に示す。
// 以下のURLを aタグのsrc属性値に指定したい場合(ageパラメータ値はユーザーが指定したとする) $url = "http://www.example.com/?name=taro&age=<script>alert(1)"; // // まずユーザが入力したパラメータ値をrawurlencodeする。 // $url1 = "http://www.example.com/?name=taro&age=" . rawurlencode("<script>alert(1)"); // // 次のように、パーセントエンコーディングされる。 // ↓ // http://example.com/?name=taro&age=%3Cscript%3Ealert%281%29%3C%2Fscript%3E // 次にURL全体をHTMLエスケープする // $url2 = htmlspecialchars($url1, ENT_QUOTES, 'UTF-8'); // // すると、&が文字参照の&になる。これを aタグのsrc属性値として指定すれば良い。 // ↓ // http://example.com/?name=taro&age=%3Cscript%3Ealert%281%29%3C%2Fscript%3E
イベントハンドラ属性値
このコンテキストの例
<div >検知したら実行させない</div>
- 信頼できない値を出力するのは、クォートで囲まれた文字列リテラル内に限定する。それ以外は危険。
- 文字参照が解釈されることに注意する。
エスケープ方法
- JavaScriptの文字列リテラルにおいて、エスケープシーケンスでの表現が必要な文字はそれに従った記述を行う。
- 例えば、ダブルクォート文字やシングルクォート文字を表すには、その前にバックスラッシュを付加する必要がある。
- 参考:7 Lexical Conventions # Ⓣ Ⓔ ① Ⓐ — Annotated ES5
- HTMLエスケープする。
- 属性値としてダブルクォートで囲む
エスケープ方法(Unicodeエスケープを使う方法)
- 文字列リテラルに出力する値をエスケープする1つの方法は、英数文字以外を Unicodeエスケープしてしまうことである。
- この方法であれば、HTMLタグの文字列があったとしても、HTMLとして解釈されることはなく、あくまでJavaScriptの中でエスケープ前の文字列として使用されるだけになる。つまりこれだけやれば文字列を埋め込める。
JavaScriptの文字列リテラルを生成する関数の例
- 体系的に学ぶ 安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践 に掲載されていたスクリプトを少し変更してある。詳細はこちらの書籍を参考にして欲しい。
- JavaScriptのエスケープ方法が複雑なため、1つ1つきめ細かいエスケープをするのではなく、数値とアルファベット(と「-」、「.」も)以外はざっくりとUnicodeエスケープしている。
function escape_js_string($s) { return 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)); }, $s); }
scriptタグ内
このコンテキストの例
<script>var foo="...ここに出力したい... ";</script>
- 信頼できない値を出力するのは、クォートで囲まれた文字列リテラル内に限定する。それ以外は危険。
エスケープ方法
- JavaScriptの文字列リテラルにおいて、エスケープシーケンスでの表現が必要な文字はそれに従った記述を行う。
- 例えば、ダブルクォート文字やシングルクォート文字を表すには、その前にバックスラッシュを付加する必要がある。
- 参考:7 Lexical Conventions # Ⓣ Ⓔ ① Ⓐ — Annotated ES5
- HTMLエスケープする。
</script
がある場合は、<\/script
に変換する。
参考
エスケープ方法(Unicodeエスケープを使う方法)
- 文字列リテラルに出力する値をエスケープする1つの方法は、英数文字以外を Unicodeエスケープしてしまうことである。
- この方法であれば、
</
もエスケープされるのでスクリプトが終端される心配はないし、HTMLエスケープもする必要がない。 - 但し、この方法でエスケープした文字列を setAttributeメソッド等で、イベントハンドラ属性に指定すると JavaScriptコードとして実行されてしまうので注意する。(参考: DOM based XSS Prevention Cheat Sheet – OWASP)
- この方法であれば、
JavaScriptの文字列リテラルを生成する関数の例
- 「イベントハンドラ属性値のエスケープ」に書いたものと同様。
JavaScriptに値を渡す方法
- JavaScriptの文字列リテラルに値を直接埋め込むのではなく、間接的に値を渡す方が安全である。
データセット属性を使う方法
- HTMLタグの属性を
data-xxx="{{ 信用できない値 }}"
というように生成しておき、JavaScriptから取得させる。PHP側で値をセットする<div id="foo" data-bar="<?php echo htmlspecialchars($value, ENT_QUOTES, 'UTF-8'); ?>"/>
JavaScript側で値を取り出す
var value = document.querySelector('#foo').dataset.bar; // もしくは var value = document.querySelector('#foo').getAttribute('bar');
hiddenパラメータを使う方法
- inputタグのtype属性にhiddenを指定して値をセットし、JavaScriptから取得させる。PHP側で値をセットする
<input type="hidden" id="foo" value="<?php echo htmlspecialchars($value, ENT_QUOTES, 'UTF-8'); ?>"/>
JavaScript側で値を取り出す
var value = document.querySelector('#foo').value;
参考
2) HTML テキストの入力を許可する場合の対策
- HTMLの危険な記述部分を削除してくれるライブラリを使う。
3) 全てのウェブアプリケーションに共通の対策
- 文字コードの指定
- php.ini 内で
default_charset
を指定する。(これにより、HTTP レスポンスヘッダの Content-Type フィールドに文字コードがセットされる)php.inidefault_charset = "UTF-8"
- PHP 5.6.0 以降は “UTF-8” がデフォルトになっている。
- すべてのバージョンの PHP は、PHP から送信する Content-Type ヘッダのデフォルト値としてこの設定値を使う。(ただし、header() で上書きは可能)
- 参考:PHP: コア php.ini ディレクティブに関する説明 – Manual
- meta要素を記述する。HTMLファイルのヘッダ部分
<meta charset="UTF-8">
- php.ini 内で
- HTMLタグの属性値はダブルクォートで囲む
- セッションクッキーに HttpOnly属性を設定する。
ini_set('session.cookie_httponly', 1);
- HTTPレスポンスヘッダに「X-XSS-Protection」を設定して XSS攻撃を検知させる。
例
// 検知したら実行させない
header("X-XSS-Protection: 1; mode=block");
- HTTPレスポンスヘッダに「Content-Security-Policy」を設定する。
例
// JavaScriptの実行を許可する対象を 同一オリジンと code.jquery.com と maxcdn.bootstrapcdn.com に制限する
header("Content-Security-Policy: default-src 'self'; script-src 'self' code.jquery.com maxcdn.bootstrapcdn.com");
参考
- XSS (Cross Site Scripting) Prevention Cheat Sheet – OWASP
- DOM based XSS Prevention Cheat Sheet – OWASP
3. SQLインジェクション対策
- エンコーディングの指定
- プレースホルダの利用
- データベースに接続するユーザの権限を限定する。
PDOを使う場合
- DBへの接続と設定
$options = array( // 静的プレースホルダを指定 PDO::ATTR_EMULATE_PREPARES => false, // エラー発生時に例外を投げる PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION ); // 複文を禁止する (この定数は、PHPのバージョン 5.5.21 および PHP 5.6.5 以上で使用できる) if (defined('PDO::MYSQL_ATTR_MULTI_STATEMENTS')) { $options[PDO::MYSQL_ATTR_MULTI_STATEMENTS] = false; } try { // charset は set names でセットせず、この第1引数で指定すること(PHP5.3.6以降で可能) $db = new PDO('mysql:host=localhost;dbname=foo;charset=utf8', 'username', 'password', $options); } catch (PDOException $e) { // $e->getMessage() などでエラー情報を取得できる }
- 名前付けされたプレースホルダを用いてプリペアドステートメントを実行するコード例 (PHP: PDOStatement::bindValue – Manualから抜粋)
$calories = 150; $colour = 'red'; $sth = $dbh->prepare('SELECT name, colour, calories FROM fruit WHERE calories < :calories AND colour = :colour'); $sth->bindValue(':calories', $calories, PDO::PARAM_INT); $sth->bindValue(':colour', $colour, PDO::PARAM_STR); $sth->execute();
- ここでは、
$calories
と$colour
に直接値が代入されていますが、ユーザーの入力した値が代入された場合の危険性を考えて下さい。 bindValue()
メソッドの第三引数に、PDO::PARAM_*
定数で型を指定します。
- ここでは、
- 疑問符プレースホルダを用いてプリペアドステートメントを実行するコード例 (PHP: PDOStatement::bindValue – Manualから抜粋)
$calories = 150; $colour = 'red'; $sth = $dbh->prepare('SELECT name, colour, calories FROM fruit WHERE calories < ? AND colour = ?'); $sth->bindValue(1, $calories, PDO::PARAM_INT); $sth->bindValue(2, $colour, PDO::PARAM_STR); $sth->execute();
- ここでは、
$calories
と$colour
に直接値が代入されていますが、ユーザーの入力した値が代入された場合の危険性を考えて下さい。 bindValue()
メソッドの第三引数に、PDO::PARAM_*
定数で型を指定します。
- ここでは、
参考
- PHP: PDO – Manual
- PHP: 文字セット – Manual
- PHPでデータベースに接続するときのまとめ – Qiita
- php – PHPのsprintfによるSQL組み立てで脆弱性が生じる例 – スタック・オーバーフロー
- PHP: MySQL (PDO) – Manual
(仕方なく)生のSQL文を書く場合の例
- 信用できない値を埋め込む場合は、以下を参考にしてちゃんとエスケープ処理する。
エスケープ方法
- 整数リテラルには intval() 関数を通す。
- PDO::quote メソッドの第2引数に PDO::PARAM_INT を指定してエスケープすればよさそうだが、これには実は問題があるため使わない。(「参考」のリンク先を参照)
- 文字列リテラルは PDO::quote メソッドを使って引用符で囲む(引用符自体があればエスケープされる)。
- 他のデータベース抽象化ライブラリにも大抵は似たようなメソッドがある。
- データベース毎に用意されたエスケープ用関数(例えば MySQLなら mysqli_real_escape_string 関数)でもよい。
例
$item_id = intval($_POST["item_id"]); $name = $db->quote($_POST["name"], PDO::PARAM_STR); $result = $dbh->exec( "INSERT INTO items (item_id, name)". "VALUES($item_id, $name)");
参考
- 『最初に「読む」PHP』は全体的にとても良いが惜しい脆弱性がある – 徳丸浩の日記
- [Perl][PHP][SQL]: quoteメソッドの数値データ対応を検証する – 徳丸浩の日記(2009-10-19)
4. クロスサイトリクエストフォージェリ(CSRF)対策
- トークンを埋め込んで接続元を判定する。
- トークンの生成には、暗号論的擬似乱数生成器を使用する。
- PHP 7.0移行であれば、random_bytes 関数を使うと良い。
- 例:
$csrf_token = base64_encode(random_bytes(64));
- 例:
- PHP5.3.0以降であれば、openssl_random_pseudo_bytes 関数を使うとよい。
- PHP 5.x であれば、random_bytes 関数の代わりとして random_compat を使うと良い。
- PHP 7.0移行であれば、random_bytes 関数を使うと良い。
- ワンタイムトークンを使う必要はない。
5. OSコマンド・インジェクション対策
- なるべく、外部からのパラメータ値をOSコマンド(パラメータを含む)に使用しない。
- 外部からは番号等を指定させ、実際にコマンドに使用する文字列は予め用意された文字列を使用する。
- パラメータのエスケープには、escapeshellarg 関数を利用する。
6. ディレクトリ・トラバーサル対策
- できれば、ファイル名を外部から指定させない。
- basename() 関数を利用する。
- 但し、basename 関数はヌルバイトを削除しないので自分で削除する必要がある。もしくは、逆にホワイトリスト方式で許可する文字だけで構成されているかチェックする。
- また basename() は setlocale()がちゃんと設定されている必要がある。
注意:
basename() はロケールに依存します。 マルチバイト文字を含むパスで正しい結果を得るには、それと一致するロケールを setlocale() で設定しておかなければなりません。
7. 安全でないデシリアライゼーション (Insecure Deserialization) 対策
unserialize()
関数に、外部からの値を渡さない。- シリアル化したデータをユーザーに渡す必要がある場合は、安全で標準的なデータ交換フォーマットである JSON などを使う。(
json_decode()
およびjson_encode()
を利用する)
参考
- PHP: unserialize – Manual
- 注意点が記載されている。
- 安全でないデシリアライゼーション(Insecure Deserialization)入門 | 徳丸浩の日記
- 2017年9月25日
8. XML外部実体参照(XXE) 対策
- libxml2 を最新にする。
参考
- PHPプログラマのためのXXE入門 | 徳丸浩の日記
- 2017年12月25日
9. メールヘッダインジェクション対策
- できれば、外部からのパラメータ値をメールヘッダに埋め込まないようにする。
- 外部から指定するメールアドレスをバリデーションする。
- メールアドレスのバリデーション:PHP: 検証 – Manual
- 件名のバリデーション:「制御文字以外にマッチする」正規表現を利用する。
参考
- mb_send_mail(),mail()で第5引数を設定する際の注意点 – t_komuraの日記
10. HTTPヘッダ・インジェクション対策
- header関数を使えばよさそう。
- 但し、リダイレクトさせる場合はドメインをチェックする。
メモ
- PHP5.1.2から、header()関数は一度に複数のヘッダを送信できないようになった。 これは、ヘッダインジェクション攻撃への対策のためである。
- 参考
11. オープン・リダイレクト対策
リダイレクトには以下の3パターンがある。
- レスポンスヘッダ(“Location: URL”)でリダイレクトさせる例
header('Location: http://www.example.com/');
- <meta refresh>を使ってリダイレクトさせる例
<meta http-equiv="Refresh" content=0;URL=http://www.example.com/'">
- JavaScriptによるlocationオブジェクトへの代入によってリダイレクトさせる例
location.href = url_from_input;
対策
- リダイレクト先のURL文字列に、ユーザーの入力した値を直接使用しない作りにする。ユーザーの入力した値を基に、アプリケーション側で用意した文字列を選択して使用する。
- それができない場合
- URL Scheme をチェックする(http もしくは https のみ許可するなど)
- 許可されたドメインかどうかチェックする。
- <meta refresh> は危険なので使わないほうが良い。
参考
- HTML5時代の「新しいセキュリティ・エチケット」(4):これなら合格! 正しいリダイレクターの作り方 (1/3) – @IT
12. セッション管理の不備への対策
セッションフィクセーション
- ログイン時に、session_regenerate_id() 関数を実行してセッションIDを再生成する。
- ログアウト後に、session_destroy() 関数を実行してセッションに登録されたデータを全て破棄する。
13. ファイルアップロード
- アップロードされたファイルを公開ディレクトリに置かない。
- 画像を扱う場合、BMP形式はプログラムで扱い辛い面があるため対象外にしておくのが妥当である。
- IE7以前での画像XSS対策
- イメージファイトのまとめ: 画像ファイルによるクロスサイト・スクリプティング(XSS)傾向と対策 – 徳丸浩の日記(2007-12-10)
画像ファイルの判定について
- FileInfo の関数や、getimagesize関数で判定する。これらはマジックバイトでの判定であり、多少信頼性が低いので imagecreatefromstring 関数でイメージリソースが生成できるか確認しておくとよい。
- exif_imagetype関数でも画像の種類は判定はできるが、exif 拡張モジュールを必要とする。
渡されたファイル(ファイルパス)が画像ファイルであるかどうかをチェックする関数の例
- set_error_handler関数を使って、全てのエラーで ErrorExceptionクラスをスローしている環境を想定している。
- imagecreatefromstring関数は環境によって対応している画像フォーマットが違ってくるらしいので、対応している画像フォーマットのみに使用する。
/**
* @param String $filepath ファイルパス(拡張子は当てにしない)
* @return bool
*/
function isValidImageFile($filepath)
{
try {
// WARNING, NOTICE が発生する可能性あり
$img_info = getimagesize($filepath);
switch ($img_info[2]) {
case IMAGETYPE_GIF:
case IMAGETYPE_JPEG:
case IMAGETYPE_PNG:
// イメージリソースが生成できるかどうかでファイルの中身を判定する。
// データに問題がある場合、WARNING が発生する可能性あり
if (imagecreatefromstring(file_get_contents($filepath)) !== false) {
return true;
}
}
} catch (\ErrorException $e) {
// ログ出力する文字列の例
$err_msg = sprintf("%s(%d): %s (%d) filepath = %s",
__METHOD__, $e->getLine(), $e->getMessage(), $e->getCode(), $filepath);
// TODO:
// - $e->getSeverity() の値によって、ログ出力を変えたりする。
}
return false;
}
メモ
- JPEG, TIFF の場合は、EXIF情報を削除することも検討する。
参考
- PHP/Apache httpdのファイルアップロード/ダウンロード処理 – yohgaki’s blog
14. パスワードの保存方法
- PHP5.5以降が使える環境では password_hash関数を使う。(パスワードが保存されたハッシュ値にマッチするかどうか調べるには、 password_verify() を使う)
password_hash() 関数を使ったコードサンプル
POSTメソッドで送信されたパスワードをハッシュ化してセッション変数にセットする。
$_SESSION['password_hash'] = password_hash($_POST['password'], PASSWORD_DEFAULT);
POSTメソッドで送信されたパスワードと、セッション変数にセットされたハッシュ値とを照合する。
if (password_verify($_POST['password'], $_SESSION['password_hash'])) {
echo '正しいパスワードです!';
} else {
echo 'パスワードが間違っています';
}
15. アクセス制御や認可制御の欠落
- 権限情報はセッション変数に保持して、権限が必要な処理の直前で必要な権限をチェックする。
16. PHPの設定値
開発環境用の設定
display_errors = On
display_startup_errors = On
error_reporting = -1
log_errors = On
全てのエラーを表示する設定(PHPのバージョン毎)
< 5.3 -1 or E_ALL
5.3 -1 or E_ALL | E_STRICT
< 5.3 -1 or E_ALL
本番環境用の設定
display_errors = Off
display_startup_errors = Off
error_reporting = E_ALL
log_errors = On
17. WordPress
1. WordPress の各種エスケープ関数
esc_html()
- HTML ブロックをエスケープする。
- 参考
esc_attr()
- < > & ” ‘ (小なり、大なり、アンパサンド、ダブルクォート、シングルクォート) 文字参照をエンコードする。
- 参考
esc_js()
- シングルクォーテーション、HTMLの特殊文字、&、改行コードをエスケープする。
- 参考
sanitize_text_field()
- ユーザーが入力、またはデータベースから取得した文字列を無害化します。
- 無効な UTF-8 をチェックし、独立した ‘<‘ 文字をエンティティーへ変換し、タグをすべて除去し、改行・タブ・余分な空白を削除し、オクテット(’%’ に続く 2 桁の 16 進数)を除去します。
- 参考
など…
参考
2. WordPress のデータベース操作関数
データベースの操作を行う場合、基本的には以下の関数を使用する。
get_post()
- 投稿 ID で指定した投稿のレコードをデータベースから取得する。
- 参考
wp_insert_post()
- データベースへ投稿(および固定ページ)を追加する(無害化や値のチェック、デフォルト値の設定なども行う)。
- 参考
など…
3. $wpdb
オブジェクトを使って直接データベースを操作する場合
$wpdb
オブジェクトを使って直接データベースを操作する場合は、wpdb::prepare()
メソッドを利用してエスケープする。
参考
18. その他のメモ
- ereg()関数はバイナリセーフでない。このためPHP 5.3.0 で非推奨となった。
- アプリケーション開発者は Composer を使うことで、
require
/require_once
/include
/include_once
に起因するファイルインクルード攻撃についてはあまり心配しなくてよくなった(これらを直接使うことはなくなったので)。 - eval() 関数は使わない。
- 本記事では、IE7以前に実装されていた「CSS Expressions」機能については触れていない。
- 「外部からコントロールできる値をunserialize関数に処理させない」
19. 参考
- PHP: セキュリティ – Manual
- 体系的に学ぶ 安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践
- 安全なPHPアプリケーションの作り方2014
- 「10日でおぼえるPHP入門教室 第4版」はセキュリティ面で高評価 – 徳丸浩の日記」の内容
- PHP: The Right Way – Security
- PHP と Web アプリケーションのセキュリティについてのメモ
- OWASP Secure Coding Practices – Quick Reference Guide – yohgaki’s blog
- とにかく速いWordPress(19):「これだけ」はやっておこう──「WordPress実行環境とアプリ開発環境」のセキュリティ対策マニュアル (1/3) – @IT
関連
こちらの記事もご覧ください。