Comments
Transcript
ソフトウェアアーキテクチャ論 Software Architecture (2003年度2
ソフトウェアアーキテクチャ論 Software Architecture (2003年度2-2期 I435) 国立情報学研究所 ソフトウェア研究系 助教授 鈴木 正人 [email protected] 第13回:J2EE(3) WEB技術とセキュリティ 内容 Enterprise JavaBeans フレームワーク セキュリティの問題とセキュアプログラミング Enterprise JavaBeans Javaによるサーバサイドコンポーネント機構 業務プログラムに必要なサービスの標準化と サーブレット/JSP/Beansによる提供 ビジネスロジックのカプセル化 DB処理の容易化 WEBアプリケーション/WEBサービスへの対応 要素技術 JNDI(Java Naming and Directory Interface): 名前解決 JDBC(Java DataBase Connection): DB接続の標準化(ODBCのJavaによる実装) 動作環境 4層(4-tier)アーキテクチャ ビジネスロジック層をWEBと共通サービス (トランザクション、セキュリティ等)に分割 非JavaApplication WEBApplication JSP/Servlet E-Beans DB JDBC/JTA E-Beans クライアント層 プレゼンテーション層 (WEB層) ビジネス層 EIS層 (Enterprise Information System) E-Beanの種類[EJB2.0以上] Session:同一クライアント、同一ユーザからの一連の 操作を扱う. 状態の有無で2種類存在 Entity:データを表現、RDBの表に対応 セッション終了後も永続. 方式の違いで2種類存在 Message Driven: Java Message Serviceを利用した非同期通信を実現 Session E-Beans Statefull Entity Message Driven BMP Stateless CMP 同期 (1.1には存在しない) 非同期 E-Beanのインターフェース SessionとEntity:リモートとローカルのインタフェース MessageDriven:インターフェースなし(JMSを利用) リモートインターフェース:他のJVMから呼び出し可能 RMIを実装、引数と戻り値は値渡し ローカルインターフェース:同一JVMからのみ呼び出し可能 引数と戻り値は参照渡し それぞれホームとコンポーネントの2種類に分類 ホーム:生成/削除/廃棄、検索、共通ロジック コンポーネント:業務に必要なビジネスロジック EJBの配備と呼び出し 実行前にコンテナ内に配備されている必要あり EJBコンテナ ローカルの エンティティビーン ネットワーク Javaクライアント ローカルの ホームオブジェクト ローカルの EJBオブジェクト ローカルホーム インタフェース ローカルコンポーネント インタフェース セッションビーン リモートホーム インタフェース Javax.ejb.EJBHome IIOP リモートコンポーネント インタフェース Javax.ejb.EJBObject JVM SessionBeanの状態遷移 生成時にContextオブジェクトを登録 Statefullは非活性化が可能 非活性化時に呼び出されると自動的に活性化 存在しない 状態 1. create 2. setSessionContext(c) 3. ejbCreate() 存在しない 状態 1. create 2. setSessionContext(c) 3. ejbCreate() 1. remove 2. ejbRemove() 実行可能 状態 ejbPassivate() ejbActivate() a) ステートフルセッションビーン 非活性化 状態 1. remove 2. ejbRemove() 実行可能 状態 b) ステートレスセッションビーン EntityBeanの状態遷移 存在しない 状態 setEntityContext(c) unsetEntityContext(c) プールされた 状態 1. create 2. ejbCreate() 3. ejbPostCreate() ejbActivate() ejbPassivate() 実行可能 状態 生成時にContextを登録 すぐ実行されずにプールされる (IDは持たない) ejbCreare/ejbActivateを 受けると実行可能に(IDを持つ) BMPの場合は主キー(*)も登録 実行中にLoad/Store可能 (Serializationを利用) 1. remove 2. ejbRemove() ejbStore() ejbLoad() (*)主キー:DBでオブジェクト検索に 用いる値, 要serializable (ほとんどがjava.lang.Integer) EJBの動作(1):Bean定義 RoomRemote <<entity>> RoomBean RoomHomeRemote ホームIF定義は省略 public/abstract/例外は 省略 interface RoomRemote リモートIF extends javax.ejb.EJBObject { void setAvail(String av) ...; String getAvail() ...; } class RoomBean 本体 impements javax.ejb.EntityBean { void setAvail(String av) {} String getAvail() {} Integer ejbCreate(Integer id) { ... } void setEntityContext(EntityContext c){} void unsetEntityContext(){} void ejbActivate() {} void ejbPassivate() {} void ejbLoad() {} void ejbStore() {} void ejbRemove() {} } EJBの動作(2) AgentRemote interface AgentRemote extends javax.ejb.EJBObject { String[] listAvail() ...; } リモートIF <<session>> AgentBean AgentHomeRemote class AgentBean 本体 impements javax.ejb.SessionBean { String [] listAvail() { ... } void ejbCreate() { ... } void ejbActivate() {} void ejbPassivate() {} void ejbRemove() {} void setSessionContext(SesstionContext c){} } EJBの動作(3) listAvail <<session>> AgentBean home JNDI RoomBean 1 2 getAvail RoomBean String [] listAvail() { Context jndiContext= new ... obj=jndiContext.lookup (1)ホームを検索 (“java:comp/env/ejb/RoomHomeRemote”) RoomHomeRemote home=(RoomHomeRemote) PortableRemoteObject.narrow(obj,...) Vector v=new Vector(); for (i=0;i<size;i++) { Integer pk=new Integer(i); RoomRemote room= (2)主キーよりEntityを得る home.findByPrimaryKey(pk); if (room.getAvail()==“ok”) { v.addElement(room.getName()); } (3) Entityにアクセス } // 結果を返す } EJBの配備と流通 JNDIによるentity検索と実行が正しく行われるには、 各Beanを正しい位置に設置(配備)する必要あり EJBパッケージファイル(.ear) 各Bean実装 .class .class インターフェース 主キー 配備記述(DD) <ejb-jar> <enterprise-beans> <session> <ejb-name>AgentBean</.> <session-type>Stateless</.> <transaction-type>Container</.> <ejb-ref> <ejb-ref-name> ejb/RoomHomeRemote</.> <ejb-ref-type>Entity</.> </ejb-ref> </session> (entityも同様) </enterprise-beans> </ejb-jar> EJBの提供するサービス いずれも業務アプリケーションに必須 同時実行性(排他制御) トランザクション セキュリティ 永続化 信頼性(レプリケーション) スケーラビリティ ベンダ非依存によるポータビリティ 実用規模のものは高価 開発、運用に習熟が必要 WEBアプリケーション GUI基盤としてWEBブラウザを、 データサーバとしてWEBサーバを用いた アプリケーションの総称 最近ではXMLによる情報交換が標準化 WEBブラウザ WEBサーバ JSP サーブ レット コンテナ JVM a.xml JAXP JDBC DB d.xml WEBアプリケーションの構成 MVCアーキテクチャに基づく 構成に共通部分多い (WEBブラウザ, JSP, サーブレット, E-Bean) 要求の獲得と変数(Cookie含む)への格納 応答の作成(DB問合せ結果の加工) 画面の遷移 例外処理 ログ作成 共通な構造を抽出⇒フレームワーク フレームワーク 特定のドメインのアプリケーションに適した再利用 可能な雛型 不変部と可変部から構成 規約に従って可変部を作成 クラスライブラリとは制御の方向が異なる アプリケーション 初期化 描画 OpenWin DrawWin クラスライブラリ GUIフレームワーク Open Draw 初期化 描画 アプリケーション 不変部 可変部 Struts:WEBアプリケーション フレームワーク 基本構成 (1) request Suzuki 2/2 2/4 ActionServlet ActionForm ActionFormBean (2) Suzuki, 2/2,2/4 (8) response (7) Model (3) JSP (6) (4) ActionClass update .... (5) View Controller StrutsによるWEBアプリ(1) ActionForm: 要求を受け付ける画面 <%@ taglib prefix=“html” url=“/WEB-INF/struts-html.tld” %> <html:html> <html:form action=“/postRetrieveResv”> <table> <html:text property=“userName” size=20 /> <html:text property=“chkInDate” size=20 /> <html:text property=“chkOutDate” size=20 /> </table> <html:submit property=“submit” value=“send” /> </html:form> </html:html> StrutsによるWEBアプリ(2) ActionFormBean: データの格納 import org.apache.struts.actions.*; public final class RetreiveResvForm extends ActionForm { private String userName; private String chkInDate; private String chkOutDate; public String getChkInDate() { ... } ...... } ActionClass: データの利用 import org.apache.struts.actions.*; public final class RetrieveResvAction extends Action { public ActionForward execute(ActionMapping m, ActionForm f, ... ) { String chkInDate = f.getChkInDate(); ...... return (mapping.findforward(“success”)); } } 戻り値はActionMappingのキー StrutsによるWEBアプリ(3) ActionMapping: JSP画面の制御 コングレーションファイルで定義 例: 照会に成功したら showResult.jspを、失敗したらshowError.jspを表示 <struts-config> ActionFormBeanのクラス名 <form-beans> <form-bean name=“” RetrieveResvForm” type=“RetrieveResvForm” /> </form-beans> Actionのクラス名 <action-mappings> <action path=“/RetrieveResv” type=“RetrieveResvAction” ... > <forward name=“success” path=“showResult.jsp” /> <forward name=“fail” path=“showError.jsp” /> </action> </action-mapping> </struts-config> セキュリティ 危険なJSPコードの例(JSP 1.1以降では対策済み) Name=‘<%= userName %>’ address= ... userName=Suzukiの場合、正常に表示 userName= ‘ <% jsp:include url=偽ページ %> ’の場合: 偽ページが表示される可能性あり(クロスサイトスクリプティング) 他にもTextareaの上限を超えて文字列を入力した場合、 他の変数の内容を書き換える場合あり (バッファオーバーラン) セキュアプログラミング 安全性の高いコードを書くための手法 アーキテクチャによるサポートはまだ不十分 セキュリティホールの性質を理解することが重要 ファイル漏洩 : .jsp, .xmlファイルのパーミッションに注意 WEB-INF の下は通常クライアントには見えないが、過信は禁物 (myjsp%00, myjsp::$DATA問題) JDBCのパスワードをJSPコードに埋め込むことなどは避ける コード埋め込みとバッファオーバーラン 対策 : 文字数の検査 <,>, %, & , 引用符などの入力を監視 (入力されたら無害な文字に置換) 毎回検査するコードを 書くのは面倒 検査コードの信頼性 フレームワークによる入力の検査 strutsに含まれる検証フレームワーク validatorの利用 (1) ActionFormBeanにvalidateメソッド追加(自動的に呼ばれる) public final class ResvReqForm extends ActionForm { public String getChkInDate() { ... } ...... public ActionErrors validate(ActionMapping map, HttpServletRequest req) { ActionErrors errors = new ActionErrors(); if (userName == null && chkInDate.length > App.MAXLENGTH) errors.add(“ userName“,new ActionError(“invalidformat”)) ; } } <plug-in className=“org.apache.struts.validator.ValidatorPlugin”> <set-property value=“/WEB-INF/validator-rule.xml” > </plug-in> (2) ActionMappingにvalidator追加 pattern=“[_a-zA-Z]{1,20}” まとめ Enterprise JavaBeans : 大規模アプリケーションアーキテクチャ サーブレットとの連携 DBとの連携, 永続性, トランザクション オブジェクトの退避と活性化 フレームワーク:ドメイン固有のアプリケーション基盤 クラスライブラリとは制御の方向が逆 可変部をカスタマイズ 第5回レポート課題は後でホームページに載せます (内容はMVCを利用したアプリケーションの設計 締切 3/1[予定])