はじめに
今回は、ブラウザに情報を保管するクッキーと、クライアントとの連続した接続を確保するセッションについて、その働きと使い方を学習します。また、ある程度プログラムが作れるようになってきたら、サイト攻撃への対応についても考えなければいけません。最も基本とも言えるXSS攻撃関係の対応について簡単にまとめておきましょう。
過去の記事
対象読者
- Javaの基本(文法全般および基本的なクラスライブラリの使い方程度)をマスターしている人。
- サーバサイド(JSP、サーブレット)について基礎から勉強したい人。
- Eclipse WTPを使った開発に興味がある人。
セッションとは何か?
前回までで、フォームを使ったデータのやり取りの基本は大体頭に入ったことと思います。その中で、「セッション」というものを利用して情報を受け渡す手法があることを説明しました。このセッションとは、一体ナニモノでしょうか?
セッションは、「クライアント=サーバ間の連続した接続を確保するために考え出されたもの」です。一般に、ネットワーク関係ではサーバと接続を確立してから接続解除するまでの一連の流れを「セッション」と呼びます。
が、考えてみると、Webの世界でこうした「常に特定のクライアントとの接続が確保されている」というのは不思議です。Webに、いつからそんな機能が追加されたんでしょうか? Webには、サーバとクライアントの間の接続を常に保ち続ける機能など本来ありません。要求を送信すると、毎回新たに接続がされ、やり取りが終わると解除されます。クライアントがサーバとの接続を保ち続けることはできないのです。
このセッションというもの、種を明かせば「クライアントとサーバで相手を確認するための情報を保管し、毎回接続されるごとにそれをチェックする」ということで常に接続を保ち続けている「ふり」をしていたのです。つまり、実際には接続は保たれていないのだけど、毎回保管された情報をチェックし、「あ、これは前回アクセスしてきたのと同じクライアントだ」ということが分かったら、その続きをする、というようになっていたのです。
このセッションの利用方法としては、前回説明したようにgetAttribute
/setAttribute
を使って値を保管し受け渡すということが基本となります。この他、セッションに関する情報や操作を行うものとして、次のようなメソッドが暗黙オブジェクトsession
に用意されています。
- getId()
- setMaxInactiveInterval(int seconds)
- getMaxInactiveInterval()
- getCreationTime()
- getLastAccessedTime()
- invalidate()
setMaxInactiveInterval
は、タイムアウトまでの秒数を設定する。引数は秒数を示すint値。またgetMaxInactiveInterval
は現在のタイムアウトまでの秒数をint値で返す。setAttribute
で保管された情報は消滅する。セッションによるログイン処理
このセッションをよく使うのが、ログインしてページアクセスする処理でしょう。特定のメンバーだけが利用できるサイトなどでは、最初にIDとパスワードを入力してログインした者だけがページにアクセスできるようになっています。こうしたログインシステムは、セッションを利用すると比較的簡単に作ることができます。
考え方としては、次のようになります。――最初にログインページを用意し、そこからIDとパスワードを送信します。そこで送られたIDとパスワードが間違っていないかチェックし、正しければ、ログインしたことを示す情報をセッションに保管します。それぞれのページでは、最初にこの情報をチェックして、ログインしていなかったら別のページ(エラーページやログインページなど)にリダイレクトします。
ここでは、次のような形でページを作成し、簡単なログインシステムを動かしてみます。
- index.jsp
- index_action.jsp
- page.jsp
今回の例では、ログインページと、送信された情報を元に処理をするページを分けています。前回までのように1つのファイルで処理することもできますが、分かりやすくするためにこのようにしてあります。では各ファイルを作成し、以下に掲載するリストに従って記述をしていきましょう。
<%@ page language="java" contentType="text/html; charset=windows-31j" pageEncoding="windows-31j"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html;
charset=windows-31j"> <title>JSP SAMPLE</title> </head> <body> <% request.setCharacterEncoding("windows-31j"); if (session.getAttribute("login") != null && !session.getAttribute("login").equals("true")) out.println("※ログインに失敗しました。"); %> <form method="post" action="./index_action.jsp"> <table> <tr> <td>ID:</td><td><input type="text" name="id"></td> </tr><tr> <td>PASS:</td><td><input type="password" name="pass"></td> </tr><tr> <td></td><td><input type="submit"></td> </tr> </table> </form> </body> </html>
<%@ page language="java" contentType="text/html; charset=windows-31j" pageEncoding="windows-31j"%> <% String id_str = "code"; String pass_str = "zine"; request.setCharacterEncoding("windows-31j"); String id = request.getParameter("id"); id = id == null ? "" : id; String pass = request.getParameter("pass"); pass = pass == null ? "" : pass; if (id.equals(id_str) && pass.equals(pass_str)){ session.setMaxInactiveInterval(60 * 10); session.setAttribute("login","true"); pageContext.forward("./page.jsp"); } else { session.setAttribute("login","false"); pageContext.forward("./index.jsp"); } %>
<%@ page language="java" contentType="text/html; charset=windows-31j" pageEncoding="windows-31j"%> <% request.setCharacterEncoding("windows-31j"); String login = (String)session.getAttribute("login"); if (login == null || !login.equals("true")){ pageContext.forward("./index.jsp"); } %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html;
charset=windows-31j"> <title>PAGE</title> </head> <body> ※これは、ログインすると表示されるページです。 </body> </html>