Download - Spring Day 2016 - Web API アクセス制御の最適解
#springday
~ Basic認証? APIキー? OAuth 2.0? OpenID Connect? ~
Spring Security で作る Web API アクセス制御の
最適解
クラスメソッド株式会社 都元ダイスケ
SPRING DAY 2016 グラントウキョウサウスタワー41F
ROOM3-5 2016/11/18 (Fri)
#springday
よく訓練されたアップル信者、都元です。
Webアプリ屋・AWS屋 AWS歴 5年強(2011夏頃~) Java歴 約10年(2006頃~)
Twitter @daisuke_m
その他戦場Spring, Gradle, OAuth, OpenID Connect
自己紹介 2
#springday
【 序 章 】 概要、お詫びと訂正、 そして怒涛の結論へ
3
#springday
マイクロサービスアーキテクチャが話題を集め、 コンポーネントのWeb API化が更なる急加速を見せる昨今。 とは言え「誰でも自由に叩いて良い」Web APIなんてのは事実上無く、 ほぼ全てのケースで何かしらのアクセス制御が必要になります。
今日する話 4
Spring Security もサポートする昔ながらの「Basic認証」。 古い、ということは、悪いソリューションなのか?
最近のAPIのアクセス制御と言えば「OAuth 2.0」がトレンディ? Spring Security OAuth もあるし!
一方でAWSは「APIキー方式」を採用。なぜAWSはOAuth2ではないのか?
Spring Security はまだ公式にサポートしていない「OpenID Connect」とは一体…?
Webにおけるアクセス制御の歴史を振り返りつつ、様々なAPIの立ち位置と共に、その最適解を探っていきたいと思います。
#springday
Springの話
Webブラウザによる通信の話
ステートフルなAPIの話
HTTP(not HTTPS)通信の話
もう2016年っすよ。HTTPS使おう。
今日しない話 5
#springday
スライドを書き進めても、Springの話やJavaのコードがほとんど出てきませんでした(汗
無理やりひねり出しても仕方ないので気楽な感じで開き直って、イベント趣旨からズレた話します!
お詫び 6
#springday
結論(!?) 7
case by case結局APIの認証は何を使えばいいの?
#springday
認証:通信相手が誰か、確認すること。 (= なりすましでないことの証明)
認可:リクエストが許可されるかどうかを決めること。
認証と認可は、本来、相互に独立した概念。
しかし多くの場合、認証した上で 「その主体が権限を持つかどうか」 という視点で認可を行う。
認証と認可 8
#springday
クライアントは全てprivate networkに居る。つまりAPI サーバへの通信経路は全てprivate。牧歌的な世界。敵はいない。
そもそも認証(なりすましでないことの証明)要る?
SSLも要る? パフォーマンスを犠牲にしてまで。
まずは private network の世界 9
#springday
七人の敵どころじゃない。
アクセス制御の話を聞きに来てる時点で、SSL/TLS必須。必須。必須。
天気予報とか郵便番号検索とか、誰が見ても害がないような情報のread-only アクセスでない限り。
それだって最近は認証するケースが多い。OpenWeatherMap とか。
global network に晒した途端 10
#springday
WHAT YOU ARE (inherence factor)
顔貌、声、指紋、署名など、その人自身の提示。
WHAT YOU HAVE (possession factor)
身分証、携帯電話等、その人だけが持っているものの提示。
WHAT YOU KNOW (knowledge factor)
パスワード、秘密の質問等、その人だけが知っていることの提示。
認証の方法 11
#springday
静的・無期限のクレデンシャル 例: パスワード
静的・有期限のクレデンシャル 例: OAuth2 アクセストークン・セッションID
動的なクレデンシャル 例: リクエスト署名 (HMAC)
クレデンシャルの分類 12
#springday
【 第 1 章 】 Basic認証
13
(と、Digest認証)
#springday
HTTPではパスワードが平文で流れるので論外。
ログアウトできない。
「パスワードを保存する」チェックボックス。
見た目かっこ悪い。
(ブラウザのHTTP-BASIC認証) 14
#springday
散々disられているが、決定的な否定理由が見つからない。
BASIC認証 over HTTPS は、OAuth 2.0(後述)及びその周辺プロトコルにおける、1つの技術要素。
Access Token Request, Revocation, Introspection
API における BASIC認証 over HTTPS 15
Is HTTPS and Basic Authentication secure enough for banking webservices (RESTful)? http://security.stackexchange.com/questions/44811/
#springday
HTTPSという前提条件の下、適切に運用すれば直ちに安全に影響を及ぼすレベルではない。
ただ、敢えて勧めはしない。なぜなら…
API における BASIC認証 over HTTPS 16
#springday
Attack windowが大きい。
リクエスト毎に静的・無期限なクレデンシャルが毎回流れる。
SSL/TLSとて万能ではない。
Heartbleed, POODLE, FREAK, etc.
BASIC認証 over HTTPS を否定するとすれば 17
#springday
静的なクレデンシャルが毎回流れるのが問題ならば、nonceを利用したチャレンジ&レスポンスで、動的なクレデンシャルにしてしまえば良いのでは?
チャレンジ&レスポンスなので、HTTPリクエストが必ず2往復する。
結論:Web APIには向かない。
Digest認証 18
#springday
【 第 2 章 】 APIキー署名
19
#springday
AWSのAPIが採用している認証方式。
HMAC(ハッシュ関数に基づくメッセージ認証符号)
hash( secret + message ) の値はsecretを知らなければ計算できないでしょ?
リクエスト署名用 API キー 20
注:上記の式は、イメージです。素人が素朴に作ったオレオレHMACには脆弱性が発見されており、 HMACの算出は、実際はもうちょっと複雑な式を使います。
#springday
message = リクエスト内容+現在時刻 等
secret = シークレット・アクセスキー
上記でHMACを計算、これを署名とする。
リクエストと共に、ヘッダで署名を送る。
署名は動的クレデンシャル。
HMACによるリクエスト署名 21
実は、OAuth 1.0a はこんな感じの仕組みでリクエストを行う。 つまり、リクエスト毎に面倒な計算が必要。
#springday
RFC的なスタンダードは存在しない。(欲しい)
署名算出にあたって、"aws4_request" という文字列定数を利用するオレオレ感。
V1~4までがあるが、V1は脆弱なので利用しない。
V4の利用を推奨。
AWS Signature Version 4 22
#springday
23
幕間
#springday
最近、都元がやってるお仕事です。
要するに、ECサイト等を作るためのAPIサービス
商品やカテゴリのマスメンや検索
顧客管理
注文や決済の処理
prismatix 24
ここで一旦、CMです。 25
#springday
prismatix の開発を取り巻く環境 26
#springday
都元、前職は某スタートアップ。
現職、クラスメソッド (ブログの会社?)
スタートアップとしての prismatix 27
#springday
prismatixは、UI は提供しません。APIだけ。
ECサイトの UI を持つフロントエンドシステムは、prismatix API を利用する「クライアント」
「顧客」「クライアント」「prismatix」
3者のアイデンティティ(ID)を連携、コントロールするアクセス制御機構。それが OAuth 2.0 。
prismatix API 28
#springday
【 第 3 章 】 OAuth 2.0
29
#springday
認証をするための仕組みじゃねェ。
認可をするための仕組みでさえねェ。
A があらかじめもっている認可を B に対して 部分的に委譲するための仕組み。
そもそも OAuth とは 30
認証:通信相手が誰か、確認すること。 認可:リクエストが許可されるかどうかを決めること。
#springday
3者(本当は4者だけけど)間のやり取りで、 エンドユーザの権限を、クライアントに委譲する手続き。複雑。超複雑。
クライアントは、ユーザから委譲を受けた証として、 「ユーザのIDとpass」ではなく「アクセストークン」を入手する。
アクセストークンは、静的だが有期限のクレデンシャル。
OAuth の概要 31
#springday
一般的なAPI アクセス制御
OAuthによるアクセス制御の特徴 32
OAuth によるアクセス制御
#springday
#springday
通常は、クライアントが全権を握る。
クライアントに認証を受けたユーザが、クライアントの監督の下に、クライアントの権限を以って、APIアクセス。
OAuthは、エンドユーザが全権掌握。
神様であるエンドユーザ様の許しを得たクライアントが、エンドユーザ様の名の下に、委譲を受けた権限を行使することによる、APIアクセス。
強いのは、クライアントか、エンドユーザか。 33
#springday
エンドユーザは神様である前提のプロトコル。
つまり、エンドユーザに対する認可の仕組みは定義していない。(スコープ外)
OAuth 2.0 におけるエンドユーザの権限管理 34
#springday
認証Authentication userAuthentication;
エンドユーザが持つ権限(認可) Collection<GrantedAuthority> userAuthorities = userAuthentication.getGrantedAuthorities();
OAuth2における認証(直接的にはクライアントの認証)OAuth2Authentication oauth2AuthN; // (has-a userAuthentication)
OAuth2においてエンドユーザから委譲を受けた権限の範囲 Set<String> scopes = oauth2AuthN.getOAuth2Request().getScope();
Client Credentials 認証においてクライアントが持つ権限(認可)Collection<GrantedAuthority> clientAuthorities = oauth2AuthN.getOAuth2Request().getAuthorities();
Spring security のモデル 35
#springday
【 第 4 章 】 OpenID Connect
36
#springday
むしろ OAuth 2.0 よりもシンプル。
個人的に、とっっっっても面白い技術。
でも実は Web API の認証にはあんまり関係が深くない。
というわけで、今日の話のスコープ外。
OpenID Connect 37
#springday
あるところに、とあるアプリがあり、それを操作しているエンドユーザがいました。
アプリはエンドユーザが誰なのか知りたくなりました。(ユーザを認証したい)
が、アプリ自身ではユーザのパスワードを管理したくありません。
そこでアプリは、第三者の「既にパスワードを管理しているシステム」(OpenID Provider) に、エンドユーザを連れて行って(リダイレクト)、代わりに認証をしてもらいました。
OpenID ProviderはID/passを確認したら、「この人は都元さんだよ」というデータに電子署名をつけて、アプリに渡します。
アプリは、OpenID Providerの公開鍵を使って署名を検証します。
検証が成功するということは、この人は確かに都元さんなんだ、と確認が持てます。
もし正しいID/passを示せないのであれば、OpenID Providerはこのデータに署名するわけがないのだから。
(OpenID Connect がしてくれること) 38
#springday
まとめ
39
#springday
認証と認可は複雑。 本当に仕組みが必要か、考える。
BASIC認証 over HTTPS は害悪ではない。 が、お勧めもしない。
クライアントを神に位置づけるのであれば、 APIキー署名方式は適切な選択肢。 ただし、仕様がオレオレ化するので、標準化が望まれる。
まとめ 40
#springday
OAuth は2つの主体間で認可を委譲する複雑なモデル。 オーバースペックの可能性があるので、要熟考。
OpenID Connect Web API 認証には縁が深くない。 でも面白いヨ。
まとめ 41
#springday
42
絶賛エンジニア募集中