夜行月報

“夜更かし”から“新しい”をみつけるためのブログ

「プロになるためのWeb技術入門 ――なぜ、あなたはWebシステムを開発できないのか」を読んだまとめ(2/2)

Webの世界を知る

こんにちは、シロネコ書房です。

今回は、 「プロになるためのWeb技術入門 ――なぜ、あなたはWebシステムを開発できないのか」のまとめのその2になります。

その1となる前回の記事も、よければご覧くださいませ! 

www.yako-geppo.com

 Webアプリケーションを構成する技術

Cookieとは

通信プロトコルには、FTPのように状態を保持できるステートフルなプロトコルと、HTTPのように、状態を保持できないがオーバーヘッドの少ないステートレスなプロトコルがある。

HTTPが考案された当初はHTTPを使ってWebアプリケーションを実現することは考えられていなかったため、認証を必要とするようなアプリケーションでは、どうにかしてその状態を表現する必要がある。

そこで考えられたのが、Cookieという技術。

CookieはHTTPの使用を拡張して、WebアプリケーションとWebブラウザの間で情報を交換できるようにしたもの。

Cookieは「名前=値」の組み合わせで表され、WebサーバからWebブラウザへ、HTTPレスポンスのヘッダを利用して送られる。

Cookieを用いた状態の管理

WebサーバからCookieを受け取ったWebブラウザは、次回以降同じWebサーバにアクセスする際、受け取ったCookieをそのままHTTPリクエスト・ヘッダに入れて送る。

Webアプリケーション側では、リクエスト・ヘッダに入っているCookieを調べることで、アクセスしてきた相手が誰なのかを知ることができる。

Webブラウザは、Cookieを受けとったサーバとは異なるWebサーバに対してはそのCookieを送らないため、意図しない情報が他のサーバに送られることはない。

しかし、Cookieの情報はHTTPのリクエスト・ヘッダやレスポンス・ヘッダを利用して行われるため、中身を簡単に覗けてしまうという点で、セキュリティ上の課題がある。

また、CookieはPC上に保存されるため、安全性が高いとは言えない。

そこで考え出されたのが、Sessionという仕組み。

Session

Sessionとは

Sessionとは、Webアプリケーションに対して行われる、ログイン => アクション1 => アクション2 => ログアウトというような、一連の処理の流れのことを指す。

このSessionの状態(ログイン済みか、ショッピングカートに何を入れているか等)をWebアプリケーション(メモリやDB)で管理し、そしてWebサーバとWebブラウザの間では、Session ID(セッションID)という識別番号のようなものをやり取りすることで、Webクライアントの識別を行う。

こうすることで、ユーザーIDやパスワードなど重要な情報をクライアントとサーバ間でやり取りする必要がなくなり、安全性が向上する。

Sessionを用いた状態の管理

Session IDはただの数字(文字列)なので、Cookieを使ってやり取りができる。

Webサーバは、ログインなどによってセッションが開始された際にSession IDを新たに発行し、HTTPレスポンスのCookieに格納してWebクライアントに送る。

それ以降、Webクライアントがサーバにリクエストを送るときには、Session IDを格納したCookieをサーバへ送る。

WebサーバはCookieを受け取ると、そこに格納されたSession IDを元にしてクライアントの情報を復元させる。 

スポンサーリンク 

 

Webアプリケーションの構成要素

WebアプリケーションはクライアントとサーバがHTTPによって通信することによって実現されている。

つまり、デスクトップアプリケーションとは違い、Webアプリケーションの世界では、少なくともWebサーバとWebクライアントそれぞれが動作する2台のコンピュータが必要であり、多くの場合、サーバ側で複数のコンピュータが連携して動作している。

その構成にはバリエーションがあり、時代や求められる機能に応じて異なってきた。

例えば、WWWが生まれた当初は、WebサーバとWebクライアントがあれば十分事足りていた(静的なHTMLをやり取りするだけだったため)が、そこにDBが組み込まれるようになると、負荷分散のためにそれぞれを別々のコンピュータ上で動作させるようになった。

Webアプリケーションとデータベースは、データベース製品固有の通信プロトコルを用いて通信を行う。このような通信は、DBアクセス用のライブラリが行ってくれるため、アプリケーションの開発者がプロトコルを意識する必要はない。

アプリケーションサーバの登場

JavaでWebアプリケーションを開発する際、JavaVM上ではアプリケーションサーバと呼ばれるソフトウェアが動作しており、それがServletやJSPを動かしている。

Webサーバにリクエストが届くたびに新しいプロセスが起動されるCGIとは違い、アプリケーションサーバでは常にプロセスが実行されているため、Webサーバからのリクエストを受けるたびに処理を実行できる。

アプリケーションサーバには、代表的なものとして、オープンソースで開発されているTomcatなどがあげられる。

Webサーバとアプリケーションサーバは異なるプロセス上で動いているため、互いに連携するには何かしらの通信を行う必要がある。

一般的には、アプリケーションサーバ側が主要なWebサーバごとに連携用のモジュールを用意してくれている。Tomcatの場合、Apache向けにmod_jkと呼ばれる連携モジュールが用意されている。

Webサーバとアプリケーションサーバを異なるノードに配置すると、軽い処理で回数の多い静的コンテンツのリクエストはWebサーバに、回数が少なく処理の重い動的コンテンツへのリクエストはアプリケーションサーバに、と処理を分けることで負荷を分散できる。

実はほとんどのアプリケーションサーバはWebサーバとしての機能も持ち合わせているため、単独でWebサーバとして機能することもできる。(システム構成の単純化)

ただ、最低限のWebサーバとしての機能しか提供しないことが多いため、Webサーバとしてより多くの機能を利用したい場合は、やはりWebサーバとアプリケーションサーバを分離して運用する必要がある。

Webシステムの3層構造

Webアプリケーションを構成するサーバは、理論的には、Webサーバとアプリケーションサーバ、そしてデータベースサーバの3種類しかない。

各サーバのプロセスを1つのノードにまとめて配置するのか、必要に応じて複数のノードに分散して配置するのかが異なるだけで、それは実現したいWebアプリケーションの規模や使用目的に応じて異なる。

こうしたWebシステムを構成する3つのソフトウェアを連携させる構成を、Webシステムの3層構造と呼ぶ。

Webアプリケーションのシステムを理解するためには、これらの役割を理解することが大切。

スポンサーリンク

 

Webアプリケーションを効率よく開発するための仕組み

Forward(フォワード)

ログイン処理を行ったのち、ユーザ認証が通った場合には商品一覧ページへ、通らなかった場合にはログイン失敗ページへそれぞれ遷移するような処理は、ブラウザを通さずにアプリケーションサーバの中でのみ行われる。

こうした遷移を、Forward(フォワード)という。

Forwardではリダイレクトと違って、1回のHTTPリクエストで遷移が可能となるため、リダイレクトよりも処理が早くなる。

リクエストスコープ

Forwardによって別のページに遷移する場合、DBを参照して得たログインしているユーザーの情報など、画面上の表示で使用する情報をフォワード元とフォワード先の間で共有する必要がある。

そういった場合に利用されるのが、リクエストスコープによる情報の引き渡し。

リクエストスコープはアプリケーションサーバによって提供される機能で、フォワードの前後でJavaのオブジェクトを共有できる。

ただし、1回のHTTPリクエストを処理する間のみ有効であり、リクエストが終了するとリクエストスコープに保持されていた情報は消えてしまう。

なぜリクエストスコープが必要なのか

リクエストスコープの代わりに、セッション(セッションスコープ)を利用しても同様の処理は実現できる。

しかし、セッションに保持した情報は、ログアウトなどの明示的なセッションの破棄が行われない限り解放されない。

通常、セッションが保存する情報はアプリケーションサーバのメモリに保存されるため、セッションが増えてくるとメモリ不足に陥ってしまう。

一定時間しようされなかったセッション情報を自動的に破棄するセッション・タイムアウトを用いることで上記の問題はある程度解決できるが、それなら、リクエストが終わった時に自動的に情報が破棄されるリクエストスコープを使った方が効率がよい。

Webアプリケーションのアーキテクチャ

品質の良いアプリケーションを開発するには、その全体構造を最初にきちんと考慮した設計を行う必要がある。

その上で、似たようなソフトウェアには共通の設計スタイルとその設計に基づく全体構造があり、それをアーキテクチャと言う。

MVCモデル

Webアプリケーションの処理は、個々のリクエストに対する処理というレベルでは、情報の「入力(input)」「処理(process)」「出力(output)」の繰り返しでしかない。

この3要素は、それぞれの頭文字をとってIPOと呼ばれる。

WebアプリケーションではIPOの処理と画面遷移の制御がメインとなるが、これらを踏まえたWebアプリケーションのアーキテクチャを「MVCモデル」という。

 

MVCモデルでは、アプリケーションを「モデル(Model)」「ビュー(View)」「コントローラー(Controller)」の3つの役割に分けて作成する。

モデル(Model)

モデルはアプリケーションの「処理(process)」とそれに関する情報の保持を担当する。

その一方で、画面の出力などの部分には一切関わらない。

ビュー(View)

ビューはモデルによる処理結果の画面への表示を担当する。

処理結果自体はモデルが持っているため、ビューがモデルから情報を取り出して、見やすく整形した上で画面上に表示する。

モデルとは逆に、画面への表示を行うが、情報の処理には一切関わらない。

コントローラー(Controller)

コントローラーは画面からの情報の入力と、モデルの呼び出し、およびその結果に従ったビューの呼び出しを行う。

具体的には、まずユーザが画面に入力した情報を取り出し、処理を担当するモデルに渡すし、その結果によって表示するビューを選択して呼び出す、という処理を行っている。

その名の通り、全体の流れの制御を行っているのである。

フレームワークを用いたアーキテクチャの実現

MVCモデルの知見を簡単に実現するものとして、フレームワークという考え方がある。

アーキテクチャを実現する部分を共通化し、効率よくアプリケーションを開発できるようにするのが、フレームワーク。

Struts

Javaには、WebアプリケーションフレームワークとしてStruts(ストラッツ)がある。

Strutsでは、アクションサーブレットというサーブレットがHTTPリクエストを一手に引き受けて処理を行う。

レイヤパターン

MVCモデルのようなアーキテクチャパターンに、Layersと呼ばれるアーキテクチャパターンがある。

その名の通り、Layersパターンはシステムを階層化し、上位レイヤが下位レイヤの提供する機能を利用することで各レイヤの作りを単純化していく考え方。

各レイヤは、それぞれの直接の下位レイヤ以外を知る必要がなくなるため、各レイヤの責務を明確化することができ、また各レイヤがその責務を全うできるように開発するだけでシステム全体を動かすことができる。

Webアプリケーションでは、以下の3つのレイヤに分離されることが一般的になっている。

プレゼンテーション層

プレゼンテーション層は、システム利用者とのインターフェイスを担当するレイヤ。

Webブラウザを通してユーザからの入力を受け取り、下位レイヤであるビジネスロジック層へ渡す。また、その処理結果を再びWebブラウザに表示したり、画面遷移を制御したりする。

MVCモデルにおいては、コントローラーとビューが担当する。

ビジネスロジック層

ビジネスロジック層は、アプリケーションが実現すべき固有の処理を実行するためのレイヤ。

ユーザーが入力した情報をプレゼンテーション層から受け取り、必要に応じてデータアクセス層を通じてデータベースを利用し、処理を実行する。そしてその結果を、再びプレゼンテーション層へ返す。

MVCモデルにおいては、モデルが担当する。

データアクセス層

データアクセス層は、ビジネスロジック層とデータベースの仲立ちを行うレイヤ。

データベースへアクセスするための複雑な処理をビジネスロジックから切り離し、データベースへのアクセス手順などを意識せずとも利用できるようにするのが主な役割。

MVCモデルにおいては、ここもモデルが担当する。

O/Rマッピングフレームワークデータアクセス層の実現

データアクセス層を実現するには、DAO(Data Access Object)を利用する。

DAOはJavaEEにおけるデザインパターンの一つで、データベースへのアクセス機能をDAOというオブジェクトに分離することで再利用性とメンテナンス性を向上させるもの。

ただし、これだけで面倒なデータベースアクセスが簡単になるわけではなく、実際には「O/Rマッピングフレームワーク」と呼ばれるフレームワークが利用され、これによって課題の解決が行われている。

O/Rマッピングフレームワークは、リレーショナルデータベースとオブジェクト指向の考え方の違いから生じるインピーダンス・ミスマッチを解決することが最大の役割である。

O/Rマッピングフレームワークは、DBから取得した情報をオブジェクトに組み立て直すという、通常なら単純なコードを書かねばならない過程を省略してくれるため、バグ埋め込みのリスクを回避し、開発自体を効率化してくれる。

スポンサーリンク

 

フレームワークを利用することのメリットとデメリット

Webアプリケーションを開発する上で、フレームワークの利用は必要不可欠と言える。

ただし、そこにはメリットだけでなくデメリットも存在するため、それらを考慮してフレームワークの導入を検討する必要がある。

主なメリット、デメリットは以下の通り。

メリット

  • 設計・開発工数の削減
  • 品質の向上
  • テスト工数の削減

デメリット

  • 学習コストの増大
  • 設計における自由度の低下
  • フレームワーク利用者の長期的な技術力の低下

セキュリティを確保するための仕組み

Webアプリケーションを含む情報システムにおいては、以下の3つの守るべき情報セキュリティがある。

  1. 情報の漏えい防止(機密性)
  2. 情報の改ざん防止(完全性)
  3. 適切な権限を持った人間が適切な情報を利用できること(可用性)

代表的なWebの攻撃方法とその対策

SQLインジェクション

Webフォームなどのインターフェースを利用し、データベースに発行されるSQLを開発者が意図しない形に変更することで、情報の不正な取得や改ざんを行うこと。

インターネットに繋がる世界中のコンピュータから攻撃が可能であること、また被害者が情報の流出に気づきにくいことがSQLインジェクションの恐ろしい点。

対策としては、入力値の正当性チェック、DBのプリペアード・ステートメントの利用などがある。

クロスサイトスクリプティング(XSS)

HTMLの中に悪意のある動作をするJavaScriptを埋め込み、それをWebブラウザに実行させることで、Cookieの盗聴やページの改ざんなどを行う攻撃方法。これによって、不正ログインや個人情報の漏えいなどが引き起こされてしまう。

クロスサイトスクリプティングは、フォームへ入力された情報がそのままHTMLに出力されるようなサイトで狙われる。

そのため対策としては、HTMLへ出力する前に文字列をサニタイズ(HTMLに対して無害な文字列に変換)したり、それ以前に入力値のチェックを行うなどが考えられる。

セッションハイジャック

クライアントとサーバの間でやり取りされているセッションIDを第三者が盗み見ることで、正規の利用者になりすましてサービスを不正利用する、という攻撃方法、

セッションハイジャックが行われると、何者かに勝手に買い物をされるなどの被害が生じる。

対策としては、SSLによる通信制路の暗号化、セッション・タイムアウト値の適切な設定、セッションIDのランダム化などが挙げられる。

クロスサイトリクエストフォージェリ

攻撃者が捏造したWebフォームから強制的に情報をサブミットすることで、掲示板に意図しない書き込みをされたり、ユーザー情報の勝手な更新を行われたりする攻撃方法。

利用するのにログインが必要なサイトであっても、攻撃を受けた人がすでにログイン状態にあれば、攻撃者がその人のログイン情報を知らなくても攻撃が可能。

対策としては、ワンタイムトークンによる正当な利用者によるサブミットかどうかの確認がある。

強制ブラウズ

WebブラウザのアドレスバーにURLを直接入力することで、本来表示されるべきではない画面を表示させる攻撃。

対策としては、どのような画面にアクセスされても必ずログイン状態のチェックを行い、未ログイン状態であればログイン画面に強制遷移させるなどの方法が挙げられる。

ディレクトリトラバーサル

リクエスト時に渡された文字列を用いてシステム内のファイルを表示するようなアプリケーションでは、その文字列によっては公開されてはいけない情報まで閲覧可能になってしまう。

このような脆弱性を狙って行われる攻撃を、ディレクトリトラバーサル攻撃という。

これを防ぐには、サニタイズ処理によって「/」などの文字列を削除したり、ファイルシステムのアクセス権限をユーザーごとに適切に設定することが必要になる。

しかしそもそも、ユーザーから入力されたパラメータをそのままファイル名として利用するような設計にしないことが重要。

設計や実装ミスに起因する誤動作・セキュリティ問題

戻るボタン問題

Webブラウザの戻るボタンはWebブラウザのキャッシュを利用して画面を再表示しているため、例えば、ショッピングサイトで購入ボタンを押した後に戻るボタンを押し、再び注文ボタンを押すと、同じ注文が再度行われてしまう。

こうした戻るボタンの意図しない動作を防ぐための対策には、以下の方法がある。

  • ブラウザによるキャッシュの無効化
  • JavaScriptによる戻るボタンそのものの無効化
  • ワンタイムトークンの利用

ダブルサブミット問題

ネットワークが混み合っている時、ユーザーがサブミットボタンを連続でクリックしたような場合に、同じ処理が複数回行われてしまうことがある。

これを防ぐためには、JavaScriptよって2回目以降のサブミットを無効化したり、ワンタイムトークンによって適切なサブミットかどうかを確認するなどの処理を行う必要がある。

その他の実装上の注意

  • hiddenパラメータに重要な情報を持たせない
  • デバック情報をWebブラウザに表示しない
  • グローバル変数に情報を持たせない

まとめ

ザーッと内容を振り返ってみましたが、全体の感想として、本書はWebアプリケーションを開発する上で必須の知識を得るのに最適な1冊だなと思いました(小並感)。

特に、WebとWebアプリケーション発達の歴史やその経緯を知れたことが、現代のWebアプリ開発に取り入れられている手法や思想が、なぜそうなっているのか、どうしてそうする必要があったのかという背景の理解につながり、個人的にとても大きな学びになりました。

普段はRubyとRailsを用いた開発を行っているのですが、恥ずかしい話、MVCモデルやら、セッションやら、O/Rマッパーやらを「なんでこういうものが必要かは知らないけど、とりあえず便利らしいから使う」という認識で開発を行ってきていたので......。今回、その中にあったモヤモヤした部分を今回解消できたことは、Webエンジニアとして大きな進歩だと思っています。

Webアプリケーションを開発に携わる新人さんに太鼓判を押してお勧めできる内容だと思うので、気になる方はぜひ!

 

それでは、今回はこの辺で。

ではでは、またまた。