記事の下書きを自動で登録する仕組みを使っています。ある日、それが403を返しました。
403は普通、「権限がない」という意味です。ところが同じアカウントで管理画面を開くと、手では問題なく書けます。
「人が操作すると通るのに、プログラムから叩くと落ちる」状態をどう切り分けたか。権限の問題ではないと判断するまでに確かめた5つと、そこで分かった犯人です。
第1回:症状の切り分け(この記事)/第2回:二分探索で原因を絞る/第3回:エスケープが効かなかった理由/第4回:意味を変えずに書き直す/第5回:正しく止められたときに何を残すか
最初に疑ったのは、全部はずれだった
思いつく順に確かめました。
| 疑ったこと | 確かめ方 | 結果 |
|---|---|---|
| ログインが切れた | 自分の情報を取得する問い合わせを投げる | 通る。切れていない |
| 権限が足りない | 管理画面から同じ操作をする | 書ける。足りている |
| 投げ先が違う | 一覧の取得を同じ入口に投げる | 通る。入口は合っている |
| 記事が壊れている | タイトルだけで空の下書きを作る | 通る |
| 本文が長すぎる | 本文を半分にして投げる | 通る |
ここで方向が決まりました。同じ人・同じ入口・同じ操作で、本文の中身によって結果が変わっています。
権限が足りていないなら、空の下書きも落ちるはずです。空なら通って、ある本文だと落ちる。この時点で権限は完全に容疑から外れます。
「403だから権限」と思い込むと、この切り分けに辿り着きません。番号ではなく、何を変えたら結果が変わるかで見るほうが早い。
返ってきたものが、そもそも違った
決定打は、落ちたときの応答の中身でした。
| 返ってきたもの | |
|---|---|
| 通常の権限エラー | CMSが作ったJSON。原因を示す符号が入っている |
| 今回 | サーバーが作ったHTMLのページ。CMSの符号は一切ない |
CMSが断ったなら、CMSの形式で断ります。CMSの言葉で返ってきていないということは、要求がCMSに届く前に止められているということでした。
前段に立っているものがいた
このサイトのCMSは共用サーバーに置いています。そこには、契約時から攻撃を検知して遮断する仕組みが入っていました。
管理画面の設定一覧を見ると、確かに有効になっています。自分で入れた覚えはありません。最初から入っていて、これまで一度も邪魔をしてこなかったので、存在を忘れていました。
この仕組みは、要求の中身を見て「攻撃の形をしているか」を判定します。判定に引っかかると、CMSに渡さずにその場で断ります。
問題は、断った理由がこちらに見えないことです。何が引っかかったかは教えてくれません。403という数字だけが返ってきます。
引っかかっていたのは、記事の中のサンプルコードだった
落ちていたのは、コードの書き方を説明した記事でした。本文にプログラムの断片が何か所も入っています。
攻撃を検知する仕組みから見ると、プログラムの断片と、送り込まれた攻撃コードの区別がつきません。どちらも同じ形をしています。
つまり、コードの話を書こうとすると落ちるという状態でした。書きたい内容と、守りたい形が正面からぶつかっています。
ここまでで分かったこと
| 分かったこと | |
|---|---|
| 誰が断ったか | CMSではなく、その手前にいる遮断の仕組み |
| 何で判定しているか | 送った本文の中身 |
| どこが悪いか | 不明。教えてくれない |
本文は1500文字ほどあります。そのどこか1か所が引っかかっている。読んで探しても、どれも普通のコードにしか見えません。
次回は、この「どこか1か所」を突き止めた方法を書きます。読むのをやめて、機械的に半分ずつ削っていく手順です。
今回の学び
まず、エラーの番号より、何を変えたら結果が変わるかを見るということ。403から権限を疑うのは自然ですが、空の本文で通った時点で権限は関係ありませんでした。変えた条件と結果を並べるほうが、番号を読むより速い。
次に、誰が断ったかは、断り方の形で分かること。CMSが断ればCMSの形式で返ってきます。違う形式で返ってきたということは、そこまで届いていないということでした。中身を見ずに「403だ」で終わらせると、この情報を捨てます。
そして、使っていない機能は、存在ごと忘れること。この遮断の仕組みは契約時から動いていて、これまで一度も邪魔をしませんでした。邪魔をしない期間が長いほど、思い出すきっかけが無くなります。
