#navi_header|Java| Servletプログラミングでセッションを使うとき、Cookieをクリアしたブラウザでアクセスすると初回のPOSTやGET遷移でだけ、URLに";jsessionid=xxxxyyyy..."というのが付加される。 以前から、これはServletコンテナが独自に実装してくれた機能なのか、Servletの仕様としてそうなっているのかが気になっていた。先日お仕事中にその辺りを調べる必要が生じたので、数年越しに自分の中でこの";jsessionid=xxxxyyyy..."について決着をつける。 #more|| #outline|| ---- * Servletの仕様を確認 JSESSIONIDや";jsessionid="がどこで定められているのかというと、Servletの仕様で定められています。 これらはJSRとして入手・参照可能です。 - JSR 53: JavaTM Servlet 2.3 and JavaServer PagesTM 1.2 Specifications -- http://jcp.org/en/jsr/detail?id=53 - JSR 154: JavaTM Servlet 2.4 Specification -- http://jcp.org/en/jsr/detail?id=154 -- Servlet 2.5はServlet 2.4のMaintenance Releaseとしてリリースされています。 - JSR 315: JavaTM Servlet 3.0 Specification -- http://jcp.org/en/jsr/detail?id=315 以下に簡単に主なバージョンとリリース年月についてまとめます。Version 2.3以降のリリース年月についてはJSR上での"Start"を元にしています。 | Version 1.0 | 1997-06 by Sun Microsystems | | Version 2.3 | 2001-09 Final Release Start, JSR53 (Java Community PRocess, with JSP 1.2 Specs) | | Version 2.4 | 2003-11 Final Release Start, JSR154 | | Version 2.5 | 2007-09 Maintenance Release 2 Start, JSR154 | | Version 3.0 | 2009-12 Final Release Start, JSR315 | ** Servlet 2.5 今回主に取り上げるTomcat6, Jetty7で対応しているServlet 2.5の仕様を確認すると、"SRV.7.1 Session Tracking Mechanisms"で以下のように記されています。 >SRV.7.1.1 Cookies > >Session tracking through HTTP cookies is the most used session tracking mechanism and is required to be supported by all servlet containers. >The container sends a cookie to the client. The client will then return the cookie on each subsequent request to the server, unambiguously associating the request with a session. The name of the session tracking cookie must be JSESSIONID. >(...) >SRV.7.1.3 URL Rewriting > >URL rewriting is the lowest common denominator of session tracking. When a client will not accept a cookie, URL rewriting may be used by the server as the basisfor session tracking. URL rewriting involves adding data, a session ID, to the URL path that is interpreted by the container to associate the request with a session. >The session ID must be encoded as a path parameter in the URL string. The name of the parameter must be jsessionid. Here is an example of a URL containing encoded path information: >http://www.myserver.com/catalog/index.html;jsessionid=1234 JSESSIONIDについては"must be"、つまりセッション維持のCookieの名前はJSESSIONID「でなければならない」となっています。また";jsessionid="についても"must be"で同様となっています。 もちろん後で確認するようにTomcatやJettyなど実際のServletコンテナでは、設定によってこれらを変更することも可能となっています。 クライアントがCookieを使えない場合ですが、"When a client will not accept a cookie, URL rewriting ''may be used'' by the server as the basisfor session tracking."とあります。ですので厳密にはURL Rewritingは使わなくても良いと考えられ、実際に後で確認するようにTomcat 6.0.30以上やJetty7ではURL Rewritingの無効化が設定可能です。 とはいえ、以下のようにCookieが使えないHTTPクライアントもサポートする必要があると定められていることからURL Rewritingによるセッション維持は必須の機能となっているようです。 >SRV.7.1.4 Session Integrity > >Web containers must be able to support the HTTP session while servicing HTTP requests from clients that do not support the use of cookies. To fulfill this requirement, Web containers commonly support the URL rewriting mechanism. ** Servlet 3.0 Servlet 3.0では、JSESSIONIDやURL Rewritingについて以下の変更がされています。 - JSESSIONIDという名前はカスタマイズOKになった。またカスタマイズした場合は";jsessionid="の部分もそれに合わせてOKになった。 - Cookie管理の場合は"HttpOnly"属性を設定可能なことが必須となった。 - URL RewritingについてはセッションIDの漏えいの可能性が生じること、可能であればCookieまたはSSLでのセッション維持を使うこと、という文章が追加された。 簡単に原文を紹介して終わりにします。 >7.1.1 Cookies > >Session tracking through HTTP cookies is the most used session tracking mechanism and is required to be supported by all servlet containers. >The container sends a cookie to the client. The client will then return the cookie on each subsequent request to the server, unambiguously associating the request with a session. The standard name of the session tracking cookie must be JSESSIONID, which must be supported by all 3.0 compliant containers. Containers may allow the name of the session tracking cookie to be customized through container specific configuration. >All servlet containers MUST provide an ability to configure whether or not the container marks the session tracking cookie as HttpOnly. The established configuration must apply to all contexts for which a context specific configuration has not been established (see SessionCookieConfig javadoc for more details). >If a web application configures a custom name for its session tracking cookies, the same custom name will also be used as the name of the URI parameter if the session id is encoded in the URL (provided that URL rewriting has been enabled). >(...) >7.1.3 URL Rewriting > >URL rewriting is the lowest common denominator of session tracking. When a client will not accept a cookie, URL rewriting may be used by the server as the basis for session tracking. URL rewriting involves adding data, a session ID, to the URL path that is interpreted by the container to associate the request with a session. >The session ID must be encoded as a path parameter in the URL string. The name of the parameter must be jsessionid. Here is an example of a URL containing encoded path information: >http://www.myserver.com/catalog/index.html;jsessionid=1234 >URL rewriting exposes session identifiers in logs, bookmarks, referer headers, cached HTML, and the URL bar. URL rewriting should not be used as a session tracking mechanism where cookies or SSL sessions are supported and suitable. * セッション固定化の問題と、URLからのセッションID漏えいの問題 URLでセッションIDを指定できる状態だと、セッション固定化の問題やURLからのセッションID漏えいの問題が発生します。 PC/スマホ向けのServletアプリは基本的にはCookieでセッションを管理していると思います。その場合、URLからのセッションID漏えいの問題の影響は無いと考えられます。 しかしServletの仕様によりURLからもセッションIDを受け入れてしまう状態であれば、セッション固定化の問題を考える必要があります。セッション固定化では攻撃者が用意したセッションIDを被害者に使わせ、被害者にログインさせるなどして攻撃者はセッション情報を入手しなりすまし等に悪用します。URLからセッションIDを指定できるということは、攻撃者が用意したセッションID付きのURLに被害者を誘導し、ログインなどの操作を行わせることが可能です。セッション固定化を悪用するための入り口の一つになってしまうことが考えられます。もちろん、セッション固定化の対策がきちんとされていれば、URLからセッションIDを指定できても問題にはつながらないと考えられます。 この点については最後のまとめで考えてみました。 * TomcatとJettyの場合 TomcatとJettyについて、Cookieを無効にした状態でアクセスし、初期状態でURL-Rewritingによるセッション管理が有効となるか確認してみます。 ** Tomcatの場合 今回はTomcat 6.0.35に含まれている"examples"アプリのSessionのサンプルを使って、JSESSIONIDや";jsessionid=" URL Rewritingの動作を確認してみました。 Tomcat6系はServlet 2.5を実装していますので、基本的にはJSESSIONID + ";jsessionid"によるURL Rewritingが有効化されています。しかし設定によりWebアプリごとにJSESSIONIDの名前を変更できます。また、 ''Tomcat 6.0.30 以上であれば、URL Rewritingを無効化したりすることが可能です。'' - http://tomcat.apache.org/tomcat-6.0-doc/changelog.html -- → Tomcat 6.0.30, Catalina, 49811: Add an option to disable URL rewriting on a per Context basis. (markt) -- 以下のBugzillaが6.0.30で組み込まれています: --- Bug 49811  [PATCH] Disable UrlRewriting --- https://issues.apache.org/bugzilla/show_bug.cgi?id=49811 *** JavaEEのバージョン/Servletバージョン/Tomcatバージョン JavaEE/Servlet/対応したTomcatのバージョンをまとめておきます。 | JavaEE6 | Servlet 3.0, JSP2.2 | Tomcat 7以上 | | JavaEE5 | Servlet 2.5, JSP 2.1 | Tomcat 6以上 | | J2EE 1.4 | Servlet 2.4, JSP 2.0 | Tomcat 5.x, 5.5.x以上 | | J2EE 1.3 | Servlet 2.3 JSP 1.2 | Tomcat 4.x | *** デフォルト状態 デフォルト状態では"examples"で特にsession関連の設定は行われておりません。Tomcatであれば"conf/Catalina//"以下の".xml"でWebアプリごとのコンテキスト設定を行えますが、デフォルトでは"examples"アプリ用の設定ファイルはありません。 この状態で、Burpを使って常にリクエストからCookieヘッダーを除去するようにしたProxyを通してアクセスします。 まずテストアプリのSessionサンプルは以下のURLでアクセスできました。 http://localhost:8080/examples/servlets/servlet/SessionExample すると以下の様なレスポンスを受信しました。 #pre||> HTTP/1.1 200 OK Server: Apache-Coyote/1.1 Set-Cookie: JSESSIONID=6B9DBEF80A2B62BC04E80FD73E7B14CA; Path=/examples Content-Type: text/html Content-Length: 1270 Date: Sun, 17 Jun 2012 09:03:22 GMT ...
||< JSESSIONID Cookieが発行され、また""のaction属性に";jsessionid="が埋め込まれていることが確認されます。 BurpによりブラウザからのCookieヘッダを削除した状態でそのままサンプルアプリを操作してみると、";jsessionid="だけで正常にサンプルアプリを操作できることが確認されました *** JSESSIONIDの変更とURL Rewritingの無効化 conf/Catalina/localhost/examples.xmlを以下の内容で保存します。 #pre||> ||< セッションのCookie名に"MYSESSID"を指定し、6.0.30以降で指定可能になった"disableURLRewriting"でURL Rewritingを無効化します。 Tomcatによりコンテキストがリロードされた後、以下のURLにアクセスしました。 http://localhost:8080/examples/servlets/servlet/SessionExample CookieもBurpにより削除され、URLにも指定されていないため以下のようなレスポンスを受信しました。 #pre||> HTTP/1.1 200 OK Server: Apache-Coyote/1.1 Set-Cookie: MYSESSID=3C117B729074A4EF6A3C38127E5E1D1E; Path=/examples; HttpOnly Content-Type: text/html Content-Length: 1138 Date: Sun, 17 Jun 2012 09:19:31 GMT ... ||< "Set-Cookie"で発行されるCookie名がXMLで指定した MYSESSID" になっています。また、先ほどと違い、""要素の"action"属性のURLに";jsessionid="がありません。 このままBurpによりCookieが削除される設定で操作をすると、毎回Set-Cookieされるため、セッション情報の変更などサンプルアプリの一部の機能が動かなくなりました。 なお"disableURLRewriting"はTomcat6系の、6.0.30以降でのみ使えます。Tomcat5系、Tomcat 6.0.29以前、Tomcat7系では使えません。Tomcat7系であればServlet 3.0に対応していますので、web.xmlによりCookieのみ+URL Rewriting無しを指定できます。 *** Tomcat全体でのセッションCookie名の変更 Javaのシステムプロパティを使うことで、Tomcat全体でセッションCookie名を変更できます。但しこれはアプリごとのContext設定を上書きしてしまいますので、実用上のメリットは薄いかもしれません。 - Apache Tomcat Configuration Reference (6.0.35) - System Properties -- http://tomcat.apache.org/tomcat-6.0-doc/config/systemprops.html - [Tomcat] How to change default JSESSIONID cookie/parameter identifier @Digizol -- http://www.digizol.org/2010/10/jsessionid-tomcat-cookie-change-default.html >Sessions > >org.apache.catalina.SESSION_COOKIE_NAME >An alternative name for the session cookie. Defaults to JSESSIONID. Note that the Servlet specification requires this to be JSESSIONID. You should not rely on being able to change this. > >org.apache.catalina.SESSION_PARAMETER_NAME >An alternative name for the session path parameter. Defaults to jsessionid. Note that the Servlet specification requires this to be jsessionid. You should not rely on being able to change this. *** Tomcat7, disableURLRewriting, Servlet 3.0 Tomcat7系ではServlet 3.0が実装されました。その結果、Servlet 3.0の仕様としてweb.xmlにセッション維持の方法を明示できるようになりました。その影響として、 ''disableURLRewritingは不要とされTomcat7のContext設定では実装されていません。'' Servlet 3.0ではセッション維持の方法にCookieのみを用いる場合、web.xmlに以下の記述を追加します。 COOKIE ""には他にも"URL"と"SSL"を組み合わせて指定可能なようです。 参考: - Servlet 3.0でのweb.xmlのxsd -- http://java.sun.com/xml/ns/javaee/web-common_3_0.xsd - Tomcat 7も対応したServlet 3.0の変更点 後編 (3/3) - @IT -- http://www.atmarkit.co.jp/fjava/rensai4/tomcat7_02/03.html - 感想: 体系的に学ぶ 安全なWebアプリケーションの作り方 - penultimate diary -- http://d.hatena.ne.jp/penult/20110606/1307374235 - What's New in Tomcat 7 | Andrius Miasnikovas's Blog -- http://andrius.miasnikovas.lt/2010/07/whats-new-in-tomcat-7/ - Servlet 3.0 ≪ JBoss -- http://middlewaremagic.com/jboss/?tag=servlet-3-0 *** JSESSIONIDと";jsessionid="のどちらが優先されるか。(Tomcat 6.0.35, Tomcat 7.0.16) 既にTomcat6.0系では検証記事がありますが、自分でも確認してみました。 - [Java][小ネタ] Cookie の JSESSIONID と URL の jsessionid= どちらが優先されるか。 -- http://d.hatena.ne.jp/tksmd/20090903 結果(Tomcat 6.0.35): |デフォルト状態:disableURLRewriting指定なし(=有効)|Cookie優先| |disableURLRewriting="true"|Cookie優先| 結果(Tomcat 7.0.16): |デフォルト状態:指定なし|Cookie優先| |COOKIEのみ指定|Cookie優先| リクエスト-レスポンス例(上記4パターン全てで同じ挙動): #pre||> [request] GET /examples/servlets/servlet/SessionExample;jsessionid=CA3FABDC2A12AF2CA7F33AEABF13280D HTTP/1.1 Host: localhost:8080 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: JSESSIONID=BFC3212F70EE1BB1D88B9AF9077FC0F7 ;;BFC3...が自分のブラウザに発行されたセッションID ;;CA3F...が別ブラウザに発行されたセッションID [response] HTTP/1.1 200 OK Server: Apache-Coyote/1.1 Content-Type: text/html Content-Length: 1170 Date: Sun, 17 Jun 2012 09:43:10 GMT ...

Sessions Example

Session ID: BFC3212F70EE1BB1D88B9AF9077FC0F7 ||< →";jsessionid="で指定されたセッションIDは無視され、Cookieで送信したセッションIDが使われていることが確認されました。 このように ''既にCookieがセットされた状態であれば'' URLではなくCookieの値をセッションIDとして使います。ではCookieが空、つまりそのサイトに初回アクセスしたり、ログアウトされてセッションがクリアされた状態で";jsessionid="付きのURLにアクセスするとどうなるかというと、URL Rewriting ON/OFFに応じて以下のようになります。 - Tomcat 6.0.35 -- URL Rewriting ON/OFF共: --- ";jsessionid="で指定された値がセッションIDとしてServlet側では使われます。 - Tomcat 7.0.16 -- 指定なし: --- ";jsessionid="で指定された値がセッションIDとしてServlet側では使われます。 -- COOKIEのみ指定: --- ";jsessionid="で指定された値は無視され、新たなセッションIDがSet-Cookieされます。 ''Tomcat 6.0.35では";jsessionid="指定されたCookieをそのまま受け入れてしまっています。'' これは、"disableURLRewriting"はあくまでも「URLのRewriting」の設定であってセッション維持の方法の指定ではない=";jsessionid="で指定された値が受け入れられる挙動には影響しない、ということが想像されます。 一方でTomcat7のServlet 3.0での""はURL Rewritingだけでなくセッション維持の方法そのものを指定しているため、COOKIEとした場合Cookieのみが受け入れられ、";jsessionid="の指定は無視されているということが想像されます。 ** Jettyの場合 今回は jetty-hightide-7.6.4.v20120524 を使って、Jettyに最初から含まれているtest.war中のSessionサンプルプログラムの動作を確認してみました。 - Jetty (web server) - Wikipedia, the free encyclopedia -- http://en.wikipedia.org/wiki/Jetty_(Web_server) Jetty-7系はServlet 2.5を実装していますので、基本的にはJSESSIONID + ";jsessionid"によるURL Rewritingが有効化されています。しかし設定によりWebアプリごとにJSESSIONIDの名前を変更できたり、URL Rewritingを無効化したりすることが可能です。 - Jetty/Howto/SessionIds - Eclipsepedia -- http://wiki.eclipse.org/Jetty/Howto/SessionIds *** デフォルト状態 contexts/test.xml ではデフォルトでは特にsession関連の設定は行われていません。以下がコメントアウトされているだけです。 この状態で、Burpを使って常にリクエストからCookieヘッダーを除去するようにしたProxyを通してアクセスします。 まずテストアプリのSessionサンプルは以下のURLでアクセスできました。 http://localhost:8080/test/session/ "No Session"と表示され、"New Session"というボタンが表示されているのでクリックすると以下のような302リダイレクトレスポンスを受信しました。 #pre||> HTTP/1.1 302 Found Date: Sun, 17 Jun 2012 07:43:15 GMT Set-Cookie: JSESSIONID=spzyfhy235vg562pm2yeydof;Path=/test Expires: Thu, 01 Jan 1970 00:00:00 GMT Location: http://localhost:8080/test/session/;jsessionid=spzyfhy235vg562pm2yeydof?R=1 Content-Length: 0 Server: Jetty(7.6.4.v20120524) ||< JSESSIONID Cookieが発行され、さらにLocationでは";jsessinid="によりURLでセッションIDを指定するURLにリダイレクトさせています。 ブラウザはLocationで指定されたURLに遷移しますが、この時、BurpによりCookieヘッダーを削除したリクエストがサーバに送信されました。 #pre||> GET /test/session/;jsessionid=spzyfhy235vg562pm2yeydof?R=1 HTTP/1.1 Host: localhost:8080 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:8080/test/session/ ||< その結果、レスポンスHTML中の""タグは以下のようにURL Rewritingされたaction属性がセットされました。

Session Dump Servlet:

ID: spzyfhy235vg562pm2yeydof
... そのままサンプルプログラムの機能としてセッションへのNameとValueペアの追加や更新、削除が正常に実行できました。 *** JSESSIONIDの変更とURL Rewritingの無効化 contexts/test.xmlに以下の設定を追加してみます。(上書き保存すると自動的にコンテキストがリロードされます) #pre||> ... MYSESSID none ... ||< sessionIdPathParameterName に "none" を指定することで、";jsessionid="のURL Rewritingが無効化されます。 コンテキストがリロードされた後、以下のURLにアクセスしました。 http://localhost:8080/test/session/ CookieはBurpにより削除され、URLにも指定されていないので、以下のような"No Session"レスポンスを受信しました。

Session Dump Servlet:

No Session

"New Session"ボタンをクリックすると、以下の302リダイレクトレスポンスを受信しました。 #pre||> HTTP/1.1 302 Found Date: Sun, 17 Jun 2012 07:56:52 GMT Set-Cookie: MYSESSID=1lj1lzunafwtim2g5gy0wsrkd;Path=/test Expires: Thu, 01 Jan 1970 00:00:00 GMT Location: http://localhost:8080/test/session/?R=0 Content-Length: 0 Server: Jetty(7.6.4.v20120524) ||< "Set-Cookie"で発行されるCookie名がXMLで指定した MYSESSID" になっています。また、先ほどと違い、Locationのりダイレクト先に";jsessionid="がありません。 ブラウザはLocationで指定されたURLに遷移しますが、途中のBurpによりCookieヘッダが削除されたリクエストがJettyに送信されました。その結果、セッションが無いものとServlet側では認識され、再度"No Session"レスポンスを受信しました。 *** JSESSIONIDと";jsessionid="のどちらが優先されるか。(jetty-hightide-7.6.4.v20120524) Tomcat6(Servlet 2.5)の比較としてjetty-hightide-7.6.4.v20120524について確認してみました。 先に結論ですが、jettyの場合は none を指定することでServlet側は";jsessionid="で指定された値を無視します。但しURL Rewriteについては";jsessionid="で指定された値が使われるため、CookieとURL Rewriteされる値がチグハグな状態になります。 1. jetty-hightide-7.6.4.v20120524, none 1-a. Cookie + ";jsessionid="両方を指定 #pre||> GET /test/session/;jsessionid=wzf5bjy9k3kxqjif7faaj172 HTTP/1.1 Host: localhost:8080 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: JSESSIONID=1xxlrptfiimi2iw5spo1kueas HTTP/1.1 200 OK Date: Sun, 17 Jun 2012 10:47:51 GMT Content-Type: text/html;charset=ISO-8859-1 Content-Length: 1068 Server: Jetty(7.6.4.v20120524)

Session Dump Servlet:

ID: 1xxlrptfiimi2iw5spo1kueas
... ||< →ServletにはCookieで送信した値が受け入れられているが、URL Rewritingで使われているのは";jsessionid="で指定した値。 1-b. Cookie削除, ";jsessionid="のみを指定 #pre||> GET /test/session/;jsessionid=wzf5bjy9k3kxqjif7faaj172 HTTP/1.1 Host: localhost:8080 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 HTTP/1.1 200 OK Date: Sun, 17 Jun 2012 10:48:08 GMT Content-Type: text/html;charset=ISO-8859-1 Content-Length: 193 Server: Jetty(7.6.4.v20120524)

Session Dump Servlet:

No Session

||< →"No Session"と判定されているが、""要素の"action"属性には";jsessionid="で指定した値でそのままURL RewriteされたURLが埋め込まれています。なお、このまま"New Session"をクリックすると以下のようになります(Burpにより強制的にCookieを削除して送っています): #pre||> POST /test/session/;jsessionid=wzf5bjy9k3kxqjif7faaj172 HTTP/1.1 Host: localhost:8080 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:8080/test/session/;jsessionid=wzf5bjy9k3kxqjif7faaj172?R=4 Content-Type: application/x-www-form-urlencoded Content-Length: 18 Action=New+Session HTTP/1.1 302 Found Date: Sun, 17 Jun 2012 10:53:24 GMT Set-Cookie: JSESSIONID=1c69qt9s3qjnr1s2s0ez300q;Path=/test Expires: Thu, 01 Jan 1970 00:00:00 GMT Location: http://localhost:8080/test/session/;jsessionid=wzf5bjy9k3kxqjif7faaj172?R=5 Content-Length: 0 Server: Jetty(7.6.4.v20120524) GET /test/session/;jsessionid=wzf5bjy9k3kxqjif7faaj172?R=5 HTTP/1.1 Host: localhost:8080 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:8080/test/session/;jsessionid=wzf5bjy9k3kxqjif7faaj172?R=4 HTTP/1.1 200 OK Date: Sun, 17 Jun 2012 10:53:25 GMT Content-Type: text/html;charset=ISO-8859-1 Content-Length: 193 Server: Jetty(7.6.4.v20120524)

Session Dump Servlet:

No Session

||< ここでCookieを有効にしてもう一度"New Session"をクリックします。 #pre||> HTTP/1.1 302 Found Date: Sun, 17 Jun 2012 10:53:53 GMT Set-Cookie: JSESSIONID=k2jt9gwim4t09qyip8hmbxu6;Path=/test Expires: Thu, 01 Jan 1970 00:00:00 GMT Location: http://localhost:8080/test/session/;jsessionid=wzf5bjy9k3kxqjif7faaj172?R=6 Content-Length: 0 Server: Jetty(7.6.4.v20120524) GET /test/session/;jsessionid=wzf5bjy9k3kxqjif7faaj172?R=6 HTTP/1.1 Host: localhost:8080 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:8080/test/session/;jsessionid=wzf5bjy9k3kxqjif7faaj172?R=5 Cookie: JSESSIONID=k2jt9gwim4t09qyip8hmbxu6 HTTP/1.1 200 OK Date: Sun, 17 Jun 2012 10:53:54 GMT Content-Type: text/html;charset=ISO-8859-1 Content-Length: 1043 Server: Jetty(7.6.4.v20120524)

Session Dump Servlet:

ID: k2jt9gwim4t09qyip8hmbxu6
... ||< 結論から言うと、Jetty7でnoneとした場合、URL Rewritingに使われるのは";jsessionid="で指定された値であるものの、実際にServletが処理で使っているのはCookieの値となります。 2. jetty-hightide-7.6.4.v20120524, デフォルト 2-a. Cookie + ";jsessionid="両方を指定 #pre||> GET /test/session/;jsessionid=ku2aqgtv6zefbk4on821ebaa HTTP/1.1 Host: localhost:8080 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: JSESSIONID=1hkvypdmvxe5wrmgbf8zz3fqz HTTP/1.1 200 OK Date: Sun, 17 Jun 2012 11:02:18 GMT Content-Type: text/html;charset=ISO-8859-1 Content-Length: 997 Server: Jetty(7.6.4.v20120524)

Session Dump Servlet:

ID: 1hkvypdmvxe5wrmgbf8zz3fqz
||< →";jsessionid="で指定した値は完全に無視され、""要素の"action"属性もURL Rewriteされていません。 2-b. Cookie削除, ";jsessionid="のみを指定 #pre||> GET /test/session/;jsessionid=ku2aqgtv6zefbk4on821ebaa HTTP/1.1 Host: localhost:8080 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 HTTP/1.1 200 OK Date: Sun, 17 Jun 2012 11:04:25 GMT Content-Type: text/html;charset=ISO-8859-1 Content-Length: 1070 Server: Jetty(7.6.4.v20120524)

Session Dump Servlet:

ID: ku2aqgtv6zefbk4on821ebaa
... ||< →Servlet側で";jsessionid="で指定された値を受け入れ、さらにURL Rewritingでも使っていることが確認されました。 * まとめ:ServletプログラミングでURLセッション管理を無効化するには - ''Servlet 3.0以上に対応したServletコンテナを使用するのが確実な方法と考えられます。'' - TomcatやJettyで確認したように、Servlet 2.5対応のServletコンテナにおいても URL Rewriting によるセッション維持を無効化できるよう独自に対応しているものがあります。 - 問題1:ブラウザの履歴やブックマーク、リンク等によるセッションIDの漏えい -- これを防ぐという目的においては、それらの独自対応により効果があると考えられます。 - 問題2:セッション固定化の問題で、攻撃者が用意したセッションを使わせるための誘導用URLに悪用される -- Cookieと";jsessionid="とで異なるセッションIDが指定された場合、少なくともTomcat6とJetty7においては、Cookieで指定された方をServlet側で取得できます。従って";jsessionid="によるセッション固定化の問題を考慮しなければならないのは、「対象サイトのCookieが空の状態の被害者が、攻撃者が用意した";jsessionid="付きURLに誘導された場合」であると考えられます。 -- Servlet2.5系までのコンテナによるURL Rewriting無効化独自対応については、それがURL Rewriting「だけ」を無効化するのか、";jsessionid="によるセッションIDの受け入れまで含めて無効化しているのかについてはServletコンテナにより異なるようです。 --- もしセッションIDの受け入れまで含めて無効化してくれるのであれば、「対象サイトのCookieが空の状態の被害者が、攻撃者が用意した";jsessionid="付きURLに誘導された場合」でも問題無いと考えることができそうです。 --- もし";jsessionid="については依然として受け入れてしまうのであれば、Cookie空状態での誘導ケースについては問題が残っていると考えることができそうです。 もし完全にセッションIDを制御下に置きたいのであれば、ServletコンテナすなわちServletの仕様で提供されているセッション機構を使うのでなく、独自のセッション管理機構を開発した方が良いのかもしれません・・・。 他、参考になったURL: - WEB開発メモ: 初回アクセス時のjsessionidを非表示にする -- http://buzzmemo.blogspot.jp/2010/03/jsessionid.html - 最初のアクセスで;jsessionidを表示させない方法 - ひがやすを blog -- http://d.hatena.ne.jp/higayasuo/20080724/1216889790 - strutsのjsessionid - ぐだぐだ日記 -- http://d.hatena.ne.jp/izuno4t/20041105/1099587280 - TomcatのJSESSIONIDに悩んだら -- http://neta.ywcafe.net/001172.html ---- あとがき: OWASPとかWASCも調べてみたんですが、Servletの";jsessionid="の記事が見つかりませんでした。Session管理系の話題でもスルーされているようです。 とまれ、数年来の疑問が解決しましたので気分的にはすっきりしました。 LL言語であれば変数のシリアライズが比較的簡単に出来るので、独自のセッション機構を開発するのは割りと敷居が低いのですが、Java Servletとなりますと、特にレプリケーションなどで複数インスタンス間で同期を取ることを考えるとJavaオブジェクトのSerializeをしなければなりませんので大変そうです。Servletコンテナの1インスタンス内で完結するのであれば他にやり用はあるかもしれませんが・・・。 #navi_footer|Java|