<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="rss.css" type="text/css"?>
<rdf:RDF xmlns="http://purl.org/rss/1.0/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:xhtml="http://www.w3.org/1999/xhtml" xml:lang="ja-JP">
	<channel rdf:about="http://www.tokumaru.org/d/index.rdf">
	<title>徳丸浩の日記</title>
	<link>http://www.tokumaru.org/d/</link>
	<xhtml:link rel="alternate" media="handheld" type="text/html" href="http://www.tokumaru.org/d/" />
	<description></description>
	<dc:creator>徳丸浩(ockeghem)</dc:creator>
	<dc:rights>Copyright 2010 徳丸浩(ockeghem) &lt;hiroshi2007 [at] tokumaru.org&gt;, copyright of comments by respective authors</dc:rights>
	<items><rdf:Seq>
<rdf:li rdf:resource="http://www.tokumaru.org/d/20100725.html#p01"/>
<rdf:li rdf:resource="http://www.tokumaru.org/d/20100701.html#p01"/>
<rdf:li rdf:resource="http://www.tokumaru.org/d/20100701.html#c07"/>
<rdf:li rdf:resource="http://www.tokumaru.org/d/20100701.html#c06"/>
<rdf:li rdf:resource="http://www.tokumaru.org/d/20100701.html#c05"/>
<rdf:li rdf:resource="http://www.tokumaru.org/d/20100701.html#c04"/>
<rdf:li rdf:resource="http://www.tokumaru.org/d/20100701.html#c03"/>
<rdf:li rdf:resource="http://www.tokumaru.org/d/20100701.html#c02"/>
<rdf:li rdf:resource="http://www.tokumaru.org/d/20100701.html#c01"/>
<rdf:li rdf:resource="http://www.tokumaru.org/d/20080601.html#c11"/>
<rdf:li rdf:resource="http://www.tokumaru.org/d/20080601.html#c10"/>
<rdf:li rdf:resource="http://www.tokumaru.org/d/20100118.html#c11"/>
<rdf:li rdf:resource="http://www.tokumaru.org/d/20100405.html#c03"/>
<rdf:li rdf:resource="http://www.tokumaru.org/d/20100406.html#p01"/>
<rdf:li rdf:resource="http://www.tokumaru.org/d/20100405.html#c02"/>
</rdf:Seq></items>
</channel>
<item rdf:about="http://www.tokumaru.org/d/20100725.html#p01">
<link>http://www.tokumaru.org/d/20100725.html#p01</link>
<xhtml:link rel="alternate" media="handheld" type="text/html" href="http://www.tokumaru.org/d/20100725.html#p01" />
<dc:date>2010-07-25T12:57:15+09:00</dc:date>
<title>ツッコミSPAM対策で、ツッコミ抜きのRSSフィードを用意しました</title>
<dc:creator>徳丸浩(ockeghem)</dc:creator>
<description>昨日17:47から19:13にかけて、大量のツッコミSPAMが来ています。取り急ぎ、ツッコミの一日あたりの上限数を0にすることにより、対応しましたが、フィードで日記をご覧いただいてる方々には、見苦しいものをお見せして申し訳ございません。 ツッコミ対策は色々工夫してはおりますが、まだ決定的なものはない状態で、時々このような事態となっております。 当面の問題として、RSSフィードがSPAMだらけになることが問題ですので、ツッコミを含まないRSSフィードも生成する設定にいたしました。ツッコミがうざいと思われる方は、恐れ入りますが、以下のURLから再設定いただけるとよろしいかと思います。 http://www.tokumaru.org/d/no_comments.rdf no_comments.rdfの方は当面試験運用といたします。不具合などありましたら、ツッコミなどでお知らせください。</description>
<content:encoded><![CDATA[<h3>ツッコミSPAM対策で、ツッコミ抜きのRSSフィードを用意しました</h3><p>
<p>昨日17:47から19:13にかけて、大量のツッコミSPAMが来ています。取り急ぎ、ツッコミの一日あたりの上限数を0にすることにより、対応しましたが、フィードで日記をご覧いただいてる方々には、見苦しいものをお見せして申し訳ございません。</p>
<p>ツッコミ対策は色々工夫してはおりますが、まだ決定的なものはない状態で、時々このような事態となっております。</p>
<p>当面の問題として、RSSフィードがSPAMだらけになることが問題ですので、<a href="http://www.tokumaru.org/d/no_comments.rdf">ツッコミを含まないRSSフィード</a>も生成する設定にいたしました。ツッコミがうざいと思われる方は、恐れ入りますが、以下のURLから再設定いただけるとよろしいかと思います。</p>
<p><a href="http://www.tokumaru.org/d/no_comments.rdf">http://www.tokumaru.org/d/no_comments.rdf</a></p>
<p>no_comments.rdfの方は当面試験運用といたします。不具合などありましたら、ツッコミなどでお知らせください。</p>

</p>

<p><a href="http://www.tokumaru.org/d/20100725.html#c">ツッコミを入れる</a></p>]]></content:encoded>
</item>
<item rdf:about="http://www.tokumaru.org/d/20100701.html#p01">
<link>http://www.tokumaru.org/d/20100701.html#p01</link>
<xhtml:link rel="alternate" media="handheld" type="text/html" href="http://www.tokumaru.org/d/20100701.html#p01" />
<dc:date>2010-07-01T22:17:15+09:00</dc:date>
<title>ぼくがPDOを採用しなかったわけ(Shift_JISによるSQLインジェクション)</title>
<dc:creator>徳丸浩(ockeghem)</dc:creator>
<description>PHPのデータベース・アクセス・ライブラリPDOは、DB接続時の文字エンコーディング指定ができないため、文字エンコーディングの選択によっては、プレースホルダを使っていてもSQLインジェクション脆弱性が発生します。 はじめに 本を書いています。SQLインジェクションの節から書き始めて、初稿はレビュアーの方々にお送りしましたところ、さっそく有意義なコメントを多数頂戴しています。ありがとうございます。 その原稿の中で、DBアクセスに使用するPHPのライブラリとしてMDB2を紹介していたところ、PDOを紹介すべきではという意見を複数頂戴しました。そこで、現時点でPDOを採用していない理由を報告したいと思います。これは、「安全なSQLの呼び出し方」でPDOを取り上げていない理由でもあります。 PDOは接続時に文字エンコーディングを指定できない（指定しても無視される）ので、データベースへの接続時の文字エンコーディングはLatin1が暗黙に指定されます。すると、日本語の読み書きで文字化けが生じるため、「SET NAMES SJIS」により、文字エンコーディングを接続後に指定するようなプログラミン..</description>
<content:encoded><![CDATA[<h3>ぼくがPDOを採用しなかったわけ(Shift_JISによるSQLインジェクション)</h3><p>
<p>PHPのデータベース・アクセス・ライブラリPDOは、DB接続時の文字エンコーディング指定ができないため、文字エンコーディングの選択によっては、プレースホルダを使っていてもSQLインジェクション脆弱性が発生します。</p>
<h4>はじめに</h4>
<p>本を書いています。SQLインジェクションの節から書き始めて、初稿はレビュアーの方々にお送りしましたところ、さっそく有意義なコメントを多数頂戴しています。ありがとうございます。</p>
<p>その原稿の中で、DBアクセスに使用するPHPのライブラリとしてMDB2を紹介していたところ、PDOを紹介すべきではという意見を複数頂戴しました。そこで、現時点でPDOを採用していない理由を報告したいと思います。これは、「<a href="http://www.ipa.go.jp/security/vuln/websecurity.html">安全なSQLの呼び出し方</a>」でPDOを取り上げていない理由でもあります。</p>
<p>PDOは接続時に文字エンコーディングを指定できない（指定しても無視される）ので、データベースへの接続時の文字エンコーディングはLatin1が暗黙に指定されます。すると、日本語の読み書きで文字化けが生じるため、「SET NAMES SJIS」により、文字エンコーディングを接続後に指定するようなプログラミングがなされているようです（MySQLの場合）。</p>
<p>そのようなプログラム例を示します。このプログラムでは、内部文字エンコーディングとしてShift_JISを利用しているという想定です。PHP5.3.0とMySQL5.1.37の組み合わせで確認しました。</p>
<pre>
&lt;?php
  $dbh = new PDO('mysql:host=localhost;dbname=test;charset=sjis', 'username', 'password');
  $dbh->query("SET NAMES sjis");
  $sth = $dbh->prepare("select * from test WHERE name=?");
  $sth->setFetchMode(PDO::FETCH_NUM);
  $name = ...
  $sth->execute(array($name));
  while ($data = $sth->fetch()) {
    var_dump($data);
  }
</pre>
<p>PDO+MySQLの場合、プレースホルダは「動的プレースホルダ」あるいは、俗に「クライアントサイドのプリペアードステートメント」などと呼ばれる実装になっています<span class="footnote">*1</span>。</p>
<p>このため、$nameとして「ソ' OR 1=1#」という文字列を指定した場合、MySQLに対して以下のようなクエリが送信されます（Wiresharkによるダンプ）。</p><BR/>
<img src="/img/PDO-MYSQL.png">
<p>0x83は「ソ」の先頭バイトです。これをPDOではLatin1(ISO-8859-1)として扱うので、0x83はNBHという制御文字を意味し、1バイト文字になります。PDOは、続く「\'」を「\\\'」とエスケープします。</p>
<p>一方、MySQLサーバー側では、受け取ったSQLをShift_JISと想定しているので「ソ\\'」という並びと解釈します。「\\」は「\」をエスケープしたものなので、後続の「'」は文字列リテラルの終端に使われ、残りの「 OR 1=1#'」はSQL文の一部とみなされます。SQL文が注入できたので、SQLインジェクション脆弱性があるということになります。ここまでの説明を下図にまとめました。</p><br/>
<img src="/img/pdo-sjis-escape.png">
<h4>my.cnfの修正でもダメ</h4>
<p>「set names」がセキュリティ上問題があることが広く知られるようになったせいか、PDOの文字化けを別の方法で対処するようにすすめているエントリもあります。たとえば<a href="http://yuubiseiharukana.blog.shinobi.jp/Entry/77/">このエントリ</a>では、my.cnf(my.ini)の修正でPDOの文字化けに対応しているのですが、Shift_JISを使う場合はこれもダメです<span class="footnote">*2</span>。その理由は、「PDOはLatin1として処理したものを、MySQLはShift_JISとして解釈する」状態には変わらないからです。</p>
<h4>まとめ</h4>
<ul>
<li>PDO+MySQLでは、動的プレースホルダ（なんちゃってプリペアード・ステートメント）が使われる
<li>PDOでは文字エンコーディングが指定できない
<li>PDO+MySQL+Shift_JISでは、プレースホルダを使ってもSQLインジェクション脆弱性となる
</ul>
<h4>解決策・回避策</h4>
<p>PDOの文字化け問題とSQLインジェクション脆弱性問題を解決するにはどうすればよいでしょうか。私が思いつくのは以下の2つの方法です。</p>
<OL>
<LI>PDOではなくMDB2など文字エンコーディングを正しく扱えるライブラリを使用する(根本的対策)
<LI>アプリケーションからDBまで一貫してUTF-8で処理し、set names utf8により文字化けを回避する(回避策)
</OL>
<p>2.で具体的な問題が起こるかどうかは分かりませんが、文字エンコーディングを正しく扱えないことで潜在的なリスクがあると考えます。そのため、書いている本の中では1.を採用したという訳です。</p>
<p>しかし、私自身PHPを熟知しているわけではないので、ひょっとすると、PDOの使い方などでもっとよい方法があるかもしれません。識者のご指摘をいただければ幸いです。</p>
<h4>追記(2010/07/01 21:30)</h4>
<p><a href="http://d.hatena.ne.jp/nihen/">id:nihen</a>さんが、PDOに対して文字エンコーディングを設定する方法を調べてくださいました。nihenさん、どうもありがとうございます。以下に引用します。</p>
<pre>
PDOからよばれるreal_escape_stringで文字コードを考慮させたい場合は
$dbh = new PDO('mysql:host=localhost;dbname=sandbox;charset=cp932', 'sandbox', 'sandbox', array(
    PDO::MYSQL_ATTR_READ_DEFAULT_FILE => '/etc/mysql/my.cnf',
    PDO::MYSQL_ATTR_READ_DEFAULT_GROUP => 'client',
));

もしくはserver-side-prepareを使う場合(文字コード気にしなくておｋ)

$dbh = new PDO('mysql:host=localhost;dbname=sandbox;charset=cp932', 'sandbox', 'sandbox', array(
    PDO::ATTR_EMULATE_PREPARES => false,
));

ちなむと前者は接続時に使われるオプションなのでnew PDOしたあとにあとから
$dbh->setAttribute
しても、ダメ。後者はおｋ。
</pre>
<div align="right"><a hre="http://gist.github.com/459499"><a href="gist:">gist:</a> 459499 - GitHub</a>より引用</div>
<p>ご覧のように、MySQLサーバーへの接続時に、MySQL APIに渡すパラメータとして、my.cnfのファイル名を指定しています。上記の例ではGROUPを「client」に設定していますので、my.cnfに以下の設定を追加することになります。</p>
<pre>
[client]
default-character-set=sjis
</pre>
<p>ただし、Windows版のPHPでは、PDO::MYSQL_ATTR_READ_DEFAULT_FILEが使えないようです。このため、サーバー接続時に文字エンコーディングを指定する方法がありません。このため、Windows版のPHPを使う場合は、PDO::ATTR_EMULATE_PREPARESをfalseにする(真のプリペアード・ステートメントを使う)ことで対策することになります。</p>


</p>
<div class="footnote">
	<p class="footnote">*1&#160;高木浩光氏のいわれる「<a href="http://www.atmarkit.co.jp/fsecurity/column/ueno/60.html">なんちゃってプリペアド・ステートメント</a>」</p>
	<p class="footnote">*2&#160;元エントリはUTF-8なので問題はおきませんが、逆に言えば、set names utf8でも問題ないことになります</p>
</div>

<p><a href="http://www.tokumaru.org/d/20100701.html#c">ツッコミを入れる</a></p>]]></content:encoded>
</item>
<item rdf:about="http://www.tokumaru.org/d/20100701.html#c07">
<link>http://www.tokumaru.org/d/20100701.html#c07</link>
<dc:date>2010-07-01T19:41:12+09:00</dc:date>
<title>2010-07-01のツッコミ[7] (carrot)</title>
<dc:creator>carrot</dc:creator>
<description>PHP5.2.1から、PDO_MYSQLは、デフォルトではクライアントサイドのプリペアードステートメントになったようですね。  http://www.php.net/releases/5_2_1.php に PDO_MySQL now uses buffered queries by default and emulates prepared statements to bypass limitations of MySQL's prepared statement API. とあります。  プリペアードステートメントだと、MySQLのクエリキャッシュが効かないためのようです。  こちらに動作検証された方がいらっしゃいます。 http://d.hatena.ne.jp/do_aki/20100221/1266746673  </description>
<content:encoded><![CDATA[PHP5.2.1から、PDO_MYSQLは、デフォルトではクライアントサイドのプリペアードステートメントになったようですね。<br><br><a href="http://www.php.net/releases/5_2_1.php">http://www.php.net/releases/5_2_1.php</a> に<br>PDO_MySQL now uses buffered queries by default and emulates prepared statements to bypass limitations of MySQL's prepared statement API.<br>とあります。<br><br>プリペアードステートメントだと、MySQLのクエリキャッシュが効かないためのようです。<br><br>こちらに動作検証された方がいらっしゃいます。<br><a href="http://d.hatena.ne.jp/do_aki/20100221/1266746673">http://d.hatena.ne.jp/do_aki/20100221/1266746673</a><br><br>]]></content:encoded>
</item>
<item rdf:about="http://www.tokumaru.org/d/20100701.html#c06">
<link>http://www.tokumaru.org/d/20100701.html#c06</link>
<dc:date>2010-07-01T18:37:21+09:00</dc:date>
<title>2010-07-01のツッコミ[6] (bero)</title>
<dc:creator>bero</dc:creator>
<description>上記mysql-&gt;libmysql  ドキュメントにも書いてた http://php.net/manual/ja/ref.pdo-mysql.php &gt; PDO_MYSQL は、MySQL 4.1 以降に存在するプリペアドステートメントを ネイティブにサポートしているという利点があります。 古いバージョンの mysql クライアントライブラリを使用している場合は、 PDO がこの機能をエミュレートします。 </description>
<content:encoded><![CDATA[上記mysql-&gt;libmysql<br><br>ドキュメントにも書いてた<br><a href="http://php.net/manual/ja/ref.pdo-mysql.php">http://php.net/manual/ja/ref.pdo-mysql.php</a><br>&gt; PDO_MYSQL は、MySQL 4.1 以降に存在するプリペアドステートメントを ネイティブにサポートしているという利点があります。 古いバージョンの mysql クライアントライブラリを使用している場合は、 PDO がこの機能をエミュレートします。<br>]]></content:encoded>
</item>
<item rdf:about="http://www.tokumaru.org/d/20100701.html#c05">
<link>http://www.tokumaru.org/d/20100701.html#c05</link>
<dc:date>2010-07-01T18:19:47+09:00</dc:date>
<title>2010-07-01のツッコミ[5] (bero)</title>
<dc:creator>bero</dc:creator>
<description>&gt; PDO+MySQLの場合、プレースホルダは「動的プレースホルダ」あるいは、俗に「クライアントサイドのプリペアードステートメント」などと呼ばれる実装になっています  mysqlがよほど古いバージョンでもなければサーバサイドのを使うと思うんですが  ext/pdo_mysql/mysql_statement.c #if HAVE_MYSQL_STMT_PREPARE ... mysql_stmt_bind_param(...)  php 5.1.6と5.3.1で確認 </description>
<content:encoded><![CDATA[&gt; PDO+MySQLの場合、プレースホルダは「動的プレースホルダ」あるいは、俗に「クライアントサイドのプリペアードステートメント」などと呼ばれる実装になっています<br><br>mysqlがよほど古いバージョンでもなければサーバサイドのを使うと思うんですが<br><br>ext/pdo_mysql/mysql_statement.c<br>#if HAVE_MYSQL_STMT_PREPARE<br>...<br>mysql_stmt_bind_param(...)<br><br>php 5.1.6と5.3.1で確認<br>]]></content:encoded>
</item>
<item rdf:about="http://www.tokumaru.org/d/20100701.html#c04">
<link>http://www.tokumaru.org/d/20100701.html#c04</link>
<dc:date>2010-07-01T15:09:56+09:00</dc:date>
<title>2010-07-01のツッコミ[4] (kanehama)</title>
<dc:creator>kanehama</dc:creator>
<description>徳丸浩さんありがとうございます。  確認してみると確かに書き込み/読み込みで文字化けていました。(確認が足りなくて申し訳ありません。。 読み書きを正しく処理できるようにMySQLの設定を変更すると 徳丸浩さんが書かれているようにSQLインジェクションが起きました!! # MySQLの文字コード関連の設定は下記のようになっています。 character_set_client sjis character_set_connection sjis character_set_database sjis character_set_filesystem binary character_set_results sjis character_set_server sjis character_set_system utf8    ただし、同じPHPソースを別環境で実行すると、SQLインジェクションは起きませんでした。 確認した組み合わせは PHP 5.2.3 と MySQL 5.0.37  # MySQLの文字コード設定は下記のようになっています。 ch..</description>
<content:encoded><![CDATA[徳丸浩さんありがとうございます。<br><br>確認してみると確かに書き込み/読み込みで文字化けていました。(確認が足りなくて申し訳ありません。。<br>読み書きを正しく処理できるようにMySQLの設定を変更すると<br>徳丸浩さんが書かれているようにSQLインジェクションが起きました!!<br># MySQLの文字コード関連の設定は下記のようになっています。<br>character_set_client sjis<br>character_set_connection sjis<br>character_set_database sjis<br>character_set_filesystem binary<br>character_set_results sjis<br>character_set_server sjis<br>character_set_system utf8<br><br><br><br>ただし、同じPHPソースを別環境で実行すると、SQLインジェクションは起きませんでした。<br>確認した組み合わせは PHP 5.2.3 と MySQL 5.0.37 <br># MySQLの文字コード設定は下記のようになっています。<br>character_set_client sjis<br>character_set_connection sjis<br>character_set_database sjis<br>character_set_filesystem binary<br>character_set_results sjis<br>character_set_server sjis<br>character_set_system utf8<br><br>PHP 5.3から何か変更あったのですかね。。<br>念のためあとでPHP 5.3.2が入ってる環境のPHPのバージョンを5.2.3に変えて確認してみます。<br><br><br>]]></content:encoded>
</item>
<item rdf:about="http://www.tokumaru.org/d/20100701.html#c03">
<link>http://www.tokumaru.org/d/20100701.html#c03</link>
<dc:date>2010-07-01T15:01:19+09:00</dc:date>
<title>2010-07-01のツッコミ[3] (心は萌え)</title>
<dc:creator>心は萌え</dc:creator>
<description>時間があったら試してみたいと思いますが　そもそもlatin1などがなぜ出てくるのでしょうか？ 日本語の場合はMysqlをビルドするときに--with-charset=で利用する文字コードをsjisなりutf8なりに固定したほうが良いのではないでしょうか？元々英語圏が基本でビルドされたmysqlを使っていませんか？</description>
<content:encoded><![CDATA[時間があったら試してみたいと思いますが　そもそもlatin1などがなぜ出てくるのでしょうか？<br>日本語の場合はMysqlをビルドするときに--with-charset=で利用する文字コードをsjisなりutf8なりに固定したほうが良いのではないでしょうか？元々英語圏が基本でビルドされたmysqlを使っていませんか？]]></content:encoded>
</item>
<item rdf:about="http://www.tokumaru.org/d/20100701.html#c02">
<link>http://www.tokumaru.org/d/20100701.html#c02</link>
<dc:date>2010-07-01T13:26:21+09:00</dc:date>
<title>2010-07-01のツッコミ[2] (徳丸浩)</title>
<dc:creator>徳丸浩</dc:creator>
<description>kanehamaさん、こんにちは 再現テストをしていただき、ありがとうございます。 当方では、SQLインジェクションとなるようです。 頂戴した結果ですが、  &gt; character_set_client latin1 &gt; character_set_connection latin1   この状態ですと、データベースの日本語に対して正常にアクセスできないのではないでしょうか。 当方の条件を変えて、上記エンコーディングをlatin1になるように調整すると、SQLインジェクションは出ない代わりに、日本語が文字化けします。 お手数ですが、いったんテーブルに格納した日本語が正常に読み書きできるかご確認いただけないでしょうか。 </description>
<content:encoded><![CDATA[kanehamaさん、こんにちは<br>再現テストをしていただき、ありがとうございます。<br>当方では、SQLインジェクションとなるようです。<br>頂戴した結果ですが、<br><br>&gt; character_set_client latin1<br>&gt; character_set_connection latin1 <br><br>この状態ですと、データベースの日本語に対して正常にアクセスできないのではないでしょうか。<br>当方の条件を変えて、上記エンコーディングをlatin1になるように調整すると、SQLインジェクションは出ない代わりに、日本語が文字化けします。<br>お手数ですが、いったんテーブルに格納した日本語が正常に読み書きできるかご確認いただけないでしょうか。<br>]]></content:encoded>
</item>
<item rdf:about="http://www.tokumaru.org/d/20100701.html#c01">
<link>http://www.tokumaru.org/d/20100701.html#c01</link>
<dc:date>2010-07-01T12:23:54+09:00</dc:date>
<title>2010-07-01のツッコミ[1] (kanehama)</title>
<dc:creator>kanehama</dc:creator>
<description>再現しなかったので、もう少し現象が再現できる設定を教えていただけると幸いです。  私は下記のような環境で試しました。  ■PHPソースコード(Shift_JIS) mb_internal_encoding('sjis'); echo mb_internal_encoding() . &quot;\n&quot;; $dbh = new PDO('mysql:host=localhost;dbname=test', 'root', '');  $sth = $dbh-&gt;prepare(&quot;SHOW VARIABLES LIKE 'char%'&quot;); $sth-&gt;setFetchMode(PDO::FETCH_NUM); $sth-&gt;execute(); while ($data = $sth-&gt;fetch()) {     echo $data[0] . ' ' . $data[1] . &quot;\n&quot;; }  $sth = $dbh-&gt;prepare(&quot;select ?&quot;); $sth-&gt;setFetchMode(PDO::FETCH_NUM); $name = urlde..</description>
<content:encoded><![CDATA[再現しなかったので、もう少し現象が再現できる設定を教えていただけると幸いです。<br><br>私は下記のような環境で試しました。<br><br>■PHPソースコード(Shift_JIS)<br>mb_internal_encoding('sjis');<br>echo mb_internal_encoding() . &quot;\n&quot;;<br>$dbh = new PDO('mysql:host=localhost;dbname=test', 'root', '');<br><br>$sth = $dbh-&gt;prepare(&quot;SHOW VARIABLES LIKE 'char%'&quot;);<br>$sth-&gt;setFetchMode(PDO::FETCH_NUM);<br>$sth-&gt;execute();<br>while ($data = $sth-&gt;fetch()) {<br>&#160;&#160;&#160;&#160;echo $data[0] . ' ' . $data[1] . &quot;\n&quot;;<br>}<br><br>$sth = $dbh-&gt;prepare(&quot;select ?&quot;);<br>$sth-&gt;setFetchMode(PDO::FETCH_NUM);<br>$name = urldecode(&quot;%83%5C'%20OR%201=1#&quot;); // ソ' OR 1=1#<br>$sth-&gt;execute(array($name));<br>while ($data = $sth-&gt;fetch()) { <br>&#160;&#160;&#160;&#160;var_dump($data);<br>} <br><br><br>■実行結果<br>SJIS<br>character_set_client latin1<br>character_set_connection latin1<br>character_set_database sjis<br>character_set_filesystem binary<br>character_set_results latin1<br>character_set_server sjis<br>character_set_system utf8<br>character_sets_dir /usr/local/mysql/share/mysql/charsets/<br>array(1) {<br>&#160;&#160;[0]=&gt;<br>&#160;&#160;string(11) &quot;ソ' OR 1=1#&quot;<br>}<br><br>■バージョン<br>　MySQL：5.1.34 <br>　PHP：5.3.2<br><br>ちなみにPHPのソースコード、内部エンコーディングなどはShift_JISで統一しています。<br>今回のSQLインジェクションが成功するのであれば<br>var_dumpの結果は「1」になる予定でSQLを変更しています。<br><br>よろしくお願いします。<br>]]></content:encoded>
</item>
<item rdf:about="http://www.tokumaru.org/d/20080601.html#c11">
<link>http://www.tokumaru.org/d/20080601.html#c11</link>
<dc:date>2010-05-27T14:08:45+09:00</dc:date>
<title>2008-06-01のツッコミ[11] (Nkzn)</title>
<dc:creator>Nkzn</dc:creator>
<description>↑セカンドオーダーSQLインジェクション？っていうんでしたっけ？</description>
<content:encoded><![CDATA[↑セカンドオーダーSQLインジェクション？っていうんでしたっけ？]]></content:encoded>
</item>
<item rdf:about="http://www.tokumaru.org/d/20080601.html#c10">
<link>http://www.tokumaru.org/d/20080601.html#c10</link>
<dc:date>2010-05-06T21:24:48+09:00</dc:date>
<title>2008-06-01のツッコミ[10] (momo)</title>
<dc:creator>momo</dc:creator>
<description>クオートをエスケープした内容をSQLに格納するのはいいが、次にDBからその内容を利用するとき、エスケープは消え、クオートは裸のままであることをおわすれなく。</description>
<content:encoded><![CDATA[クオートをエスケープした内容をSQLに格納するのはいいが、次にDBからその内容を利用するとき、エスケープは消え、クオートは裸のままであることをおわすれなく。]]></content:encoded>
</item>
<item rdf:about="http://www.tokumaru.org/d/20100118.html#c11">
<link>http://www.tokumaru.org/d/20100118.html#c11</link>
<dc:date>2010-04-15T15:56:48+09:00</dc:date>
<title>2010-01-18のツッコミ[11] (徳丸浩)</title>
<dc:creator>徳丸浩</dc:creator>
<description>コメントいただいた皆様、ありがとうございました。 さすがに、言語毎に方法はあるのですね。 ですが、あまり知られていない方法を使わないといけないこと、そのための説明などがドコモの解説などにないことから、やはりPOSTデータの扱いは「困難」だなと思います。 この問題は引き続きウォッチしたいと思います。ありがとうございました。</description>
<content:encoded><![CDATA[コメントいただいた皆様、ありがとうございました。<br>さすがに、言語毎に方法はあるのですね。<br>ですが、あまり知られていない方法を使わないといけないこと、そのための説明などがドコモの解説などにないことから、やはりPOSTデータの扱いは「困難」だなと思います。<br>この問題は引き続きウォッチしたいと思います。ありがとうございました。]]></content:encoded>
</item>
<item rdf:about="http://www.tokumaru.org/d/20100405.html#c03">
<link>http://www.tokumaru.org/d/20100405.html#c03</link>
<dc:date>2010-04-15T15:31:06+09:00</dc:date>
<title>2010-04-05のツッコミ[3] (徳丸浩)</title>
<dc:creator>徳丸浩</dc:creator>
<description>金床さん、コメントいただきありがとうございました。 sunのドキュメントはまだきちんと読めていないので、読ませて頂きたいと思います。 ただ、生Socketが使えるDNSリバインディングは、プラグイン側の問題として対処が進んでいるようですね。</description>
<content:encoded><![CDATA[金床さん、コメントいただきありがとうございました。<br>sunのドキュメントはまだきちんと読めていないので、読ませて頂きたいと思います。<br>ただ、生Socketが使えるDNSリバインディングは、プラグイン側の問題として対処が進んでいるようですね。]]></content:encoded>
</item>
<item rdf:about="http://www.tokumaru.org/d/20100406.html#p01">
<link>http://www.tokumaru.org/d/20100406.html#p01</link>
<xhtml:link rel="alternate" media="handheld" type="text/html" href="http://www.tokumaru.org/d/20100406.html#p01" />
<dc:date>2010-04-06T09:31:09+09:00</dc:date>
<title>PROXY（プロキシ）経由でのDNSリバインディングと対策</title>
<dc:creator>徳丸浩(ockeghem)</dc:creator>
<description>このエントリでは、PROXY経由でWebアクセスしている場合のDNSリバインディング対策について考察する。 PROXY（プロキシ）経由でWebアクセスしている場合、DNSによる名前解決はブラウザではなくPROXYにより行われる。したがって、	ブラウザ側ではDNS Pinningできないので、PROXY側での対策が重要になる。 広く使われているPROXYサーバーであるsquidの場合、DNS Pinningに相当するパラメータは、negative_dns_ttlであり、デフォルト値は1分間である。したがって、最初のアクセスから1分あけてXMLHttpRequestすれば、DNSリバインディングが成立する。これは実験で確認した。Internet ExplorerやOperaは、他のブラウザと比べてDNS Pinningがしっかりされている印象があるが、PROXY経由の場合は、これらブラウザでも比較的簡単にDNSリバインディングが成立するので注意が必要だ。 先のエントリで説明したように、JavaアプレットによるDNSリバインディングでも、URLクラスを使いかつPROXY経由でのアクセスの..</description>
<content:encoded><![CDATA[<h3>PROXY（プロキシ）経由でのDNSリバインディングと対策</h3><p>
<p>このエントリでは、PROXY経由でWebアクセスしている場合のDNSリバインディング対策について考察する。</p>
<p>PROXY（プロキシ）経由でWebアクセスしている場合、DNSによる名前解決はブラウザではなくPROXYにより行われる。したがって、	ブラウザ側ではDNS Pinningできないので、PROXY側での対策が重要になる。</p>
<p>広く使われているPROXYサーバーであるsquidの場合、DNS Pinningに相当するパラメータは、negative_dns_ttlであり、デフォルト値は1分間である。したがって、最初のアクセスから1分あけてXMLHttpRequestすれば、DNSリバインディングが成立する。これは実験で確認した。Internet ExplorerやOperaは、他のブラウザと比べてDNS Pinningがしっかりされている印象があるが、PROXY経由の場合は、これらブラウザでも比較的簡単にDNSリバインディングが成立するので注意が必要だ。</p>
<p><a href="http://www.tokumaru.org/d/20100405.html#p01">先のエントリ</a>で説明したように、JavaアプレットによるDNSリバインディングでも、URLクラスを使いかつPROXY経由でのアクセスの場合は、やはりPROXYでのDNS Pinningが問題となる。PROXY経由でのアクセスでは、Javaアプレットの場合でも、JavaScriptのXMLHttpRequestの場合同様、1分以上間隔をあけてやればDNS Rebindingが成立する。ただし、攻撃に使用できるプロトコルはHTTPのみであるので、JavaアプレットとJavaScriptでは、リスクは変わらない。</p>
<p>negative_dns_ttlの値を大きくすれば、squidがDNSキャッシュする最低時間を伸ばすことが可能だが、二つの点で問題がある。</p>
<p>第一の問題は、negative_dns_ttlを大きくすることの副作用だ。negative_dns_ttlは元々、DNSアクセスに失敗した場合のキャッシュ保持時間を意味するからだ。以下に、negative_dns_ttlのリファレンスを引用する。</p>
<blockquote cite="http://www.squid-cache.org/Doc/config/negative_dns_ttl/" title="squid : negative_dns_ttl configuration directive">
<p>Time-to-Live (TTL) for negative caching of failed DNS lookups. This also sets the lower cache limit on positive lookups. Minimum value is 1 second, and it is not recommendable to go much below 10 seconds.</p>

</blockquote>
<p class="source">[<cite><a href="http://www.squid-cache.org/Doc/config/negative_dns_ttl/" title="squid : negative_dns_ttl configuration directiveより引用">squid : negative_dns_ttl configuration directive</a></cite>より引用]</p>

<p>このため、一例として、negative_dns_ttlを6時間に設定した状態でDNS参照に失敗した場合（参照先DNSサーバーが一時的に停止した場合など）も6時間はDNSを再アクセスしない。すなわち、DNSのエラーが発生した場合は、negative_dns_ttlで設定した時間内は、当該サイトにアクセスできなくなるのだ。このため、negative_dns_ttlの値をあまり大きくすると、サイト閲覧に支障がでる可能性がある。</p>
<p>第二の問題は、negative_dns_ttlを長くしてもDNSリバインディングの根本対策にはならないことだ。
その背景には、PROXYサーバーをマルチユーザで使う場合が多いことや、タブブラウザの普及などがある。
やはりnegative_dns_ttlを6時間に設定した場合で説明しよう。AさんとBさんが同じPROXYサーバーを共有しているとする。Aさんが10:00にワナサイトにアクセスした場合、PROXYは16:00までワナサイトのIPアドレスをキャッシュする。したがって、Bさんが15:59にワナサイトを閲覧すると、そこから一分間でDNSキャッシュが無効になり、Bさんのブラウザ上動作するXMLHttpRequestがプライベートアドレスにアクセスすることを許してしまうかもしれない。
また、シングルユーザで考えても、タブブラウザのユーザはタブを開きっぱなしにする傾向があるので、6時間後の攻撃が成立する可能性はある。</p>
<h4>アクセス制御による対策</h4>
<p>結局negative_dns_ttlによる対策はうまくいかないので、別の方法を考える必要がある。有効な対策は、proxyのアクセス制御(ACL)により、squidにプライベートアドレスを中継させないことだ。以下に、192.168.0.0/16に対してアクセスを禁止する場合のsquid.confの設定例を示す。</p>
<pre>
acl localnet dst 192.168.0.0/16
http_access deny localnet
</pre>
<p>この場合、プライベートアドレスに対してはPROXY経由でアクセスできなくなるので、ブラウザのPROXY設定の例外設定をお忘れなく。下図に例外設定の例を示す。</p>
<img src="/img/IE-proxy-settings-x.png"><br clear=left>
<p>このACLによる対策の効果であるが、JavaScriptとJavaによるアクセスに関しては完全に対策できると考える。当初Javaアプレットが対策から漏れることを心配していたが、<a href="http://www.tokumaru.org/d/20100405.html#p01">先のエントリ</a>で検証したように問題ないことがわかった。Flashについては未検証なので今後検証したい…ところだが、私はFlashのコンテンツを書いたことがない。どなたか教えてください。</p>
<h4>まとめ</h4>
<p>PROXY経由でWebアクセスしている場合のDNSリバインディング対策について検討し、PROXYのACLによりプライベートアドレスを中継禁止することで対策可能であることを示した。DNSリバインディング対策のまとめについては別稿にて報告する。</p>

</p>

<p><a href="http://www.tokumaru.org/d/20100406.html#c">ツッコミを入れる</a></p>]]></content:encoded>
</item>
<item rdf:about="http://www.tokumaru.org/d/20100405.html#c02">
<link>http://www.tokumaru.org/d/20100405.html#c02</link>
<dc:date>2010-04-05T22:16:28+09:00</dc:date>
<title>2010-04-05のツッコミ[2] (金床)</title>
<dc:creator>金床</dc:creator>
<description>＞おそらく金床氏もupdate 3で対策されたとは明確には分からなかったのだろう。  いえいえ、ちゃんとわかってましたYo！当日のプレゼンでは口頭で説明しました。BHはプレゼン資料提出がかなり早いんで訂正できなかったんですよ。</description>
<content:encoded><![CDATA[＞おそらく金床氏もupdate 3で対策されたとは明確には分からなかったのだろう。<br><br>いえいえ、ちゃんとわかってましたYo！当日のプレゼンでは口頭で説明しました。BHはプレゼン資料提出がかなり早いんで訂正できなかったんですよ。]]></content:encoded>
</item>
</rdf:RDF>
