【初心者目線】Webアプリケーションの開発 第8回
【初心者目線】Webアプリケーションの開発 第8回を書きます。
1. HTTP通信の問題点
前回Webアプリケーション作成としてショッピングサイトを例としてログイン処理、リダイレクト処理を説明しましたが、今回のアプリケーションではログイン画面で正しいユーザIDとパスワードを入力することで、商品一覧画面を表示することができますがこれには大きな問題があります。
ログイン画面のURLにアクセスするとログイン画面が表示されますが、例えば商品一覧画面のURLに直接アクセスした場合も商品一覧画面が表示されてしまいます。
本来ログイン画面を介して表示される想定の画面が正しいルート以外でも閲覧できてしまうのです。
これはHTTP通信では以前の状態を保てないことが原因となっています。
※第8回の説明にあたり、引き続き第7回で掲載したショッピングサイトを例題として使用しています。
画面遷移図があると処理をイメージしやすい箇所もあるので、第7回も併用して読み進めてください。
1-1. ステートフルなプロトコル
まず初めにコマンドプロンプトを開き、以下の下線部のようにコマンドを入力してみてください。
以下のように表示されるので下線部の文字を順番(A~D)に入力してください。
今回「Anonymous FTPサーバ」と呼ばれる誰でも自由に匿名で使用出来るFTPサーバと手順を踏んだ対話(通信)ができることを確認しましたが。
対話を日本語で表すと以下のようになります。
FTPサーバ:こちらはAnonymous FTPサーバです。
ユーザ:ユーザ名anonymousでログインします。
FTPサーバ:それでは、パスワードとしてメールアドレスを入力してください。
ユーザ:webtext@になります。
FTPサーバ:匿名アクセスを承諾しました。
ユーザ:現在のディレクトリはどこですか。
FTPサーバ:あなたのディレクトリは「/(ルート)」になります。
ユーザ:終了します。
FTPサーバ:それでは。
ここまで手順を踏んだ対話をしてきましたが、ログインの手順を飛ばしてコマンドを実行するとどうなるでしょうか。
以下は実行結果になります。
PWDコマンドをログインせずにいきなり実行しても、下線部のように受け付けてもらえません。
これはFTPサーバが前回のリクエスト結果を保持していて、その情報を踏まえて次のリクエストを実行しているからです。
よって、ユーザ名とパスワードの情報をFTPサーバに渡すまでは次の手順に進めないのです。
このようにFTP通信はクライアントからのリクエストによってFTPサーバの状態が変化(直前までの情報を保持)するプロトコルであり、これを「ステートフルプロトコル」と呼びます。
1-2. ステートレスなプロトコル
HTTP通信の場合はFTP通信と比べ非常にシンプルな通信となります。
HTTPリクエストとして「ログインページのHTML」を要求した場合、HTTPサーバ側はすぐに該当するHTMLファイルを渡します。
FTP通信のように何度も通信せず1回のリクエストで通信が終了してしまうため「状態」の保持が必要ありません。これを「ステートレスプロトコル」と呼びます。
このようにHTTP通信は直前の状態を保持できないため、ログイン画面の介さなくてもログインが必要な画面を見ることができてしまうのです。
2. ログイン状態を保持するには
まず最初に考えられる方法として、GETリクエストのパラメータにログイン情報を付与しサーバへ渡す方法があります。
そしてgoods_list.phpの中でstatus_loginパラメータの状態を確認し、「ok」であれば商品一覧画面を表示すれば良いわけですが、結論から申し上げるとこの方法も大きな問題があり使用できません。
GETリクエストのパラメータにログイン状態を保持させるということは、パラメータの値を把握できることになります。そしてURLのパラメータですので容易に編集することが出来ます。
よって、このログイン状態の保持方法に気づいたユーザはパラメータの値を編集することにより、簡単にログイン認証を回避することができてしまいます。
ログイン状態の保持では不十分なので、ユーザIDとパスワードをパラメータとしてサーバに渡し、毎回アプリケーション側でログインチェックを実行するとします。
機密情報なのでPOSTリクエストでパラメータを渡すのですが、ここで別の問題が発生します。
POSTリクエストを送信する場合、フォームの利用が不可欠であるため遷移前のページに必ずフォームを設置する必要があり、アプリケーション作成としては手間がかかってしまいます。
2-1. Cookie(クッキー)の仕組み
この技術はHTTPの仕様を拡張し、WebブラウザとWebアプリケーションの間で情報の交換ができるようにしたものです。
それでは、ログイン認証が成功し商品一覧画面を表示する際のGETリクエストを確認してみましょう。
下線部に今までになかったCookieというヘッダが追加されています。
これがWebブラウザに状態を保持させる技術であるCookieであり、ここではユーザIDとパスワードが格納されていることが分かります。
Cookieには「パラメータ名=値」という組み合わせで情報が格納されており、WebサーバからCookieを受け取ったWebブラウザは、次回同じWebサーバにアクセスする際にCookie情報をHTTPリクエストヘッダにいれて送信します。
そしてアプリケーション側ではリクエストヘッダに格納されているCookieを確認することにより、アクセスしてきたクライアントの情報を知ることが出来ます。
上記の図はCookieの仕組みを簡単に表したものです。
この図からも読み取れるように、Webブラウザ側はCookieを受け取ったWebサーバ以外のサーバへはCookieを送信しません。
これは意図していない情報の誤送信を防ぐための仕組みです。
2-2. Cookie(クッキー)の使用方法
まず初めにログイン認証が終わりHTTPレスポンスが帰ってきた部分が、WebサーバからWebブラウザにCookieを送信している処理に当てはまります。
login.phpからのレスポンスについて、枠線部①の部分に「Set-Cookie」というヘッダが追加されていることが確認できます。
これは「user=tanaka」「password=Test123」というユーザIDとパスワードの情報をブラウザに送信している部分になります。
Cookieに含める情報はアプリケーション側で自由に決めることができ、今回はログイン状態を情報として渡したいので、ユーザIDとパスワードを設定しています。
PHPの場合、この処理は「setcookie」関数を使用することにより実現できます。
Webサーバから受け取ったCookieはクライアントPCに保管され、再び同じドメインにリクエストを送信する際にリクエストヘッダに含めた状態で送られます。
Webサーバへ再度送信されたCookieはWebアプリケーション側で情報の妥当性を確認します。
上記のコードは商品一覧画面のPHPに追加したCookieの情報をチェックする処理になります。
枠線部①では、Cookieに格納されたユーザIDとパスワードをそれぞれ変数「$user」「$password」に格納しています。
ユーザIDとパスワードの入力内容に誤りがあった場合、枠線部②の処理が実行されます。
ここでは、userとpasswordのCookieの値を削除してログイン失敗画面へリダイレクトしています。
Cookie削除の方法はsetcookie関数の第2引数に空文字「””」を設定し、第3引数のCookieの有効期限に過去の日付「time() - 3600 」を設定します。
※Cookieの有効期限はクライアントPCの現在時刻に対して比較されるため、時刻設定が誤っている場合はサーバの時刻と比較してもCookieが削除されない可能性があります。
そのため、time()関数で取得したサーバの時刻から余裕を持った3600秒前(1時間前)が設定されています。
商品一覧画面にあるログアウトボタンを押下するとログイン画面に遷移するような機能が必要な場合は、先ほどCookieのユーザIDとパスワードをチェックした処理を応用すれば簡単に作ることができます。
上記のコードではCookieのuser、passwordを削除したのちにログイン画面にリダイレクトすることで、ログアウト処理を実現しています。
Cookieが削除された状態はレスポンスヘッダ上で以下のように確認することができます。
枠線部のSet-Cookieヘッダでuser、passwordの値が「deleted」に書き換わり、expires属性に過去の日付が設定されていることが分かります。
この状態でWebブラウザのアドレスバーにURLを直接入力し、商品一覧画面に遷移しようとしてもログイン情報を送信することができないため遷移できません。
これによりログインが必要な機能で、ログイン認証を回避する不正なアクセスを防ぐことができます。
3. 第8回 まとめ
今回はWebサイトの作成におけるHTTP通信の問題点や、その問題を解決する「Cookie」という技術について解説してきました。これで問題は解決したかと思われますが、実はCookie自体にも問題があり、Webアプリケーションの作成は簡単に進まないようです。
次回はCookieの問題点とそれを解決する技術について解説予定です。