Zend_Acl in ServiceLayer
Upcoming SlideShare
Loading in...5
×

Like this? Share it with your network

Share

Zend_Acl in ServiceLayer

  • 4,959 views
Uploaded on

phpstudy_91 Zend Framework勉強会#2 noopable's presentation

phpstudy_91 Zend Framework勉強会#2 noopable's presentation

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
4,959
On Slideshare
2,956
From Embeds
2,003
Number of Embeds
6

Actions

Shares
Downloads
24
Comments
0
Likes
4

Embeds 2,003

http://d.hatena.ne.jp 1,966
http://webcache.googleusercontent.com 18
http://www.slideshare.net 14
http://linyo.ws 3
http://translate.googleusercontent.com 1
http://ss.dotbranch.com 1

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. アクセス制御
    Zend_Aclin ServiceLayer
  • 2. CWE(Common Weakness Enumeration)~脆弱性の種類を識別するための共通の脆弱性タイプの一覧~
    http://cwe.mitre.org/top25/
    http://www.ipa.go.jp/security/vuln/CWE.html
  • 3. 脆弱性タイプの一覧
    1位:XSS
    2位:SQLインジェクション
    3位:バッファオーバーフロー
    4位:CSRF
    5位:不正確なアクセス制御
    制御方法がさまざまでノウハウが蓄積されにくい?
    http://cwe.mitre.org/top25/
    http://cwe.mitre.org/top25/#CWE-285
    http://www.ipa.go.jp/security/vuln/CWE.html
  • 4. 手動アクセス制御の失敗
    アクセス制御を個別メソッドに書く限りうっかりミスは防げない。
    動作とアクセス制御は分離するべき
    テストで防げる?
    ついうっかりが発生するシチュエーションではテスト仕様自体に漏れがある
    制御コードを回避?
    ある画面へのアクセス許可があっても、その画面から対象外のリソースへアクセスするコードが混入すると、回避リスクが発生する
    課題
  • 5. サイバー・ノーガード戦法
    対策は
    例えば、PHPを避ける
    サービスレイヤーでアクセス制御
  • 6. アクセス制御
    アクセス制御は脆弱性ランキング5位
    コントローラーでアクセス制御
    ZF+ OSSで見るアクセス制御の実例
    サービス層でリファレンスモニタを使う
    テーマ
  • 7. アクセス制御用コンポーネント
    Zend_Acl(承認)
    ロールベースアクセス制御(RBAC)
    Zend_Auth(認証)
    認証アダプタを利用した認証
    DBアダプタを利用するとユーザーの関連情報も取得できる。
    認証の永続化
    デフォルトではセッションを利用するが、memcached等の分散ストレージで構成することも可能。ファーム構成でも使える
  • 8. クィックスタート
    http://framework.zend.com/manual/ja/learning.multiuser.html
    Zend Frameworkによるマルチユーザーアプリケーションの構築
    ユーザーセッション管理
    ユーザー認証
    承認システムの構築
  • 9. Zend_Acl
  • 10. ルールの設定
    定義
    セット(リソース・ロール・権限)に対するルールを設定する
    nullは常に一致する
    同じセットへのルールは上書きされる。
    同じセットに対して、原則許可、assert付きで拒否というようなルールは作成できない
  • 11. リソースとロールの継承
    継承はクラス継承ではなく、Aclへの登録時に親を指定する。
    権限チェックは親を辿ってルールを探索
    リソース継承
    リソースをツリー状に構成
    ロール継承
    権限の集約
    許可がわかりやすくなる
    × if super-admin or manager
    ○ if manager
    複数ロールの所有をまとめる
    Zend_Acl 2.0では、複数ロールに対応するかもしれない
  • 12. 疑似ロールの例(CURRENT_USER)
    単一ユーザーアクセス規約
    現在アクセスしているユーザーの権限でだけ動作すると仮定できる場合
    ログインしたユーザーが持つ複数のロールを、疑似ロール CURRENT_USERでまとめる
    特定の許可は与えず、ユーザーが保持しているロールを継承するのみとする。
    権限チェックは疑似ロールに対して行う
  • 13. 疑似ロール(CURRENT_USER)
    構成
    @singleton Current_User
    $user = Current_User::getInstance();
    $roles = $user->getRoles();
    $acl->addRole(CURRENT_USER,$roles);
    チェック
    $acl->isAllowed(CURRENT_USER, $resource, $priv);
  • 14. Assertion
    $acl->allow($role, $res, $priv, $assertion);
  • 15. Assertionの仕様
    http://framework.zend.com/manual/ja/zend.acl.advanced.html#zend.acl.advanced.assertions
    Zend_Acl_Assert_Interface
    // @return boolean
    functionassert(Zend_Acl $acl,
                               Zend_Acl_Role_Interface $role = null,
                               Zend_Acl_Resource_Interface $resource = null,
                               $privilege = null)
    リソース自身がassetするassertionという実装も
  • 16. Assertionの使いどころ
    banリスト
    IPアドレス等でアクセス拒否
    個別ユーザーの任意アクセス制御
    友達まで公開
    一時的特権
    1日店長とか
    ASPで試用期間、サポートチケットとか
    ※Zend_Cacheを使うと簡単
  • 17. ルール+Assertion
    $acl->allow($role, $res, $priv, $assert);
    $assertがtrueならallow、 falseならnull
    $acl->deny($role, $res, $priv, $assert);
    $assertがtrueならdeny、 falseならnull
    $acl->allow(null, null, null, $assert);
    assertがtrueならallow、falseならdeny
    Assertに失敗した場合は次のルールを評価する。全null許可は最後に確認され、反転した許可タイプが返される
  • 18. ルール評価順チートシート
    指定リソース
    指定ロール
    指定権限
    全権(null)
    親ロール
    指定権限
    全権(null)
    親リソース
    指定ロール
    指定権限
    全権(null)
    親ロール
    指定権限
    全権(null)
    nullリソース
    以下同じ
    $acl->isAllowed($resource, $role, $privilege)
    指定したリソース、ロール、権限に一致するルールを順に検索する。
    一致したルール以後は評価されない。
    (assertionは一致条件の追加)
    nullを指定した検索では、nullルールにマッチする
    注)間違いがあったら、ご指摘ください。
  • 19. ルール作成と運用のコツ
    複雑化するときはスコープを分けてAclオブジェクト自体を切り替える
    アクセスブロック、コントローラー、サービス
    リソースと権限の表を作り、分割と集約で整理する
    権限が多すぎる場合は、リソースを分割
    リソースが多すぎる場合には、リソースの継承で集約リソースを作成
    ロールを組み立てる
    リソース毎の権限を整理して、機能ロールを作成
    機能ロールを集め、集約ロールを作る
  • 20. リソース、権限の整理
  • 21. サンプルコード
  • 22. 規約重視の制御例
    NewsControllerextends Zend_Controller_Action
    News_Aclextends Zend_Acl
    Newsextends Zend_Db_Table_Abstract
    参考)
    http://weierophinney.net/matthew/archives/201-Applying-ACLs-to-Models.html
    http://www.oplabo.jp/article/44
  • 23. News_Acl
    <?php
    class News_Acl extends Zend_Acl
    {
    protected $_name = 'news';
    public function __construct()
    {
    //sample
    $this->addRole(new Zend_Acl_Role('marketing'), 'staff')
    ->addResource(new Zend_Acl_Resource($this->_name))
    ->allow('marketing', $this->_name, array('publish', 'archive'));
    }
    }
  • 24. NewsController
    <?php
    class NewsController extends Zend_Controller_Action
    {
    // resource name
    protected $_name = 'news';
    public function init()
    {
    $this->_acl = new News_Acl;
    }
    }
  • 25. NewsController::preDispatch()
    $action = $this->getRequest()->getActionName();
    $auth = Zend_Auth::getInstance();
    $role = $this->getRole($auth->getIdentity());
    if (! $this->_acl->isAllowed($role, $this->_name, $action)) {
    throw new Exception('action not permitted');
    //ここでエラーアクションに書き換えてもよい。
    }
    parent::preDispatch();
  • 26. コントローラーでのアクセス制御
    介入ポイント
    init
    preDispatch
    アクションヘルパー
    プラグイン
    メリット
    MVCで動作するかぎり必ず処理される
    代替画面などクライアント向けの親切対応ができる
  • 27. Final Answer?
    "Keep it simple, stupid“
    システムに複雑さを持ち込まない。
    アクセス制御は可能な限りシンプルに
    必要最小限の複雑さで実装する
    規約重視パターンは単純な実装形態の一つ
    単純な実装で複雑な仕様を実現しようとすれば破綻する
    仕様と実装のバランスで最適な表現方法を見つけることが重要
  • 28. Zend_Aclの実際
    オープンソースで見る
  • 29. Live Commerce
    http://www.live-commerce.com/
    LoginController
    Aclを定義してZend_Aclインスタンスを返す
    セッションにAclごと保存
    アクションヘルパーLoginValidator
    ログインチェック
    セッションに保存されたAclでコントローラーに対する権限チェック
    管理画面用モジュール
    コントローラー::initで、コントローラーへのアクセス権があるかどうかを必ずチェックしてリダイレクト
    c::isAllowed
    グローバル参照可能なチェックメソッド
    ビューでメニューの表示を調整
  • 30. Omeka
    http://omeka.org/
    AclはZend_Application用のAclリソースを作成して使う
    aclを定義したリソースファイルから読み込むOmeka_Aclを準備してリソースとして返す
    omeka/application/core/acl.php
    アクションヘルパーacl
    preDispatchで基本的な権限チェック
    モジュール+コントローラー = リソース
    基底コントローラーにisAllowedメソッドを持ち、重要なアクションの前にチェック
    リソースに権限セットを割り当て
  • 31. TomatoCMS
    http://www.tomatocms.com/
    SingletonServices_Acl
    データベースからルールセットを取得してAclをビルドしている
    isUserOrRoleAllowed
    Authプラグイン
    preDispatchでモジュール・コントローラーへのアクセス権をチェック
    Services_RuleChecker
    アクセス許可があればコールバックの結果を返すプロキシ
    主にviewヘルパーで使う
    Block IP assertion
    BackEnd Access white list
  • 32. Aclデータの保存
    データの使用法にはさまざまなものが考えられるので、 ACL データの保存は、場面に応じて開発者側で考えることになります。 Zend_Acl はシリアライズ可能なので、ACL オブジェクトを PHP の serialize() 関数でシリアライズすることができます。シリアライズした結果を、 ファイルやデータベースあるいはキャッシュなどのお好みの場所に保存することができます。
    マニュアルより
  • 33. Aclデータのロード・保存方法比較
    Live Commerce
    コントローラーに設定
    セッションに保存
    Omeka
    Zend_Applicationリソースでacl.phpを読む
    TomatoCMS
    データベースから読み込み
    任意アクセス制御にはDB読込
  • 34. いずれも
    コントローラーでのアクセス制御
  • 35. コントローラー制御の困り所
    プラグイン開発
    サービスBの機能を利用するプラグインαは、コントローラーYと同様のアクセス制御を自主的にセット
    サービスBへのアクセス制御レベルが変更になった
    変更を必要とするのはどのライブラリ??
    WebサービスサーバーやCLIの実装
    サーバーライブラリやCLIからサービスを使いたいというシナリオは増加傾向
  • 36. 複雑なシステムでの制御
    コントローラーでのアクセス制御は画面に対するアクセス制御
    回避ルートを作らない
    境界とポリシーを明確にする
    サービスはコントローラーを無条件で信用してはいけない。
    モデルでの制御が不要になるのは、サービスとコントローラーの関係が固定されているときのみ
  • 37. 安全な仕組みを提供する
    コントローラーの仕事
    クライアント認証を保証する
    画面レベルの制御ポリシーを作る
    モデルへ問い合わせる
    サービスレイヤー
    承認を経ていないアクセスを拒否する
    クライアントからの問い合わせに答える?
    Mediatorを入れている場合はMediatorで
  • 38. Zend_Acl in Service Layer
  • 39. アクセス制御レイヤーについて調べてみた
    http://www.infoq.com/articles/ddd-in-practice
  • 40. サービスレイヤーでアクセス制御
    Service Layer(PofEAA)
    http://www.martinfowler.com/eaaCatalog/serviceLayer.html
    http://www.slideshare.net/weierophinney/architecting-ajax-applications-with-zend-framework
    P28~32
    参考
  • 41. Domain Layer
    Data Source Layer
    ServiceLayer
    Presentation Layer
    ドメインロジックと
    アプリケーションロジックの境界で、アプリケーション層からの要求を監査する
    http://www.martinfowler.com/eaaCatalog/serviceLayer.html
  • 42. サービスレイヤーで実装例
    サービスはリソース
    渡されたAclに自分のAclを追加定義する
    渡されたRoleを元に、権限をチェックして許可がなければ実行しない
  • 43. サンプルコード
  • 44. Model_User
    implements Zend_Acl_Role_Interface
     
        public function getRoleId()
        {
            if ($this->_aclRoleId == null) {
                return 'guest';
            }
     
            return $this->_aclRoleId;
        }
  • 45. Service_Posts
    implements Zend_Acl_Resource_Interface
    public function getResourceId()
    {
    return ‘service_posts';
    }
  • 46. Aclの受け入れと設定
    public function setAcl(Zend_Acl $acl)
    {
    $acl->add($this)
    // ...
    ->allow('admin', $this, array(
    'register', 'update', 'list', 'delete'));
    $this->_acl = $acl;
    return $this;
    }
  • 47. Roleの受け入れ(subject設定)
    public function setRole( Zend_Role_Interface $role ) {
    $this->_role = $role;
    return $this;
    }
  • 48. メソッドに制御を追加
    public function getList()
    {
    if (!$this->getAcl()->isAllowed(
    $this->getRole(), $this, 'list')
    ) {
    throw new UnauthorizedException();
    }
    // ...
    }
  • 49. クライアントコード
    $service->setAcl($acl);
    $service->setRole($role);
    try {
    $list = $service->getList();
    } catch (UnauthorizedException $e) {
    $this->_redirect(‘unauth’);
    }
  • 50. これでサービスレイヤーでのアクセス制御が可能になりました
  • 51. サンプルソースの課題
    サービスがAclを操作している
    制御実装がサービスクラスに依存
    Aclに対する操作は実際は単純ではない
    ロールやリソースの継承、2重登録チェック
    メソッドにアクセス制御コード必須
    メソッドに要件以外の内容を追加すべきか
    すべてのサービスにsetAcl SetRoleを実装すべきか。
    SRP単一責任原則は?
  • 52. そこで、セキュリティといえばIPA
    ということで、調べてみました
    http://www.ipa.go.jp/security/awareness/administrator/security-model.pdf
  • 53. リファレンスモニターを使う
    Subject
    参考
    Acl
    http://www.ipa.go.jp/security/awareness/administrator/security-model.pdf
    Object
    リファレンス
    モニタ
  • 54. リファレンスモニター
    アクセスをする側(サブジェクト)から、アクセスされる対象(オブジェクト)へどんなアクセス(リファレンス)ができるのかを明確化する。
    「リファレンス・モニター」はすべてのアクセス(リファレンス)を監視・仲介してアクセス制御ポリシーを適用する。
    参考
  • 55. 目標
    Acl操作はリファレンスモニターの責務
    制御に対応するサービス
    getRulesでルールを提供
    許可されていないメソッドを禁止する
    制御に対応するサブジェクト
    getRoleIdでロールを提示
    サービスコンテナ
    オブジェクトの関係を定義して、使えるサービスを保管する
  • 56. リファクタリング手順
    クラスの責務と関係を明確にする
    Visitorパターン
    処理を仲介する
    Mediatorパターン
    構成を管理する
    コンテナ
  • 57. 「金づちを持つとすべて釘に見える」
    http://www.doyouphp.jp/phpdp/phpdp_01-2-2_demerit_of_design_pattern.shtml
  • 58. サンプルの構成
    • サービスがAclを操作する。
    • 59. サービスがAclに対する操作を知っている必要がある
  • Visitorパターン
    クラスの責務と関係を明確にする
    Monitor
    Aclを管理する
    アクセスを監視する
    Object(サービス)
    Monitorを受け入れる
    アクセスルールを提供する
    Subject
    自分が何者かを表明する
  • 60. interface
    interface Acceptor
    {
    public function accept(visitor $visitor);
    }
    interface Visitor
    {
    public function visit(Acceptor $acceptor);
    }
  • 61. interface Object
    extends Acceptor, Zend_Acl_Resource_Interface {}
    interface Subject
    extends Acceptor, Visitor, Zend_Acl_Role_Interface {}
    interface Monitor
    extends Visitor {}
  • 62. Object::accept($monitor)
    ・子オブジェクトにも伝達
    Monitor::visit(Acceptor $acceptor)
    ・オブジェクトのAclリストを取得
    ・サブジェクトのロールを取得
    Subject::visit(Acceptor $object)
    ・オブジェクトに対する処理
    Visitorパターン
    オブジェクト間処理の定型化
    SubjectからObjectへの要求
    リファレンスモニターの受け入れ
    受け入れの再帰処理
    メリット
    定型処理を集中管理できる
    クライアントが定型処理を知る必要がない
    phpにはオーバーロードがないけど?
    型チェックでswitchしたら意味がない?
  • 63. public function accept(Visitor $visitor)
    {
    switch (true) {
    case $visitor instanceof Subject:
    $this->_subject = $subject;
    break;
    case $visitor instanceof Monitor:
    $this->_monitor = $visitor;
    break;
    default:
    return $this;
    }
    $visitor->visit($this);
    return $this;
    }
  • 64. public function visit(Acceptor $acceptor)
    {
    switch (true) {
    case $acceptor instanceof Object:
    $this->_visitObject($acceptor);
    break;
    case $acceptor instanceof Subject:
    $this->_visitSubject($acceptor);
    break;
    }
    }
  • 65. protected function _visitObject(Object $object)
    {
    $resourceID = $object->getResourceId();
    if (! $this->_acl->has($object)) {
    $this->_acl->addResource($object);
    }
    if ($object instanceofRuleAggregate) {
    $rules = $object->getRules();
    foreach ($rules as $rule) {
    $type = isset($rule['type']) ? $rule['type'] : Zend_Acl::TYPE_ALLOW;
    $role = isset($rule['role']) ? $rule['role'] : null;
    $resource = isset($rule['resource']) ? $rule['resource'] : $object;
    $privileges = isset($rule['privileges']) ? $rule['privileges'] : null;
    $assert = isset($rule['assert']) && $rule['assert'] instanceof Zend_Acl_Assert_Interface ? $rule['assert'] : null;
    $this->_acl->setRule(Zend_Acl::OP_ADD, $type, $resource, $acceptor, $privileges, $assert);
    }
    }
    if ($object instanceof Zend_Acl_Assert_Interface) {
    $this->_acl->allow(null, $object, null, $object);
    }
    return $this;
    }
  • 66. Mediatorを通す
    手続きをMediatorに任せる
    クライアントからはサービスがMediatorに見える
    public function __construct(.......
    $object->accept($monitor);
    $subject->accept($monitor);
    $object->accept($subject);
  • 67. Mediator
    public function __construct(Monitor $monitor
    , Subject $subject
    , Object $object)
    {
    $this->_monitor = $monitor;
    $this->_subject = $subject;
    $this->_object = $object;
    $this->_subject->accept($this->_monitor);
    $this->_object->accept($this->_monitor);
    $this->_object->accept($this->_subject);
    }
  • 68. Mediator
    public function __call($method, $args)
    {
    $privilege =
    $this->_object->getPrivilege($method);
    if (! $this->_monitor->isAllowed(
    $this->_subject->getRole()
    , $this->_object, $privilege)) {
    throw new Exception('method not allowed');
    }
    }
  • 69. ContainerからMediatorを取得
    ・Zend_ApplicationのBootstrap用リソースで、サービス用コンテナを作成しMediatorを取得します。
    ・アクセス制御用コードを分離
    ・Aclルールはサービスのプロパティとする
  • 70. DIコンテナを使う
    Zend_Applicationのリソースだと、メソッドからのビルドを設定に書き出せません。
    yadif等をZend_Applicationのリソースで使ってみるとよいと思います。
    手前みそですがブログに書きました
    http://d.hatena.ne.jp/noopable/20100213/1266050466
  • 71. コンテナでのサンプル実装(1)
    $acl = $this->getApplication()->acl;
    $accessControl = new Foo_Service_AccessControl($acl);
    $user = new Foo_Model_User;
    $user->accept($accessControl);
    $service = new Foo_Service;
    $service->accept($accessControl);
  • 72. コンテナでのサンプル実装(2)
    $acl = $this->getApplication()->acl;
    $monitor = new Monitor($acl);
    $mediator =
    new Mediator($monitor, $user, $service);
  • 73. Controller
    $container = $this->getInvokeArg(‘bootstrap’);
    $service = $container->services->bugService;
    try {
    $service->execFoo();
    } catch (PermissionDeniedException $e) {
    die($e->getMessage());
    }
  • 74. 許可されたメソッドだけを実行
    public function __call($methodName, $args)
    {
    if (! $this->_isAllowed($methodName)) {
    throw new Exception('method not allowed');
    }
    if (method_exists($this, '_' . $methodName)) {
    return call_user_func_array(array($this, ‘_’ .    $methodName), $args);
    }
    // etc. etc. etc.
    }
  • 75. メソッドと権限をマップして許可
    protected function _isAllowed($methodName)
    {
    $privilege = $this->getPrivilege($methodName);
    if (!$this->_monitor || !$this->_subject) {
    throw new Exception('Acc is not activated.');
    }
    return $this->_monitor
    ->isAllowed($this->_subject, $this, $privilege);
    }
  • 76. 基礎設計の完成
    コントローラーはサービスを利用する
    制御情報はサービスのプロパティ
    制御操作・約束事は集中管理
    回避できないアクセス制御
  • 77. サービスレイヤーでのアクセス制御をお勧めするもうひとつの理由はZF 2.0
    バージョンアップ対応
    アプリ層でのアクセス制御では、アプリ層のV.upで再実装になるリスクが高い。サービスレイヤーなら、そのまま移植できる
    リファレンスモニターを使う理由
    setAcl形式だとZF1.xのZend_Aclを前提とせざるをえない
    リファレンスモニターなら両バージョンに対応可能
  • 78. まとめ
    モデルもAclもコアな部分は
    実装対象にベストマッチする
    アーキテクチャを構成しよう
  • 79. 何か作りませんか?
    共同開発者募集中
  • 80. ご清聴ありがとうございました
  • 81. 参考書籍、サイトなど
    http://framework.zend.com/manual
    Patterns of Enterprise Application Architecture エンタープライズアーキテクチャパターン: マーチン・ハウラー著 長瀬嘉秀 監訳
    Domain-Driven Design: Tackling Complexity in the Heart of Software :Eric Evans著
    http://www.martinfowler.com/eaaCatalog/transactionScript.html
    • http://www.slideshare.net/bngsudheer/framework-shootout-zf
    http://cwe.mitre.org/top25/
    http://www.ipa.go.jp/
    http://www.2ch.net
    http://weierophinney.net/matthew/archives/201-Applying-ACLs-to-Models.html
    http://www.slideshare.net/weierophinney/architecting-ajax-applications-with-zend-framework
    http://www.oplabo.jp/article/44
    http://www.live-commerce.com/
    http://omeka.org/
    http://tomatocms.com/