ソフトウェアアーキテクチャ論 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[予定])