TL;DR
401 Unauthorized → 認証失敗
「あんたログインできまへんで」
403 Forbidden → リソースのアクセス権ナッシング
「ログインはできてるけど、そのリソース使えまへんで」
元ネタ
403 Forbidden vs 401 Unauthorized HTTP responses
調べようとしたきっかけ:冷静になったから
APIサーバでユーザからのリクエストを 「はじくぜ〜、超はじくぜ〜」 もしくは、 「悪・即・斬!」 と言いながらエラーレスポンスを設定していた時のこと。
ある場所では、 401 Unauthorized
が返され、また別のところでは 403 Forbidden
が返されていました。
勢いに身を任せて 401 Unauthorized
を実装しそうになりましたが、一度冷静になり、違いを調べることにしました。
Stackoverflowのあるページを見つけた
私のお得意の検索術である vs比較テクニック を使い、 forbidden vs unauthenticated
で検索を行ったところ、次のような Stackoverflow が見つかりました。
403 Forbidden vs 401 Unauthorized HTTP responses
「この二つのステータスコードを返す場合はどういう時があんねん?」という質問に対し、次のような回答がありました(DeepLで翻訳したものを手直し済み)。
認証エラーのHTTPステータスコード401 Unauthorizedに問題があります。これは認証(authentication)のためのものであり、認可(authorization)ではありません。
401 レスポンスを受信すると、サーバは「あなたは認証されていません(全く認証されていないか、正しく認証されていません)が、再認証してもう一度試してください」と伝えます。
認可(authorization)には 403 Forbidden レスポンスを使用します。これは永続的なもので、アプリケーション ロジックに関連付けられており、401 よりも具体的なレスポンスです。
401 Unauthorized
は認証のためであり、認可のためではない、とあります。 401
レスポンスを受信すると、それはつまり、 「あなたは認証されていません」 という意味になります。
Unauthorized
なのに、認可(authorization)ではないとは・・・わかりにくいですね。
ここで重要な概念として、 認証(authentication) と 認可(authorization) が出てきました。
実は、シンプルにこの二つをDeepLで日本語に訳してしまうと、どっちも「認証」になってしまい、流石にわけわからんので authorization は「認可」に変えています。
さらに、回答は続きます。
403 レスポンスを受信すると、サーバは「申し訳ありません。あなたが誰だか知っています。あなたが誰だと言っているか信じています。システム管理者に頼めば許可が下りるかもしれません。しかし、あなたの苦境が変わるまで、二度と私を困らせないでください」。
403 Forbidden
は、「あなたのことはちゃんと認証できてるけど、許可されてないものにアクセスしてるよ。だからもう困らせないで。。」と、なんだか切ない気持ちになるメッセージなのです。
要約すると、認証がない場合や不正な認証の場合には 401 Unauthorized レスポンスを使用し、その後に 403 Forbidden レスポンスを使用して、ユーザは認証されているが、指定されたリソースに対して要求された操作を実行する権限がない場合に使用する必要があります。
つまり、要約すると次のようになります。
-
401 Unauthorized
→ 認証されてない場合や、不正な認証の場合に返すステータスコード -
403 Forbidden
→ ユーザは認証されているが、指定したリソースに対して要求された操作を実行する権限がない場合に返すステータスコード
納得・・・したのか・・・?
「なかなか良いページを見つけた〜。お腹いっぱい!」と満足しそうになった私でしたが、よくよく考えると、「認証」と「認可」の違いを小学生に説明できない気がしてきました。
小学生に説明できないことは理解してないのと同じだと、どこかの偉い人が言ってた気がするので、もう少し深掘って調べてみます。
こういう時は、私はいつも英語版のWikipediaを使います。例によって、DeepLで翻訳してます。
認証(Authentication)
Authentication(en.wikipedia.org)
認証とは、コンピュータシステムの利用者の身元などの主張を証明する行為である。人や物の身元を示す行為である識別とは対照的に、認証はその身元を検証するプロセスである。これには、個人の身元証明書の検証、デジタル証明書によるウェブサイトの真正性の検証、カーボン・デートによる人工物の年代の決定、または製品や文書が偽造されていないことの確認などが含まれます。
認証 とは、コンピュータシステムの利用者の身元などの 主張を証明する行為 です。ここの説明で対比されているのは、 識別(identification) です。
識別(identification) は、人や物の身元( identity )を示す行為です。
つまり、 認証(Authentication) は、識別によって示された身元(identity)を検証するプロセスを言います。
ざっくり言うと、
- 識別:「これが私です!!!」と言う主張
- 認証:「これが私です!!!」と言う主張を検証するプロセス
ということになります。
小学生に説明するならば、 「君の名前は?へぇ、◯◯さんって言うんだね。でも本当かな?学校に置いてある名簿から顔写真と名前が一致してるか確かめて来るね。」というのが 認証 です。
認可(Authorization)
Authorization(en.wikipedia.org)
オーソライズとは、資源へのアクセス権/特権を指定する機能であり、情報セキュリティやコンピュータセキュリティ全般、特にアクセス制御に関係している。より正式には、「権限を与える」とは、アクセスポリシーを定義することである。例えば、人事担当者は通常、従業員の記録へのアクセスを許可されており、このポリシーは通常、コンピュータシステムのアクセス制御ルールとして形式化されている。運用中、システムはアクセス制御規則を使用して、(認証された)消費者からのアクセス要求が承認(許可)されるか否認(拒否)されるかを決定する。資源には、個々のファイルまたはアイテムのデータ、コンピュータ・プログラム、コンピュータ・デバイス、およびコンピュータ・アプリケーションによって提供される機能が含まれる。消費者の例としては、コンピュータ・ユーザ、コンピュータ・ソフトウェア、およびコンピュータ上の他のハードウェアが挙げられる。
つまり、 認可(オーソライズ、Authorization) とは、何かしらのリソースへのアクセス権を与える(=アクセスポリシーを定義する)機能であるわけです。
もうちょっと細かく言うと、これは、次のような二つに分けることができます。
- アクセスを許可するポリシーを定義する ポリシー定義フェイズ
- アクセス要求を承認または非承認する ポリシー施行フェイズ
結局小学生にわかる説明はなんやねん、というと、
- ポリシー定義フェイズ: 「高学年しか、バスケットゴールを使ってはならない」
- ポリシー施行フェイズ: 「あなたは、高学年か?それともそれ以外か?」
という感じでしょうか。
小学生でもわかる(?)解説
401 Unauthorized = 認証失敗
学校の偉めの人「君の名前は?」
◯◯を自称する者「 ◯◯です 」 ← 識別
学校の偉めの人「へぇ、◯◯さんって言うんだね。でも本当かな?学校に置いてある名簿の顔写真・名前と一致してるか確かめて来るね。」 ← 認証
数分後・・・
学校の偉めの人「君に教えてもらった名前で学校の名簿調べたら、 全然顔写真違ったよ!誰やねん! Unauthenticated!」 ← 認証失敗
403 Forbidden = 認可失敗
バスケットゴールを司る者「人気すぎて休み時間に使える人を絞ったほうがいいな・・・。よし、 高学年だけに制限しよう 」 ← ポリシー定義フェイズ
そして、休み時間に年齢不詳の少年がやってきた。
どうやら、 学校の偉めの人による、顔写真・名前チェックは通っていたらしい 。
バスケットゴールを司る者「君は何年?」
名簿に載っているが年齢不詳の少年「3年生!」
バスケットゴールを司る者「えーと(ポリシー表見ながら)、 君は高学年ではないので使えません! Forbidden!」 ← ポリシー施行フェイズ
まとめ
最後の解説は、完全に @Yametaro さんの パクr リスペクト的な文体になってしまいました。
皆さんも、サーバでユーザの行為をはじく時、適切なステータスコードを返すようにしましょうね。
ためになったら LGTM と フォローお願いします!
とてもためになる(ならないこともある)Twitterアカウント@zawawahogeも、是非是非フォローしていただけると嬉しいです!
ありがとうございました。
本記事とはあまり関係はないですが、 【初心者向け】日本語で書いたGoのコードを丁寧に解説してみた も書いたのでご興味ある方は、ぜひご一読ください。