Java/ServletとJSESSIONIDのURL管理 でServletコンテナでのJSESSIONIDのURL管理について調べました。今回はPHPの"session.use_only_cookies"と"session.use_trans_sid"の組み合わせについて、セッション固定化の問題に対する影響を調べてみました。
結論から言うと、やはり"session.use_only_cookies=Off"と"session.use_trans_sid=1"の組み合わせがもっとも影響度が大きいと思われます。一方で同じ"session.use_only_cookies=Off"でも、"session.use_trans_sid=0"であれば影響は限定的と思われます。
Win7 SP1 日本語 32bit PHP 5.2.14 (古くてすみません・・・)
今回使ったサンプルコード:t01.php
ini_set("display_errors", 1); ini_set("session.use_only_cookies", 0); ini_set("session.use_trans_sid", 0); session_name("trans_sid_test"); session_start(); if (!isset($_SESSION['c1'])) { $_SESSION['c1'] = 0; } $_SESSION['c1']++; <html> <body> <h2>$_COOKIE</h2> <pre> var_export($_COOKIE); </pre> <h2>$_SESSION</h2> <pre> var_export($_SESSION); </pre> <h2>session_id() = echo session_id(); </h2> <hr> <a href="./t01.php">a link</a><br> <form action="./t01.php" method="POST"> <input type="text" name="dummy1" value="v1"> <input type="submit" value="POST"> </form> <form action="./t01.php" method="GET"> <input type="text" name="dummy1" value="v2"> <input type="submit" value="GET"> </form> </body> </html>
ini_set("session.use_only_cookies", 0); ini_set("session.use_trans_sid", 0);
の部分を書き換えて組み合わせを試しました。
最初に一番問題となりやすい組み合わせです。
一昔前のケータイサイトを作るときとかはこの設定が多かったように思います。Cookieに対応してなくて、GETメソッドでリンクを作らざるをえないとなると、自前で特殊な管理を行わない限りはこの設定になってしまいます。
ini_set("session.use_only_cookies", 0); ini_set("session.use_trans_sid", 1);
初回アクセス:ブラウザにはCookieはセットされていないので、送られていない。
[request]: GET /webtoys/phpsessid/trans_sid/t01.php HTTP/1.1 Host: localhost User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:13.0) Gecko/20100101 Firefox/13.0.1 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: ja,en-us;q=0.7,en;q=0.3 Accept-Encoding: gzip, deflate Proxy-Connection: keep-alive [response]: HTTP/1.1 200 OK Date: Sun, 24 Jun 2012 09:01:56 GMT Server: Apache Set-Cookie: trans_sid_test=9hkr08m2hlvgjv3e0eupsmsc30; path=/ Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 Pragma: no-cache Content-Length: 692 Content-Type: text/html; charset=EUC-JP <html> <body> <h2>$_COOKIE</h2> <pre> array ( )</pre> <h2>$_SESSION</h2> <pre> array ( 'c1' => 1, )</pre> <h2>session_id() = 9hkr08m2hlvgjv3e0eupsmsc30</h2> <hr> <a href="./t01.php?trans_sid_test=9hkr08m2hlvgjv3e0eupsmsc30">a link</a><br> <form action="./t01.php" method="POST"><input type="hidden" name="trans_sid_test" value="9hkr08m2hlvgjv3e0eupsmsc30" /> <input type="text" name="dummy1" value="v1"> <input type="submit" value="POST"> </form> <form action="./t01.php" method="GET"><input type="hidden" name="trans_sid_test" value="9hkr08m2hlvgjv3e0eupsmsc30" /> <input type="text" name="dummy1" value="v2"> <input type="submit" value="GET"> </form> </body> </html>
ここで"<a>"リンクをクリックします。
[request]: GET /webtoys/phpsessid/trans_sid/t01.php?trans_sid_test=9hkr08m2hlvgjv3e0eupsmsc30 HTTP/1.1 Host: localhost User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:13.0) Gecko/20100101 Firefox/13.0.1 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: ja,en-us;q=0.7,en;q=0.3 Accept-Encoding: gzip, deflate Proxy-Connection: keep-alive Referer: http://localhost/webtoys/phpsessid/trans_sid/t01.php [response]: HTTP/1.1 200 OK Date: Sun, 24 Jun 2012 09:02:00 GMT Server: Apache Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 Pragma: no-cache Content-Length: 692 Content-Type: text/html; charset=EUC-JP <html> <body> <h2>$_COOKIE</h2> <pre> array ( )</pre> <h2>$_SESSION</h2> <pre> array ( 'c1' => 2, )</pre> <h2>session_id() = 9hkr08m2hlvgjv3e0eupsmsc30</h2> <hr> <a href="./t01.php?trans_sid_test=9hkr08m2hlvgjv3e0eupsmsc30">a link</a><br> <form action="./t01.php" method="POST"><input type="hidden" name="trans_sid_test" value="9hkr08m2hlvgjv3e0eupsmsc30" /> <input type="text" name="dummy1" value="v1"> <input type="submit" value="POST"> </form> <form action="./t01.php" method="GET"><input type="hidden" name="trans_sid_test" value="9hkr08m2hlvgjv3e0eupsmsc30" /> <input type="text" name="dummy1" value="v2"> <input type="submit" value="GET"> </form> </body> </html>
[request]: GET /webtoys/phpsessid/trans_sid/t01.php?trans_sid_test=9hkr08m2hlvgjv3e0eupsmsc30 HTTP/1.1 Host: localhost User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:13.0) Gecko/20100101 Firefox/13.0.1 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: ja,en-us;q=0.7,en;q=0.3 Accept-Encoding: gzip, deflate Proxy-Connection: keep-alive Referer: http://localhost/webtoys/phpsessid/trans_sid/t01.php?trans_sid_test=9hkr08m2hlvgjv3e0eupsmsc30 Cookie: trans_sid_test=9hkr08m2hlvgjv3e0eupsmsc30 [response]: HTTP/1.1 200 OK Date: Sun, 24 Jun 2012 09:05:38 GMT Server: Apache Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 Pragma: no-cache Content-Length: 542 Content-Type: text/html; charset=EUC-JP <html> <body> <h2>$_COOKIE</h2> <pre> array ( 'trans_sid_test' => '9hkr08m2hlvgjv3e0eupsmsc30', )</pre> <h2>$_SESSION</h2> <pre> array ( 'c1' => 4, )</pre> <h2>session_id() = 9hkr08m2hlvgjv3e0eupsmsc30</h2> <hr> <a href="./t01.php">a link</a><br> <form action="./t01.php" method="POST"> <input type="text" name="dummy1" value="v1"> <input type="submit" value="POST"> </form> <form action="./t01.php" method="GET"> <input type="text" name="dummy1" value="v2"> <input type="submit" value="GET"> </form> </body> </html>
攻撃者が準備したCookie:1
[request]: GET /webtoys/phpsessid/trans_sid/t01.php?trans_sid_test=1 HTTP/1.1 Host: localhost User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:13.0) Gecko/20100101 Firefox/13.0.1 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: ja,en-us;q=0.7,en;q=0.3 Accept-Encoding: gzip, deflate Proxy-Connection: keep-alive [response]: HTTP/1.1 200 OK Date: Sun, 24 Jun 2012 09:19:19 GMT Server: Apache Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 Pragma: no-cache Content-Length: 592 Content-Type: text/html; charset=EUC-JP <html> <body> <h2>$_COOKIE</h2> <pre> array ( )</pre> <h2>$_SESSION</h2> <pre> array ( 'c1' => 1, )</pre> <h2>session_id() = 1</h2> <hr> <a href="./t01.php?trans_sid_test=1">a link</a><br> <form action="./t01.php" method="POST"><input type="hidden" name="trans_sid_test" value="1" /> <input type="text" name="dummy1" value="v1"> <input type="submit" value="POST"> </form> <form action="./t01.php" method="GET"><input type="hidden" name="trans_sid_test" value="1" /> <input type="text" name="dummy1" value="v2"> <input type="submit" value="GET"> </form> </body> </html>
[request]: GET /webtoys/phpsessid/trans_sid/t01.php?trans_sid_test=1 HTTP/1.1 Host: localhost User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:13.0) Gecko/20100101 Firefox/13.0.1 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: ja,en-us;q=0.7,en;q=0.3 Accept-Encoding: gzip, deflate Proxy-Connection: keep-alive Cookie: trans_sid_test=1bseoje3qpd19n6f69ppfqrm40 [response]: HTTP/1.1 200 OK Date: Sun, 24 Jun 2012 09:25:24 GMT Server: Apache Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 Pragma: no-cache Content-Length: 542 Content-Type: text/html; charset=EUC-JP <html> <body> <h2>$_COOKIE</h2> <pre> array ( 'trans_sid_test' => '1bseoje3qpd19n6f69ppfqrm40', )</pre> <h2>$_SESSION</h2> <pre> array ( 'c1' => 4, )</pre> <h2>session_id() = 1bseoje3qpd19n6f69ppfqrm40</h2> <hr> <a href="./t01.php">a link</a><br> <form action="./t01.php" method="POST"> <input type="text" name="dummy1" value="v1"> <input type="submit" value="POST"> </form> <form action="./t01.php" method="GET"> <input type="text" name="dummy1" value="v2"> <input type="submit" value="GET"> </form> </body> </html>
次に、PHP5.2までの殆どの場合のデフォルト状態です。(PHP5.3.0以降はuse_only_cookiesがデフォルト1に)
ini_set("session.use_only_cookies", 0); ini_set("session.use_trans_sid", 0);
trans_sidが無効化されているので、注目するのはCookieとURLの両方で指定された場合の挙動になります。
[request]: GET /webtoys/phpsessid/trans_sid/t01.php?trans_sid_test=1 HTTP/1.1 Host: localhost User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:13.0) Gecko/20100101 Firefox/13.0.1 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: ja,en-us;q=0.7,en;q=0.3 Accept-Encoding: gzip, deflate Proxy-Connection: keep-alive Cache-Control: max-age=0 [response]: HTTP/1.1 200 OK Date: Sun, 24 Jun 2012 09:57:43 GMT Server: Apache Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 Pragma: no-cache Content-Length: 465 Content-Type: text/html; charset=EUC-JP <html> <body> <h2>$_COOKIE</h2> <pre> array ( )</pre> <h2>$_SESSION</h2> <pre> array ( 'c1' => 3, )</pre> <h2>session_id() = 1</h2> <hr> <a href="./t01.php">a link</a><br> <form action="./t01.php" method="POST"> <input type="text" name="dummy1" value="v1"> <input type="submit" value="POST"> </form> <form action="./t01.php" method="GET"> <input type="text" name="dummy1" value="v2"> <input type="submit" value="GET"> </form> </body> </html>
[request]: GET /webtoys/phpsessid/trans_sid/t01.php?trans_sid_test=1 HTTP/1.1 Host: localhost User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:13.0) Gecko/20100101 Firefox/13.0.1 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: ja,en-us;q=0.7,en;q=0.3 Accept-Encoding: gzip, deflate Proxy-Connection: keep-alive Cookie: trans_sid_test=v3s5g3q6hdd5g1rc17p3k32l60 [response]: HTTP/1.1 200 OK Date: Sun, 24 Jun 2012 09:57:11 GMT Server: Apache Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 Pragma: no-cache Content-Length: 542 Content-Type: text/html; charset=EUC-JP <html> <body> <h2>$_COOKIE</h2> <pre> array ( 'trans_sid_test' => 'v3s5g3q6hdd5g1rc17p3k32l60', )</pre> <h2>$_SESSION</h2> <pre> array ( 'c1' => 6, )</pre> <h2>session_id() = v3s5g3q6hdd5g1rc17p3k32l60</h2> <hr> <a href="./t01.php">a link</a><br> <form action="./t01.php" method="POST"> <input type="text" name="dummy1" value="v1"> <input type="submit" value="POST"> </form> <form action="./t01.php" method="GET"> <input type="text" name="dummy1" value="v2"> <input type="submit" value="GET"> </form> </body> </html>
サーバ側ではCookieで送信されてきたセッションIDのみを受け付けるため、URLセッション管理の問題を考える必要がありません。
ini_set("session.use_only_cookies", 1); ini_set("session.use_trans_sid", 0);
[request]: GET /webtoys/phpsessid/trans_sid/t01.php?trans_sid_test=1 HTTP/1.1 Host: localhost User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:13.0) Gecko/20100101 Firefox/13.0.1 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: ja,en-us;q=0.7,en;q=0.3 Accept-Encoding: gzip, deflate Proxy-Connection: keep-alive [response]: HTTP/1.1 200 OK Date: Sun, 24 Jun 2012 09:32:15 GMT Server: Apache Set-Cookie: trans_sid_test=dfqi0odg0gkuojrbai3qqvl104; path=/ Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 Pragma: no-cache Content-Length: 490 Content-Type: text/html; charset=EUC-JP <html> <body> <h2>$_COOKIE</h2> <pre> array ( )</pre> <h2>$_SESSION</h2> <pre> array ( 'c1' => 1, )</pre> <h2>session_id() = dfqi0odg0gkuojrbai3qqvl104</h2> <hr> <a href="./t01.php">a link</a><br> <form action="./t01.php" method="POST"> <input type="text" name="dummy1" value="v1"> <input type="submit" value="POST"> </form> <form action="./t01.php" method="GET"> <input type="text" name="dummy1" value="v2"> <input type="submit" value="GET"> </form> </body> </html>
[request]: GET /webtoys/phpsessid/trans_sid/t01.php?trans_sid_test=1 HTTP/1.1 Host: localhost User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:13.0) Gecko/20100101 Firefox/13.0.1 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: ja,en-us;q=0.7,en;q=0.3 Accept-Encoding: gzip, deflate Proxy-Connection: keep-alive Cookie: trans_sid_test=1bseoje3qpd19n6f69ppfqrm40 [response]: HTTP/1.1 200 OK Date: Sun, 24 Jun 2012 09:32:00 GMT Server: Apache Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 Pragma: no-cache Content-Length: 543 Content-Type: text/html; charset=EUC-JP <html> <body> <h2>$_COOKIE</h2> <pre> array ( 'trans_sid_test' => '1bseoje3qpd19n6f69ppfqrm40', )</pre> <h2>$_SESSION</h2> <pre> array ( 'c1' => 10, )</pre> <h2>session_id() = 1bseoje3qpd19n6f69ppfqrm40</h2> <hr> <a href="./t01.php">a link</a><br> <form action="./t01.php" method="POST"> <input type="text" name="dummy1" value="v1"> <input type="submit" value="POST"> </form> <form action="./t01.php" method="GET"> <input type="text" name="dummy1" value="v2"> <input type="submit" value="GET"> </form> </body> </html>
ini_set("session.use_only_cookies", 1); ini_set("session.use_trans_sid", 1);
エビデンスは"session.use_trans_sid=0"の時と全くおなじになりました。use_only_cookiesが有効ですとuse_trans_sidは強制的に無効になるのかもしれません。何れにしても、URLでセッションIDを指定しても無視される挙動は同じです。
外部の利用者が"use_trans_sid=1"であることを確かめるには、ブラウザの設定またはプロキシツールの設定でCookieを無効化してサイトにアクセスし、常にURLやPOSTパラメータでセッションIDをやり取りしていることを確認します。
セッション固定化の悪用への影響については、"use_trans_sid=0"の場合は低いと思われます。なぜなら、以下のように攻撃者がせっかくセッションIDを用意して被害者を誘導できたとしても、その先の本来の目的である被害者の操作とセッションIDの結びつけが出来ないと思われるからです。
スマホの台頭や、ガラパゴスケータイのブラウザでもCookieが利用可能なものが増えていると思いますので、新規にサイトを開発する場合や、既存のサイト改修でいい加減Cookie未対応のガラパゴスケータイを考慮しなくても良くなるのであれば、思い切って(?) "session.use_only_cookies=1" にすると安全だと思います。
コメント