Site cover image
セキュア・バイ・デザインを学ぶ ~ ドメイン・プリミティブ / domain primitive ~

先日、「値オブジェクト」について記事を書きましたが、ドメイン・プリミティブなるものもあることを知り学習してみました。

その内容をまとめたものになります。

先日のブログポストはこちら

📄Arrow icon of a page linkDDDを学ぶ ~ 値オブジェクト ~

ドメイン・プリミティブとは、セキュア・バイ・デザイン 安全なソフトウェア設計 で登場する設計手法で、「値オブジェクト」と「不変条件」と呼ばれる制約を組み合わせたものです。

「値オブジェクト」については 📄Arrow icon of a page linkDDDを学ぶ ~ 値オブジェクト ~ で書きました。

では、「不変条件」とは何なのでしょうか?

「不変条件」とは、オブジェクトが守らなければならない条件のことです。

(より厳密に言うと「オブジェクトが生成されてから消滅するまで常に守らなければならない条件」とされています。)

つまり、ドメイン・プリミティブを簡単に言うと「値オブジェクトにバリデーション等の条件を持たせたもの」ということができます。

値オブジェクトに条件を持たせることで、安心して使える値オブジェクトを作り出すことができ、 値オブジェクトのメリット で紹介したように「安全性」「可読性」「保守性」を高めることができます。

ここで面白い点としては、「セキュア・バイ・デザイン」はセキュリティについての本であり、ドメイン・プリミティブがセキュリティを向上させる手法として紹介されているということです。

単にクリーンなコードを書くための手法ではなく、セキュリティを向上させ安全性を高めるものとされています。

いったい、値オブジェクトであるドメイン・プリミティブが、セキュリティを向上させるというのはどういうことでしょうか?

この主張を理解するためには、セキュア・バイ・デザインのコンセプトを知る必要があります。

「セキュア・バイ・デザイン」では、以下のような主張がされています。(一部要約・意訳・省略しています)

セキュリティを担保することを考えたときに、よく採用される考え方がセキュリティの優先度をもっとも高くする、ということです。
このアプローチでは、開発者はXSS攻撃のような脅威についての知識を持っていなければならず、低レイヤーのプロトコルにおける脆弱性に注意を払い、あらゆるセキュリティについての知識やテクニックを習得している必要があります。

このアプローチが成立していたのはセキュリティに関する脆弱性が今ほど多くない時代の話であり、このアプローチで解決できるのであれば過去に問題となった脆弱性による侵害が今でも繰り返し起こるはずがありません。
開発者に常にセキュリティを意識させ、同等の知識を持つことを求めるのは無理があります。

これは、セキュリティは重要ではない、ということを言いたいわけではなく、別のアプローチがある、ということなのです。
その別のアプローチとは、ソフトウェアの開発において、セキュリティを中心に考えるのではなく、設計を中心に考えることです。
意識する対象を設計に移すことで、セキュリティを常に意識続けることなくソフトウェアの安全性を高い水準で確立できるようになります。

つまり、良い設計をすることでセキュリティが向上させられるのだ、ということです。

そして、実際に設計を中心に考えることでセキュリティを向上させられる例として、ドメイン・プリミティブの利用があげられています。

例えば、ユーザ名を画面に表示する典型的なWebアプリケーションを考えます。
User クラスが以下のようなシンプルな作りだったとします。

public class User {
  public User(final Long id, final String username) {
    this.id = id;
    this.username = username;
  }
}

このような実装の場合、もし攻撃者がユーザ名として <script>何かしらのスクリプト</script> と登録したらどうなるでしょうか?悪意のあるコードが実装されてしまいます。

そこでもし、username として、ドメイン・プリミティブを利用していたらどうなるでしょうか?

public class UserName {
  private static final String VALID_CHARACTERS = “[A-Za-z0-9_-]+”;

  public Username(final String value) {
    validate(value, VALID_CHARACTERS)
    this.value = value
  }
}

もはや <script>何かしらのスクリプト</script> という値は許可されなくなります。

そして、ここで注目して欲しいのが、セキュリティについてまだ考え始めてもいないということです。

つまり、優れた設計を行うことで気が付かないうちにセキュリティに関する多くのバグを取り除くことができ、ドメイン・プリミティブもそれを実現する手法の一つだということになります。

これを聞くとデータを受け取る場所でバリデーションをおこなっても同じことでは?と思いますが、書籍ではドメイン・モデルにバリデーションを持たせることで、効率的にかつ自動的に安全で読みやすいコードを作ることができる、と主張しています。

確かに、モデルを厳密にしておけば、バグが少なくなって結果セキュリティも向上するだろうなというのは理解できそうです。

では次に、一体どんな条件を値オブジェクトに持たせるのが良いのか?を見ていきます。

書籍では、ドメイン・プリミティブに限らず、以下の安全性を確立する実装テクニックを満たすことで、さまざまなセキュリティの問題を取り除くことができるとしています。

  • 不変性(immutability)
  • 速やかな失敗(fail-fast)
  • 妥当性確認(validation)

値オブジェクトはすでに不変性を持っているので、条件として組み込むのは下2つの要素となります。

オブジェクトを可変にした場合、フィールドの値が意図しないタイミングで値が変わる可能性があり、完全性に関わるリスクを負うことになります。

また、可変性は特にマルチスレッド処理で可用性の問題として発生することがあります。

マルチスレッド環境では安全に処理を行うために適切にロックをかける必要がありますが、それは実装に複雑さを持ち込み、スレッド競合が起きる可用性のリスクを許容することになります。

オブジェクトを不変にすると、開発者は安心してその値を使うことができ、スレッド競合が発生する心配もありません。

何かしらの処理をする場合、通常それには実行するための事前条件があります。

例えば、レストランで特定のお客さんにお酒を提供するには、お客さんが成人しているかどうか、運転する予定がないか、の確認を満たす必要があります。

serve_beer というメソッドがあったとすると、処理を実行する前に事前条件を満たしているか確認し、満たしていない場合は速やかに失敗させることで安全性を高めることができます。

データ自身の妥当性確認はもちろんですが、さまざまな種類の妥当性確認をすることで、安全を向上させることができます。

書籍では、妥当性確認の種類として、以下の5つをあげています。

  1. オリジン(発生源)ー 正当な送信元から送られてきたデータなのか?
  2. サイズ ー データのサイズは適切か?
  3. 字句的内容(lexical content) ー データを構成している文字は正当な文字だけを使っており、正しくエンコードされているのか?
  4. 構文(syntax) ー データは正しいフォーマットに沿っているか?
  5. 意味(semantics) ー そのデータは意味的に正しいものなのか?

1を値オブジェクトに組み込むことは難しいので、他4つを組み込んでいくことになります。

データ送信元の確認。

    • IPアドレスでのアクセス制限
    • アクセス・キーでのアクセス制限

データサイズの確認。

    • 郵便番号: 7桁である
    • ファイル:想定しているファイルサイズの上限値に収まっているか

データが想定している文字だけを含んでいるか、想定したエンコードが使われているかの確認。

    • 郵便番号:数字と - だけである

データが正しいフォーマットと構造になっているかの確認。

    • 郵便番号: [0-9]{3}\-[0-9]{4} のフォーマットであるか
    • JSONやXML:正しくパースできるのか

データが健全なもので、システムの他の部分と整合性が取れているのかの確認。

    • 郵便番号:郵便局のデータに存在している番号なのか
    • ユーザーID:他のユーザーと重複していないか

この5つの妥当性確認は重複している要素もありますが、上にあるものほど確認負荷が低く下のものほど確認負荷が高くなるように並べられており、上の条件から確認していくのが良いとされています。

まとめると、ドメイン・プリミティブとは、「速やかな失敗」や「妥当性確認」のような条件が実装された値オブジェクト、ということになります。

値オブジェクトに条件を追加することで、自然に不正な状態を防止し、開発者は安心してオブジェクトを利用することができるようになります。

ドメイン・プリミティブを学ぶために、セキュア・バイ・デザインを読んでみましたが、非常に面白いコンセプトだなと感じました。(通常のセキュリティ対策も重要だ!とも言っており、あくまで堅牢な設計をするための本という印象ですが)

セキュリティ対策を徹底したところで、どこか設計がまずければ穴が空いてしまうというのは、個人的には納得感がありました。

ドメイン・プリミティブも、どこまでやるの?という話はありますが、開発者にとって安全性・可読性・保守性が上がるという点でだけでも導入してみたいなと思いました。

今回、ドメイン・プリミティブの定義に関するところだけを取り上げましたが、セキュア・バイ・デザインではじゃあエンティティはどうするの?や他の安全性の高いテクニックも書いてあるようなので、引き続き読んでみようと思います。

それでは。

📄Arrow icon of a page linkDDDを学ぶ ~ 値オブジェクト ~

Thank you!
Thank you!
URLをコピーしました

コメントを送る

コメントはブログオーナーのみ閲覧できます