狠狠撸

狠狠撸Share a Scribd company logo
はてなブックマークにおけるアクセス制御
半環構造に基づくモデル化
伊奈 林太郎
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(visitor))
Some(bookmark)
else None
少し複雑なアクセス制御
? 閲覧許可ユーザの設定
? 本人に加えて許可された人にも見える
愚直なコード
if (bookmark.owner == visitor ||
bookmark.owner.allowedUsers.contains(visitor))
Some(bookmark)
else None
? 少し複雑
? そのうちチェックしわすれが発生
少し複雑なアクセス制御
? 閲覧許可ユーザの設定
? 本人に加えて許可された人にも見える
愚直なコード
if (bookmark.owner == visitor ||
bookmark.owner.allowedUsers.contains(visitor))
Some(bookmark)
else None
? 少し複雑
? そのうちチェックしわすれが発生
なにか統一的に扱いたい
アクセス制御のモデル
属性 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 = ?
例
ユーザ 閲覧許可 要求 許可
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
アクセス制御のモデル
属性 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)
? オブジェクト型ごとの一貫したメンテが可能
アクセス制御のモデル
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)
? 権限の強弱関係が束をなす
もっと複雑なアクセス制御
? 個別のブックマークを非公開にできる
? 閲覧許可ユーザにも見えない
もっと複雑なアクセス制御
? 個別のブックマークを非公開にできる
? 閲覧許可ユーザにも見えない
愚直なコード
if (bookmark.owner == visitor ||
(bookmark.owner.allowedUsers.contains(visitor) &&
bookmark.isPublic))
Some(bookmark)
else None
もっと複雑なアクセス制御
? 個別のブックマークを非公開にできる
? 閲覧許可ユーザにも見えない
愚直なコード
if (bookmark.owner == visitor ||
(bookmark.owner.allowedUsers.contains(visitor) &&
bookmark.isPublic))
Some(bookmark)
else None
? LBAC では表現不能
もっと複雑なアクセス制御
? 個別のブックマークを非公開にできる
? 閲覧許可ユーザにも見えない
愚直なコード
if (bookmark.owner == visitor ||
(bookmark.owner.allowedUsers.contains(visitor) &&
bookmark.isPublic))
Some(bookmark)
else None
? LBAC では表現不能
(※実際はあと 5 段階くらい複雑)
もっと複雑なアクセス制御
? 個別のブックマークを非公開にできる
? 閲覧許可ユーザにも見えない
愚直なコード
if (bookmark.owner == visitor ||
(bookmark.owner.allowedUsers.contains(visitor) &&
bookmark.isPublic))
Some(bookmark)
else None
? LBAC では表現不能
(※実際はあと 5 段階くらい複雑)
もっとよいモデル化が必要
アクセス制御のよいモデル
属性 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}
アクセス制御のよいモデル
属性 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) の属性
アクセス制御のよいモデル
属性 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
半環構造の妥当性
もしこう書いてしまったら?
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
半環構造の妥当性
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
半環構造の妥当性
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 (部分適用)
半環構造の妥当性
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
出典
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 ?ow control for relational data.
In 30th ACM/SIGAPP SAC, 2015.
実装戦略
基本戦略
Controller Business Logic
Domain Logic
Infrastructure
HTTP
(Adapter)
Application
Service
CLI
(Adapter)
Domain
Model
Repository
Interface
Domain
Service
Database
External
Service
複数層に権限チェックを分離可能 (∵ 準同型定理)
? アプリ層 : 前提条件でフィルタ
? ドメイン層 : 完全な権限チェック
? インフラ層 : 効率化のためのフィルタ
各層でのチェック
アプリ層 : 前提条件でフィルタ
? (例) 非公開ユーザのページは他人に見せない
ドメイン層 : 完全な権限チェック
? ? された完全な権限をチェック
? アクセス制御の完全性はこの層に集中させる
インフラ層 : 効率化のためのフィルタ
? 権限の要求を検索クエリに対応させる
? 各テーブルごとでよい
? 完全でなくてよい
整合性のための工夫
一貫性
? 属性へのマッピングは一箇所で定義
? 同じ型には同じ方法で要求/許可が決まる
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)) }
整合性のための工夫
完全性
? 許可の可否のための完全な情報を使用
? (例) ブックマークの閲覧にはユーザの閲覧許可も必要
// ユーザ閲覧可否なしにブックマーク閲覧可否だけ調べるのは禁止
private def permissionOf(bookmark: Bookmark): Permission = ...
// ブックマーク閲覧可否は以下の 2 つの合成
// - 持ち主のユーザ閲覧可否
// - ブックマークアイテムそのものの閲覧可否
def permissionOf(pair: (User, Bookmark)): Permission =
permissionOf(user = pair._1) & // ユーザ
permissionOf(bookmark = pair._2) // ブックマークそのもの
検索クエリとの対応
クエリとの対応
? インフラ層での 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
完全 vs. テーブルごと
permissionOf(user)& permissionOf(bookmark)
? JOIN が必要
? user テーブルと bookmarkテーブル
? 条件が複雑
? AND 条件と OR 条件
テーブルごとにチェック
? bookmarkテーブルの検索時は
permissionOf(bookmark)だけチェック
? permissionOf(user)は別の層でチェック
? 準同型定理が活かされる
その他の効率化
和積形
許可は和積形 p′
でも表せる
? user : 本人 ⊕ 閲覧許可ユーザ
? bookmark : 本人 (非公開の場合)
? 全体: (本人 ⊕ 閲覧許可ユーザ) ? (本人)
和積形のままチェック
? p′
allows r ? ?q ∈ p′
. q ∩ r = ?
? 積和形のチェックと同値
p′
allows r ? p allows r
和積形
許可は和積形 p′
でも表せる
? user : 本人 ⊕ 閲覧許可ユーザ
? bookmark : 本人 (非公開の場合)
? 全体: (本人 ⊕ 閲覧許可ユーザ) ? (本人)
和積形のままチェック
? p′
allows r ? ?q ∈ p′
. q ∩ r = ?
? 積和形のチェックと同値
p′
allows r ? p allows r
?時に?を計算する必要はない
まとめ
モデル化
? AND/OR 条件を属性の半環で表現
? チェック関数はブール代数への準同型写像
実装戦略
? 準同型定理を利用してチェック処理を分離
? 要求/許可は一元管理
? 完全性の担保はドメインロジックに集中
効率化
? 要求をテーブルへのクエリ条件にしてフィルタ
? 和積形の利用で無駄な計算をしないように

More Related Content

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