🎀

セキュリティと設計の関係についての学び(契約による設計編)

2022/07/02に公開

最近、「セキュア・バイ・デザイン」という本を読み終わりました。なので、自分の中での理解を一部アウトプットしようと思います。

正直、どの章も読みながらいろんなことを考えさせられる良書でした。その中でも基礎編の 4 章・5 章で説明される、ドメイン・プリミティブと契約による設計の部分が重要なのだと思っています。

今回は契約による設計について重点的に説明します。

そもそも設計とセキュリティになんの関係があるの?

セキュリティについて真剣に取り組もうと言っても、以下の理由でなかなかうまくいかないことが多いです。

  • エンジニアは設計に興味は持ってもセキュリティに興味は持ちにくい
  • どれだけセキュリティを意識しても、ゼロデイ攻撃など予期せぬ問題は起こる
  • セキュリティタスクは、他のタスクより優先度を低くされがち
  • セキュリティの専門家をプロジェクトのメンバーに加えるという考えにはなりにくい

「セキュア・バイ・デザイン」の著者は安全なソフトウェアを高効率、低コストで実現するには別のアプローチが必要になると考えました。

そこから導き出されたのが、セキュリティそのものに焦点を当てるのではなく、設計に目を向けることでセキュリティを上げるというアプローチです。

ドメインの知識を深く理解し、それをコードに落とし込み制約を作り込みます。それにより、ゼロデイ攻撃などの今まで想定になかった攻撃に対しても、防衛効果があると書かれてました。

また、フォームにundefined-1など想定にない値を入力するだけでも、サイトを落としたり会社に損害を与えることがあるので、設計が大事だということでした。

契約による設計

契約による設計とは、バートランド・メイヤー著の「ドメイン駆動設計入門 第 2 版 原則・コンセプト」で説明されている手法です。

コード上に事前条件、事後条件、クラス不変表明(不変条件)を書くことで、効果的に安全なソフトウェアを作ることが出きます。

セキュリティの問題は責任の所在が曖昧なせいで起こることが多いです。事前条件などを意識することによって、どれがなんの責任を負うのかを明確にすることができます。

契約とは

契約はメソッドが実行するための事前条件を設定し、メソッド実行後の状態を事後条件として設定することです。

例えばユーザー管理をするクラスがあった場合、以下の事前条件と事後条件を考えることができます。

メソッド 事前条件 事後条件
ユーザー登録 null は登録できない 指定のユーザーが DB に登録されていること
ユーザーの名前はアルファベットのみ
ユーザーの名前は一意であること
ユーザー削除 削除時の ユーザーの名前はアルファベットのみ 指定された名前のユーザーが DB から削除されていること
ユーザー 1 件取得 取得時の ユーザーの名前はアルファベットのみ 取得したユーザーの名前がアルファベットであること
取得できなかった場合 null を返すこと

※本当なら文字の長さなども事前条件に入るんですが省略してます

注意する必要があるのは、契約とはメソッドに対して存在するのではなくクラス全体に対して存在するということです。ユーザー 1 件取得の「取得したユーザーの名前がアルファベットであること」はユーザー登録の「ユーザーの名前はアルファベットのみ」という事前条件で保証されています。

つまり、事後条件を保証するための事前条件を同じクラスにすることが、責任の所在を明確にすることに繋がります。

速やかな失敗

事前条件を満たしていない場合、何をしたら良いのでしょうか? なにもしなければメソッドが実行されてしまいます。

事前条件を満たしていなければ、その場で処理を止めましょう。オブジェクト指向であれば例外を投げるのが一般的です。

ユーザー登録の例

UserRegister.ts
~~~
  regist(name: string) {
    if (!name.match(/^[A-Za-z]*$/)) throw new Error('ユーザーの名前はアルファベットのみ')
    if (this.userRepository.existByName(name)) throw new Error('ユーザーの名前はすでに存在する')
    this.userRepository.add(new User(name))
  }
~~~

このように間違った使われ方をした場合に速やかに失敗することにより、安全に登録することができるようになりました。

さいごに

契約による設計は大きなシステムになり複雑な条件が増えるほど効果を発揮します。しかし今のままだと、条件が増えると煩雑にもなっていきます。

そこで、ドメイン・プリミティブが役に立ちます。次回はドメイン・プリミティブについて詳しく書いていきます。
https://zenn.dev/zundaneer/articles/a43a0ba32bcb15

Discussion