こんにちは。なおとです。
大魔神佐々木のごとく、攻撃からAPIをセーブします。
防御率でいうと、0.5でも足りないくらいしっかり締めていきます。
最近APIのセキュリティについての学習を始めました。
とっかかりとして、OWASPのAPI Security Risks Top 10を1つずつ読んでとても簡単に説明し、感想の端くれを述べていくことにしました。
OWASPとは、セキュリティに関する情報共有及び普及啓発を目的としたオープンソース・ソフトウェアコミュニティです。
API Security Risks Top 10とはOWASPが発表している、Web APIにおける10大セキュリティ懸念事項みたいです。
今回はTop 10の2つ目「Broken Authentication」を見ていきます。
Broken Authenticationとは
読んで字のごとくです。
Broken Authenticationとは、
「認証周りに脆弱性が存在すること」
を指します。
認証周りに脆弱性が存在すると、攻撃者が他のユーザーの個人データを読み込んだり、なりすましたりすることが可能になってしまいます。
なお、攻撃者が他のユーザーをコントロールできる状態になってしまうと、システムが攻撃者の行動と正当なユーザーの行動を区別することが難しくなってしまいます。
脆弱性の原因
脆弱性の原因となるものは、OWASP公式に複数挙げられています。
例えば以下のようなものが挙げられています。
- ある人が別システムで使用しているユーザー名とパスワードの一覧を得た時、攻撃者はそのリストを総当たりで使用して認証を試行するクレデンシャルスタッフィング攻撃を防いでいない。
- あらゆる文字列を機械的に試行し続け、正解のパスワードを探し出すブルートフォース攻撃を防いでいない。
- 辞書に載っているような単語を機械的に試行し、正解のパスワードを探し出す辞書攻撃を防いでいない。
- 弱いパスワードを許可している。
- メールアドレスをパスワードなしで変更が可能。
- 署名していない認証トークンを有効なものとしている。
- パスワードを暗号化、ハッシュ化していない。
- マイクロサービスでは、他のマイクロサービスからのアクセスに認証が必要ない状況も危険。
- URLにトークンやパスワードなどを含ませている。
これらが全てではありませんが、ざっとこのような原因が考えられます。
具体例1
GraphQLを使用している場合を想定します。
ログインのHTTPリクエスト時にパラメータでユーザー名とパスワードを送信する必要があるとします。
もしログインのリクエストが、1分間に最大3回までに制限されていたとしても、GraphQLのクエリバッチングで1度のリクエストで多くのユーザー名とパスワードを送信することができ、ブルートフォース攻撃等を行えてしまいます。
具体例2
ユーザーのメールアドレスを更新する際にパスワードを求めていないとします。
もし攻撃者が認証トークンをなんらかの方法で攻撃対象者から盗みとれる状況にあったとすると、その認証トークンを使用してメールアドレスを更新できてしまいます。
その後、攻撃者がパスワードリセットを行うと完全にアカウントを乗っ取ることができ、攻撃対象者の情報も閲覧できてしまいます。
対策
- 認証の機構について理解すること。どの情報がどのように使われ、どのように保存されているのかを知ることが大切。
- 認証、トークン生成、パスワード保管を自分で開発しない。ライブラリなどを適切に使うこと。
- アンチブルートフォースメカニズムを実装して、認証等の機械的な試行を防ぐこと。
- CAPTCHA(キャプチャ認証)を用いるのも機械的な試行を防ぐ方法の一つ。(ロボットではありませんにチェックを入れるあれです。)
- APIキーを認証に使用しない。APIキーはAPIクライアントの認証にのみ使うこと。
- パスワードリセット機能など認証機能周りは、認証機能と同様のレベルでセキュアにすること。(パスワードリセットのメールアドレスフォームに辞書攻撃をする等でシステム内のメールアドレスの存在確認ができます。)
以上で簡単なBroken Authenticationについての説明とさせていただきます。
技術的な感想
対策として挙げられている「認証、トークン生成、パスワード保管を自分で開発しない。ライブラリを使用する」を実践しているので変わったアプリケーションの仕様でない限り大きくミスすることはないのかなと感じました。
もう少しだけ以下で感想を述べます。
-
GraphQLを用いた際のクエリバッチングによる攻撃について
GraphQLを使用したことがなかったので、まずこのような機能があるんだ、、、という所から入りました。
クエリバッチングでバッチ処理できるパラメータの個数を制限できるみたいなので、その制限によって大量回数を試行できなくなると思いました。
少しだけ別の話ですが、rubyの認証系gemでDeviseというものがあります。
Deviseは特定のアカウントがログインに何度も失敗した時、アカウントをロックする機能を提供するLockableモジュールがあります。
今回の場合、攻撃対象のユーザー名は単一ではない可能性もあるので、Lockableモジュールだと対応しきれていないと感じました。
最後に少し感想
とある開発者の方から伺ったのですが、その方が所属される会社のプロダクトはほとんどの機能をライブラリを使用せずに実装しているそうです。
認証系も同様にライブラリを使用していないみたいで、それはどうなのだろうと感じましたが、自分は以後も変わらず認証周りだけはしっかりライブラリに頼っていこうと思います。
この記事の説明は本当に簡単に行っています。
しっかり学びたい方は是非公式の文章を読んでみてください。
最後まで読んでいただき、ありがとうございました。