タイトル通り、本当に見られたくない無い要素はrequest specでも検証したほうが良さそうに思ったので、自戒の意味も込めてメモしておきます📝
想定しているケース
以下のような要件があり、
- ログインユーザーにはすべての情報を表示
- 未ログインユーザーには一部の情報だけ表示
以下のような実装をしていたとします。
- 表示部分は、フロントエンドで動的に表示
- ログインと未ログインでは共通のインターフェイスでやりとりし、JSONをバックエンドからフロントエンドに渡す
- フロントエンドでユーザーのログイン状態を判定し未ログインの場合は一部の情報を非表示する
実装イメージ
※RailsとVueの場合を想定
def index @posts = Post.all @logged_in = user_logged_in? end
<posts :init-posts=<%= @posts.to_json %> :logged_in=<%= @logged_in %> />
問題点
共通のインターフェイスでやりとりし、JSONをバックエンドからフロントエンドに渡しているのでバックエンドからのレスポンスを未ログインユーザーが見た場合、JSONの中身が見えてしまうので本来だったら見せたくない情報が閲覧出来る状態になってしまっています。
レスポンスイメージ
<posts :init-posts="[{title: "title", secret: "秘密の情報" }]" :logged_in=false />
しかもブラウザによるDOMのレンダリング後は非表示になるため、system spec等で普通にE2Eテストを書いてるだけでは検知できません。。。
対応策
見せたくない情報はマスキングして渡す
以下のようにそもそも未ログインの場合は不要な情報のハズなのでマスキングして渡す事によってレスポンスを見てもマスキングされた値が入っているので閲覧されることはありません。
MASKED_TEXT = "******" def index @posts = Post.all.map { |post| { title: post.title, secret: MASKED_TEXT } } @logged_in = user_logged_in? end
レスポンスイメージ
<posts :init-posts="[{title: "title", secret: "******" }]" :logged_in=false />
レスポンスを直接検証して発生を未然に防ぐ
E2Eテストだと検知が難しいので直接レスポンスボディを検証するようなテストを行うことで、CI等で発生を検知しリリース前に気づくことができます。
let!(:post) { create(:post, secret: "秘密の情報") } before { get posts_path } it '見えちゃいけない情報が見えないこと' do expect(response.body).not_to include post.secret end
おわりに
一見すると見えていない部分でも意図せず情報を公開してしまうようなことが発生するとクリティカルだったりするので、見えちゃいけない情報はそもそもレスポンスとしても返さないように気をつけたいですね・・・!