【開発者向け】EC-CUBE API プラグイン勉強会 | EC-CUBE 名古屋 vol.36

2019/06/29

API の提供側の話です♡

EC-CUBEの情報を扱いリスク

・個人情報満載
・決済に関わる情報を持ってる
・セキュリティ対策で重過失とされた事例もある

– – – OAuth2.0は認可フレームワークの仕様。- – —

Twitterはこれ。だけどきちんと準拠していない
FBは認可できなく認証になってるくらいオレオレになってる。

YahooとLINEのIDはわりとちゃんと準拠しつつも、拡張して認証させている。

– – –

Yahoo!Japan は OpenID Connectを利用してる

OAuth2.0の拡張版。
認証を取り扱うのが仕事。ソーシャルログインによる使われている。
アプリケーション間の認証を安全に行うための仕様
 →相互妥当性検証が可能

OpenID Authorization 2.0とは別物

– – – まとめ – – –

・第三者のアプリケーションにユーザーID&パスワードを渡さずに
・誰を認証するか - 認証(Authentication)
・誰が誰になんの権限を与えるか - 認可(Authorization)

誰が誰になにを許可する

Authorization Code flow(Webアプり向け)と
認証とアクセストークンのエンドポイントが別れてて、2つサーバーを使う仕様

Implicit flow(ネイティブアプリ向け)
認証のエンドポイントだけで
アクセストークンはブラウザのアドレスに付与される
Refresh Tokenが無いのも特徴。セキュリティレベルが下がるから

OAuth2.0も包括

その他Google Identity Platform などをRest API記述するために Swagger仕様(今後のデファクトスタンダード)を採用してる

SwaggerUIを使うと簡単に使える

参照URL : https://ec-cube.github.io/api

EC-CUBE APIでは、
Customer(フロント側)とMember(管理画面側)に認証を提供している

APIクライアントは、各ユーザーと1対1の関係

MemberごとにAPIクライアントを作る
Customerマイページの隠しページ/mypage/api でapiクライアントを作れる

未サポート
・opened connect coreのうちoptional扱いのもの
・promptパラメータ/displayパラメータ(まるまるを許可しますか?という表示の仕方。デフォはpageとかだと全画面)
・hybrid flow (認証の仕様を両方使う)
・public client(会員情報がない人(認証されていない人)が利用できる仕様)
・dynamic registration/discoveryなどopened connectの関連仕様(public clientを使うための仕様)

##チュートリアルがあるよ
http://ec-cube.github.io/api_authorization.html

1. eccubeをローカルにインストール
2. 管理画面のプラグインから、プラグインをインストール
3. 管理画面側のapiクライアントを作る。認証することが前提なので、メンバー管理から作る
4. 設定→システム管理→メンバー管理→ログインしている管理者IDからapiクライアントを新規登録してapiクライアントのアプリケーション名を入れる。
5. redirect_url … 認証したあとの戻り先URL
6. クライアントidとクライアントシークレットをメモっておく。これをつかってアクセストークンをします。
7. authorization codeを登録します。1度ログアウトして…ここからの手順はチュートリアル(http://ec-cube.github.io/api_authorization.html)で。

「JSON デバック https://jwt.io/」

改ざんされていないかというチェックができる
id_tokenを使って秘密鍵をJWTで調べれますよ〜。
暗号化アルゴリズムを間違えないでっRS256ですよっ

EC-CUBE独自に実装しているもの

tokeninfo

/OAuth2/v0/tokeninfo?id_token= へ GET リクエストをすると、 id_token の詳細情報を JSON 形式で取得できます。

{
"iss":"https:\/\/example.com",
"sub":"4nwsnbszIH4XuQnXwigtP8HaKQpjeGx499s0A9I1qko",
"aud":"2e8153023d6afb2fb29931dbf9a275ed4715f384",
"iat":1460535523,
"exp":1460539123,
"auth_time":1460535523,
"nonce":"random_nonce"
}

* iss – ID トークンの発行元。
* sub – ユーザー識別子。 id_token の公開鍵から生成される。
* aud – ID トークンの想定されるオーディエンス。 OAuth2.0 Client ID が使用される。
* iat – ID トークン発行時刻の UNIX タイムスタンプ。
* exp – ID トークン有効期限の UNIX タイムスタンプ。
* auth_time – 認証の発生時刻の UNIX タイムスタンプ。
* nonce – クライアントセッションの識別子。リプレイスアタック防止のために使用する。
この情報を元に、以下のような内容を検証する必要があります。参考
* iss の値が API の認証をしたホスト名と一致することを確認します。
* sub の値が id_token の公開鍵の thumbprint と一致することを確認します。JOSE_JWK::thumbprint() などで検証できます。
* aud の値が Client ID と一致することを確認します。
* iat の値が、現在のUNIXタイムスタンプ値 – 600秒 以上であることを確認します。
* exp の値が、現在時刻のUNIXタイムスタンプ値より大きいことを確認します。
* nonce の値が、クライアントで保持している nonce の値と同一であることを確認します。リプレイスアタック防止のため、セッションで保持している nonce を破棄します。
Member/Customer と OAuth2.0 Client の関係

* ログイン中の Member/Customer と OAuth2.0 Client の ID が相違している場合は、認可リクエスト時に access_denied エラーとなります。
redirect_uri の指定

Authorization Code Flow にて、 redirect_uri に urn:ietf:wg:oauth:2.0:oob を指定することで、 ブラウザの画面に Authorization code を表示されます。 curl を使用したテスト用途や、ネイティブアプリケーションなどに利用可能です。

実装してみましょう

・CSRF防止のためのstateパラメータは必須
・OAuth2.0では推奨になっているため、サポートしていないクライアント/SDKが多いので注意
・各言語のサンプル有り
・Java, FS, Python, PHP C言語
・Googleのさーびす OAuth 2.9 Playground(https://developers.google.com/oauthplayground/) endpoints: をカスタムにすると、Googleのサーバーを使って、accuseのapiが動くのをチェックできる
◯ accubeのAPIテストできるやつがあるので、を管理画面から使ってみましょ!

追加仕様
・Google Identity Providerを参考に追加実装したもの
・tokeninfoエンドポイント
・id_tokenを渡すと詳細情報をJSONに渡す
・urn:item:wg:oath:2,0:oob
・ネイティブアプリでAuthorization codeフローをしようとした場合、テスト用途で利用しようとするとき、管理画面に表示してくれる機能が実装されています。

## 実装について2
・customer/MemberごとにUserInfoとid_tokenのPublic keyが生成されます。
・UserInfo::subはPublic keyの指紋(thumbprint)です
・シングルサインオンをしたい場合は、もうちょっと改良した方がいい。
一応、実装してみました→https://github.com/EC-CUBE/eccube-api/issues/39#issuecomment-249665124
・id_tokenの検証は https://jet.io/ が便利

◯ 認証+全テーブルのCRUDを提供

CRUD APIについて
・RestfulなAPI
・Create=POST, Read=GET, Update=PUT, Delete=DELETE
・MemberのAPIクライアント編集画面から簡単に試せます
・一番後悔させている商品などは認証不要
・削除はdel_flgのあるテーブルのみ

・JSON<->EntityのMapperを独自に開発
・複合キーのテーブルはURLがか変わるので注意
・https:///api/v0/{table_name}/key1/value1/
・DoctrineのMetadataを横撮ってJSONとEntityをマッピングしている

## Jsonのフォーマット
コレクションの場合
プロパティの場合
配列の場合 オブジェクトに配列のセット