はてなブックマークにおけるアクセス制御
半環構造に基づくモデル化
伊奈 林太郎
id:tarao @oarat
2015-11-24
@ WebDB Forum 2015
◮ 国内最大のソーシャルブックマークサービス
◮ 国内最大のソーシャルブックマークサービス
◮ Scala でいちから作り直すプロジェクトが進行中
DISCLAIMER
◮ 内容は開発中のもの
◮ 実際のリリース時には変更の可能性あり
◮ 最終的にどうなったか公表するかどうか未定
話すこと
◮ B!のアクセス制御はかなり複雑
◮ さまざまな画面/設定
◮ AND/OR 条件
◮ 統一的なモデル化でバグの作り込みを避けたい
◮ モデルの数学的な正しさ
◮ コード上で一貫して扱うしくみ
◮ 効率化したい
◮ DB クエリ等で...
アクセス制御のモデル化
単純なアクセス制御
◮ 非公開ユーザの設定
◮ ブックマークが他人からは見えなくなる
◮ 本人にはもちろん見える
単純なアクセス制御
◮ 非公開ユーザの設定
◮ ブックマークが他人からは見えなくなる
◮ 本人にはもちろん見える
コード
if (bookmark.owner == visitor)
Some(bookmark)
else None
少し複雑なアクセス制御
◮ 閲覧許可ユーザの設定
◮ 本人に加えて許可された人にも見える
少し複雑なアクセス制御
◮ 閲覧許可ユーザの設定
◮ 本人に加えて許可された人にも見える
愚直なコード
if (bookmark.owner == visitor ||
bookmark.owner.allowedUsers.contains(...
少し複雑なアクセス制御
◮ 閲覧許可ユーザの設定
◮ 本人に加えて許可された人にも見える
愚直なコード
if (bookmark.owner == visitor ||
bookmark.owner.allowedUsers.contains(...
少し複雑なアクセス制御
◮ 閲覧許可ユーザの設定
◮ 本人に加えて許可された人にも見える
愚直なコード
if (bookmark.owner == visitor ||
bookmark.owner.allowedUsers.contains(...
アクセス制御のモデル
属性 A の羃で表現
要求 r ∈ P(A) = requestOf(viewer)
許可 p ∈ P(A) = permissionOf(target)
確認 p allows r ⇔ p ∩ r = ∅
アクセス制御のモデル
属性 A の羃で表現
要求 r ∈ P(A) = requestOf(viewer)
許可 p ∈ P(A) = permissionOf(target)
確認 p allows r ⇔ p ∩ r = ∅
例
ユーザ 閲...
アクセス制御のモデル
属性 A の羃で表現
要求 r ∈ P(A) = requestOf(viewer)
許可 p ∈ P(A) = permissionOf(target)
確認 p allows r ⇔ p ∩ r = ∅
コードによる表...
アクセス制御のモデル
r {a, b, c}
r {a, b} {a, c} {b, c}
r {a} {b} {c}
p {a} {b} {c}
p {a, b} {a, c} {b, c}
p {a, b, c}
◮ Lattice-bas...
もっと複雑なアクセス制御
◮ 個別のブックマークを非公開にできる
◮ 閲覧許可ユーザにも見えない
もっと複雑なアクセス制御
◮ 個別のブックマークを非公開にできる
◮ 閲覧許可ユーザにも見えない
愚直なコード
if (bookmark.owner == visitor ||
(bookmark.owner.allowedUsers.cont...
もっと複雑なアクセス制御
◮ 個別のブックマークを非公開にできる
◮ 閲覧許可ユーザにも見えない
愚直なコード
if (bookmark.owner == visitor ||
(bookmark.owner.allowedUsers.cont...
もっと複雑なアクセス制御
◮ 個別のブックマークを非公開にできる
◮ 閲覧許可ユーザにも見えない
愚直なコード
if (bookmark.owner == visitor ||
(bookmark.owner.allowedUsers.cont...
もっと複雑なアクセス制御
◮ 個別のブックマークを非公開にできる
◮ 閲覧許可ユーザにも見えない
愚直なコード
if (bookmark.owner == visitor ||
(bookmark.owner.allowedUsers.cont...
アクセス制御のよいモデル
属性 A の半環で許可を表現
要求 r ∈ P(A) = requestOf(viewer)
許可 p ∈ P(P(A)) = permissionOf(target)
確認 p allows r ⇔ ∃q ∈ p. ...
アクセス制御のよいモデル
属性 A の半環で許可を表現
要求 r ∈ P(A) = requestOf(viewer)
許可 p ∈ P(P(A)) = permissionOf(target)
確認 p allows r ⇔ ∃q ∈ p. ...
アクセス制御のよいモデル
属性 A の半環で許可を表現
要求 r ∈ P(A) = requestOf(viewer)
許可 p ∈ P(P(A)) = permissionOf(target)
確認 p allows r ⇔ ∃q ∈ p. ...
半環構造の妥当性
もしこう書いてしまったら?
val r = requestOf(visitor)
val p1 = permissionOf(bookmark.owner)
val p2 = permissionOf(bookmark)
if...
半環構造の妥当性
Theorem (ブール代数への準同型写像)
∀r. allows r : P(P(A)) → B は準同型写像
もしこう書いてしまったら? → OK!
val r = requestOf(visitor)
val p1 = ...
半環構造の妥当性
Theorem (ブール代数への準同型写像)
∀r. allows r : P(P(A)) → B は準同型写像
注意
◮ B, ∨, ∧, ⊥, ⊤ : ブール代数
◮ p allows r : B
◮ allows : P...
半環構造の妥当性
Theorem (ブール代数への準同型写像)
∀r. allows r : P(P(A)) → B は準同型写像
p1, p2 p1 ⊗ p2
p1 allows r,
p2 allows r
(p1 ⊗ p2) allows...
出典
G. Karvounarakis and T. J. Green.
Semiring-annotated data: Queries and
provenance?
SIGMOD Record, 41(3):5–14, 2012.
R. ...
実装戦略
基本戦略
Controller Business Logic
Domain Logic
Infrastructure
HTTP
(Adapter)
Application
Service
CLI
(Adapter)
Domain
Model
R...
各層でのチェック
アプリ層 : 前提条件でフィルタ
◮ (例) 非公開ユーザのページは他人に見せない
ドメイン層 : 完全な権限チェック
◮ ⊗ された完全な権限をチェック
◮ アクセス制御の完全性はこの層に集中させる
インフラ層 : 効率化の...
整合性のための工夫
一貫性
◮ 属性へのマッピングは一箇所で定義
◮ 同じ型には同じ方法で要求/許可が決まる
def requestOf(user: User): Request = user.accountId match {
case Ac...
整合性のための工夫
完全性
◮ 許可の可否のための完全な情報を使用
◮ (例) ブックマークの閲覧にはユーザの閲覧許可も必要
// ユーザ閲覧可否なしにブックマーク閲覧可否だけ調べるのは禁止
private def permissionOf(b...
検索クエリとの対応
クエリとの対応
◮ インフラ層での MySQLや Elasticsearch のクエリ
◮ 許可されないレコードは除いて効率化
◮ 要求 → クエリ断片への変換を用意すればよい
val r = requestOf(visitor)
// => ...
完全 vs. テーブルごと
permissionOf(user)& permissionOf(bookmark)
◮ JOIN が必要
◮ user テーブルと bookmarkテーブル
◮ 条件が複雑
◮ AND 条件と OR 条件
テーブル...
その他の効率化
和積形
許可は和積形 p′
でも表せる
◮ user : 本人 ⊕ 閲覧許可ユーザ
◮ bookmark : 本人 (非公開の場合)
◮ 全体: (本人 ⊕ 閲覧許可ユーザ) ⊗ (本人)
和積形のままチェック
◮ p′
allows r ⇔ ...
和積形
許可は和積形 p′
でも表せる
◮ user : 本人 ⊕ 閲覧許可ユーザ
◮ bookmark : 本人 (非公開の場合)
◮ 全体: (本人 ⊕ 閲覧許可ユーザ) ⊗ (本人)
和積形のままチェック
◮ p′
allows r ⇔ ...
まとめ
モデル化
◮ AND/OR 条件を属性の半環で表現
◮ チェック関数はブール代数への準同型写像
実装戦略
◮ 準同型定理を利用してチェック処理を分離
◮ 要求/許可は一元管理
◮ 完全性の担保はドメインロジックに集中
効率化
◮ 要求を...
はてなブックマークにおけるアクセス制御 - 半環構造に基づくモデル化
Upcoming SlideShare
Loading in...5
×

はてなブックマークにおけるアクセス制御 - 半環構造に基づくモデル化

0
-1

Published on

はてなブックマークの持つデータには多岐にわたるアクセス制御のための属性があり、一貫した権限確認のしくみが必要となる。できる限り効率的にデータを取得するにはクエリ段階でアクセス制御に基づくフィルタリングが必要となるが、たとえばMySQLで取得した場合とElasticsearchで取得した場合など、複数パスでの整合性も求められる。本発表では、半環構造を用いることで整合性を担保するしくみと、一貫性を保つためのScalaでの実装上の工夫を紹介する。

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
0
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
0
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

はてなブックマークにおけるアクセス制御 - 半環構造に基づくモデル化

  1. 1. はてなブックマークにおけるアクセス制御 半環構造に基づくモデル化 伊奈 林太郎 id:tarao @oarat 2015-11-24 @ WebDB Forum 2015
  2. 2. ◮ 国内最大のソーシャルブックマークサービス
  3. 3. ◮ 国内最大のソーシャルブックマークサービス ◮ Scala でいちから作り直すプロジェクトが進行中
  4. 4. DISCLAIMER ◮ 内容は開発中のもの ◮ 実際のリリース時には変更の可能性あり ◮ 最終的にどうなったか公表するかどうか未定
  5. 5. 話すこと ◮ B!のアクセス制御はかなり複雑 ◮ さまざまな画面/設定 ◮ AND/OR 条件 ◮ 統一的なモデル化でバグの作り込みを避けたい ◮ モデルの数学的な正しさ ◮ コード上で一貫して扱うしくみ ◮ 効率化したい ◮ DB クエリ等で権限に応じたフィルタリング
  6. 6. アクセス制御のモデル化
  7. 7. 単純なアクセス制御 ◮ 非公開ユーザの設定 ◮ ブックマークが他人からは見えなくなる ◮ 本人にはもちろん見える
  8. 8. 単純なアクセス制御 ◮ 非公開ユーザの設定 ◮ ブックマークが他人からは見えなくなる ◮ 本人にはもちろん見える コード if (bookmark.owner == visitor) Some(bookmark) else None
  9. 9. 少し複雑なアクセス制御 ◮ 閲覧許可ユーザの設定 ◮ 本人に加えて許可された人にも見える
  10. 10. 少し複雑なアクセス制御 ◮ 閲覧許可ユーザの設定 ◮ 本人に加えて許可された人にも見える 愚直なコード if (bookmark.owner == visitor || bookmark.owner.allowedUsers.contains(visitor)) Some(bookmark) else None
  11. 11. 少し複雑なアクセス制御 ◮ 閲覧許可ユーザの設定 ◮ 本人に加えて許可された人にも見える 愚直なコード if (bookmark.owner == visitor || bookmark.owner.allowedUsers.contains(visitor)) Some(bookmark) else None ◮ 少し複雑 ◮ そのうちチェックしわすれが発生
  12. 12. 少し複雑なアクセス制御 ◮ 閲覧許可ユーザの設定 ◮ 本人に加えて許可された人にも見える 愚直なコード if (bookmark.owner == visitor || bookmark.owner.allowedUsers.contains(visitor)) Some(bookmark) else None ◮ 少し複雑 ◮ そのうちチェックしわすれが発生 なにか統一的に扱いたい
  13. 13. アクセス制御のモデル 属性 A の羃で表現 要求 r ∈ P(A) = requestOf(viewer) 許可 p ∈ P(A) = permissionOf(target) 確認 p allows r ⇔ p ∩ r = ∅
  14. 14. アクセス制御のモデル 属性 A の羃で表現 要求 r ∈ P(A) = requestOf(viewer) 許可 p ∈ P(A) = permissionOf(target) 確認 p allows r ⇔ p ∩ r = ∅ 例 ユーザ 閲覧許可 要求 許可 u1 なし {u1} {u1} u2 u1, u3 {u2} {u1, u2, u3} u3 u2 {u3} {u2, u3} permissionOf(u1) allows requestOf(u2) = false permissionOf(u2) allows requestOf(u3) = true permissionOf(u3) allows requestOf(u1) = false
  15. 15. アクセス制御のモデル 属性 A の羃で表現 要求 r ∈ P(A) = requestOf(viewer) 許可 p ∈ P(A) = permissionOf(target) 確認 p allows r ⇔ p ∩ r = ∅ コードによる表現 val r = requestOf(visitor) val p = permissionOf(bookmark.owner) if (p allows r) Some(bookmark) else None ◮ オブジェクトから属性集合へのマッピング (permissionOf, requestOf) ◮ オブジェクト型ごとの一貫したメンテが可能
  16. 16. アクセス制御のモデル r {a, b, c} r {a, b} {a, c} {b, c} r {a} {b} {c} p {a} {b} {c} p {a, b} {a, c} {b, c} p {a, b, c} ◮ Lattice-based access control (LBAC) ◮ 権限の強弱関係が束をなす
  17. 17. もっと複雑なアクセス制御 ◮ 個別のブックマークを非公開にできる ◮ 閲覧許可ユーザにも見えない
  18. 18. もっと複雑なアクセス制御 ◮ 個別のブックマークを非公開にできる ◮ 閲覧許可ユーザにも見えない 愚直なコード if (bookmark.owner == visitor || (bookmark.owner.allowedUsers.contains(visitor) && bookmark.isPublic)) Some(bookmark) else None
  19. 19. もっと複雑なアクセス制御 ◮ 個別のブックマークを非公開にできる ◮ 閲覧許可ユーザにも見えない 愚直なコード if (bookmark.owner == visitor || (bookmark.owner.allowedUsers.contains(visitor) && bookmark.isPublic)) Some(bookmark) else None ◮ LBAC では表現不能
  20. 20. もっと複雑なアクセス制御 ◮ 個別のブックマークを非公開にできる ◮ 閲覧許可ユーザにも見えない 愚直なコード if (bookmark.owner == visitor || (bookmark.owner.allowedUsers.contains(visitor) && bookmark.isPublic)) Some(bookmark) else None ◮ LBAC では表現不能 (※実際はあと 5 段階くらい複雑)
  21. 21. もっと複雑なアクセス制御 ◮ 個別のブックマークを非公開にできる ◮ 閲覧許可ユーザにも見えない 愚直なコード if (bookmark.owner == visitor || (bookmark.owner.allowedUsers.contains(visitor) && bookmark.isPublic)) Some(bookmark) else None ◮ LBAC では表現不能 (※実際はあと 5 段階くらい複雑) もっとよいモデル化が必要
  22. 22. アクセス制御のよいモデル 属性 A の半環で許可を表現 要求 r ∈ P(A) = requestOf(viewer) 許可 p ∈ P(P(A)) = permissionOf(target) 確認 p allows r ⇔ ∃q ∈ p. q ⊆ r 半環 P(P(A)), ⊕, ⊗, ∅, {∅} ◮ p1 ⊕ p2 = p1 ∪ p2 ◮ p1 ⊗ p2 = p1 ⋒ p2 = {q1 ∪ q2 | q1 ∈ p1 ∧ q2 ∈ p2}
  23. 23. アクセス制御のよいモデル 属性 A の半環で許可を表現 要求 r ∈ P(A) = requestOf(viewer) 許可 p ∈ P(P(A)) = permissionOf(target) 確認 p allows r ⇔ ∃q ∈ p. q ⊆ r 半環 P(P(A)), ⊕, ⊗, ∅, {∅} ◮ p1 ⊕ p2 = p1 ∪ p2 ◮ p1 ⊗ p2 = p1 ⋒ p2 = {q1 ∪ q2 | q1 ∈ p1 ∧ q2 ∈ p2} 直感 ◮ p = {{a1, a2}, {a3}, {a4, a5}} ◮ (a1 かつ a2) または a3 または (a4 かつ a5) の属性
  24. 24. アクセス制御のよいモデル 属性 A の半環で許可を表現 要求 r ∈ P(A) = requestOf(viewer) 許可 p ∈ P(P(A)) = permissionOf(target) 確認 p allows r ⇔ ∃q ∈ p. q ⊆ r 半環 P(P(A)), ⊕, ⊗, ∅, {∅} ◮ p1 ⊕ p2 = p1 ∪ p2 ◮ p1 ⊗ p2 = p1 ⋒ p2 = {q1 ∪ q2 | q1 ∈ p1 ∧ q2 ∈ p2} コードによる表現 val r = requestOf(visitor) val p1 = permissionOf(bookmark.owner) val p2 = permissionOf(bookmark) val p = p1 & p2 // p1 ⊗ p2 if (p allows r) Some(bookmark) else None
  25. 25. 半環構造の妥当性 もしこう書いてしまったら? val r = requestOf(visitor) val p1 = permissionOf(bookmark.owner) val p2 = permissionOf(bookmark) if (p1 allows r) { if (p2 allows r) Some(bookmark) else None } else None
  26. 26. 半環構造の妥当性 Theorem (ブール代数への準同型写像) ∀r. allows r : P(P(A)) → B は準同型写像 もしこう書いてしまったら? → OK! val r = requestOf(visitor) val p1 = permissionOf(bookmark.owner) val p2 = permissionOf(bookmark) if (p1 allows r) { if (p2 allows r) Some(bookmark) else None } else None
  27. 27. 半環構造の妥当性 Theorem (ブール代数への準同型写像) ∀r. allows r : P(P(A)) → B は準同型写像 注意 ◮ B, ∨, ∧, ⊥, ⊤ : ブール代数 ◮ p allows r : B ◮ allows : P(P(A)) → P(A) → B ◮ allows r : P(P(A)) → B (部分適用)
  28. 28. 半環構造の妥当性 Theorem (ブール代数への準同型写像) ∀r. allows r : P(P(A)) → B は準同型写像 p1, p2 p1 ⊗ p2 p1 allows r, p2 allows r (p1 ⊗ p2) allows r p1 allows r ∧ p2 allows r ⊗ allows r allows r ∧ ◮ 条件を分解してチェックしても OK
  29. 29. 出典 G. Karvounarakis and T. J. Green. Semiring-annotated data: Queries and provenance? SIGMOD Record, 41(3):5–14, 2012. R. Thion, F. Lesueur, and M. Talbi. Tuple-based access control: a provenance-based information flow control for relational data. In 30th ACM/SIGAPP SAC, 2015.
  30. 30. 実装戦略
  31. 31. 基本戦略 Controller Business Logic Domain Logic Infrastructure HTTP (Adapter) Application Service CLI (Adapter) Domain Model Repository Interface Domain Service Database External Service 複数層に権限チェックを分離可能 (∵ 準同型定理) ◮ アプリ層 : 前提条件でフィルタ ◮ ドメイン層 : 完全な権限チェック ◮ インフラ層 : 効率化のためのフィルタ
  32. 32. 各層でのチェック アプリ層 : 前提条件でフィルタ ◮ (例) 非公開ユーザのページは他人に見せない ドメイン層 : 完全な権限チェック ◮ ⊗ された完全な権限をチェック ◮ アクセス制御の完全性はこの層に集中させる インフラ層 : 効率化のためのフィルタ ◮ 権限の要求を検索クエリに対応させる ◮ 各テーブルごとでよい ◮ 完全でなくてよい
  33. 33. 整合性のための工夫 一貫性 ◮ 属性へのマッピングは一箇所で定義 ◮ 同じ型には同じ方法で要求/許可が決まる def requestOf(user: User): Request = user.accountId match { case AccountId.Guest => Request(Attribute.Public) case _ => Request( Attribute.Public, Attribute.User(user.id)) } def permissionOf(user: User): Permission = user.status match { case User.Status.Private => Permission( Attribute.User(user.id) +: user.allowedUsers.map(u => Attribute.User(u.id)): _*) case User.Status.Public => Permission( Attribute.Public, Attribute.User(user.id)) }
  34. 34. 整合性のための工夫 完全性 ◮ 許可の可否のための完全な情報を使用 ◮ (例) ブックマークの閲覧にはユーザの閲覧許可も必要 // ユーザ閲覧可否なしにブックマーク閲覧可否だけ調べるのは禁止 private def permissionOf(bookmark: Bookmark): Permission = ... // ブックマーク閲覧可否は以下の 2 つの合成 // - 持ち主のユーザ閲覧可否 // - ブックマークアイテムそのものの閲覧可否 def permissionOf(pair: (User, Bookmark)): Permission = permissionOf(user = pair._1) & // ユーザ permissionOf(bookmark = pair._2) // ブックマークそのもの
  35. 35. 検索クエリとの対応
  36. 36. クエリとの対応 ◮ インフラ層での MySQLや Elasticsearch のクエリ ◮ 許可されないレコードは除いて効率化 ◮ 要求 → クエリ断片への変換を用意すればよい val r = requestOf(visitor) // => Request(Attribute.User(u)) val user: Option[User] = db.run { sql""" SELECT * FROM user LEFT JOIN allowing ON user.id = allowing.user_id WHERE user.status = 'public' OR user.id = $u OR allowing.allowed_user_id = $u """.as[User] }.headOption
  37. 37. 完全 vs. テーブルごと permissionOf(user)& permissionOf(bookmark) ◮ JOIN が必要 ◮ user テーブルと bookmarkテーブル ◮ 条件が複雑 ◮ AND 条件と OR 条件 テーブルごとにチェック ◮ bookmarkテーブルの検索時は permissionOf(bookmark)だけチェック ◮ permissionOf(user)は別の層でチェック ◮ 準同型定理が活かされる
  38. 38. その他の効率化
  39. 39. 和積形 許可は和積形 p′ でも表せる ◮ user : 本人 ⊕ 閲覧許可ユーザ ◮ bookmark : 本人 (非公開の場合) ◮ 全体: (本人 ⊕ 閲覧許可ユーザ) ⊗ (本人) 和積形のままチェック ◮ p′ allows r ⇔ ∀q ∈ p′ . q ∩ r = ∅ ◮ 積和形のチェックと同値 p′ allows r ⇔ p allows r
  40. 40. 和積形 許可は和積形 p′ でも表せる ◮ user : 本人 ⊕ 閲覧許可ユーザ ◮ bookmark : 本人 (非公開の場合) ◮ 全体: (本人 ⊕ 閲覧許可ユーザ) ⊗ (本人) 和積形のままチェック ◮ p′ allows r ⇔ ∀q ∈ p′ . q ∩ r = ∅ ◮ 積和形のチェックと同値 p′ allows r ⇔ p allows r ⊗時に⋒を計算する必要はない
  41. 41. まとめ モデル化 ◮ AND/OR 条件を属性の半環で表現 ◮ チェック関数はブール代数への準同型写像 実装戦略 ◮ 準同型定理を利用してチェック処理を分離 ◮ 要求/許可は一元管理 ◮ 完全性の担保はドメインロジックに集中 効率化 ◮ 要求をテーブルへのクエリ条件にしてフィルタ ◮ 和積形の利用で無駄な計算をしないように
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×