セキュリティと設計の関係についての学び(ドメイン・プリミティブ編)
最近、「セキュア・バイ・デザイン」という本を読み終わりました。なので、自分の中での理解を一部アウトプットしようと思います。
前回は「契約による設計」について書きました。
今回はドメイン・プリミティブのあたりを重点的に説明します。
ドメイン・プリミティブ
ドメイン・プリミティブをざっくり言うと、ドメイン駆動設計(DDD) でおなじみの値オブジェクトです。
もう少し詳しく説明すると、ドメイン・プリミティブとは値オブジェクトを不変条件(クラス不変表明)を持たせて、null であることを禁止したものです。
ドメイン・プリミティブを使うことにより、責任の所在が明確になりセキュリティ問題の可能性を大幅に取り除くことができます。
不変条件とは
不変条件とはいかなることが起こっても変わることのないオブジェクトの性質(ドメイン知識)を定めたものです。
たとえば、「年齢」というドメイン・プリミティブを作る場合は以下が不変条件になります。
- null ではないこと
- 整数であること
- 15 以上であること(15 歳以上を対象にしたサービス)
- 200 以下であること(ギネス最高記録が 119 歳なので余裕を持って 200 に設定)
ドメイン・プリミティブの例:年齢
class Age {
constructor(private _value: number) {
if (!Number.isInteger(_value)) throw new Error('年齢が整数ではありません')
if (_value > 200) throw new Error('年齢が最大値より高いです')
if (_value < 15) throw new Error('年齢が最小値より低いです')
}
}
契約による設計と組み合わせる
regist(id: string, name: string, age: number) {
// UserId(id)のコンストラクタ内でULIDのフォーマットなどの不変条件チェックを行っている
// Name(name)のコンストラクタ内で名前の最大長、最小長、文字の種類などの不変条件チェックを行っている
// Age(age)のコンストラクタ内で年齢の最大値、最小値、整数などの不変条件チェックを行っている
// new User(new Name(name), new UserId(id), new Age(age))のように名前とIDを入れ間違えることがない
const user = new User(new UserId(id), new Name(name), new Age(age))
if (this.userRepository.existByName(user.name)) throw new Error('ユーザーの名前はすでに存在する')
this.userRepository.add(new User(name))
}
delete(id: string) {
// UserId(id)のコンストラクタ内でULIDのフォーマットなどの不変条件チェックを行っている
const userId = new UserId(id)
this.userRepository.remove(userId)
}
不変条件の見つけ方
不変条件を書けと言われても、何を書けば良いのかわからない人も多いと思います。
業務知識は業務の数だけ存在し、全く同じということはないので、その都度考えていく必要があります。しかし、ある程度の基準はあると思っています。
お客さん(ドメインエキスパート)との打ち合わせのときに以下のことを質問することで、深い業務知識を得るきっかけになるかも知れません。
文字列の場合
- どれぐらいのサイズまで入れられるか?(文字数など)
- 使用できる文字はなにか?
- 文字のフォーマットは決まっているか?(YYYY-MM-DD、メールアドレス形式など)
数値の場合
- -1 を入れることはできるか?
- 0 を入れることはできるか?
- 1 を入れることはできるか?
- 2147483647 を入れることはできるか?
- 小数を入れることはできるか?
上記の他にも、国際標準がある場合は、それを参考にするのもありだと思います。しかし、業務知識と国際標準が違う場合もあるのでお客さんとのコミュニケーションで慎重に決めていくことが大事です。
さいごに
ドメイン・プリミティブを使うだけで劇的にセキュリティが改善されるはずです。しかし、自分の環境ではなかなか使われることがないです。
「良いコード/悪いコードで学ぶ設計入門」で書かれているプリミティブ型執着なのだと思っています。これに関しては根気よく啓蒙していくしか無いです。
「セキュア・バイ・デザイン」には今回紹介した以外にも有用な情報が沢山なので、ぜひ読んで実践してみてください。
Discussion