# LINEログインをPKCE対応する
# PKCEとは何か?
PKCE(Proof Key for Code Exchange)とは、認可コード横取り攻撃への対策を目的とし、RFC7636 (opens new window)で定義されているOAuth2.0拡張仕様です。
PKCEの機構を持たないOAuth2.0の認可フローでは、悪意のあるアプリが何らかの方法で認可コードを含むカスタムURIを取得した場合、ユーザー固有のアクセストークンを横取りされる恐れがあります。LINEログインを組み込んだウェブアプリにPKCEの認可フローを導入することで、LINEログイン v2.1のセキュリティをさらに向上させ、「認可コード横取り攻撃」を防ぐことができます。
# LINEログインにPKCEを実装するメリット
LINEログインを組み込んだウェブアプリに、PKCEを実装した場合と実装していない場合では、以下のように「認可コード横取り攻撃」に対する動作が異なります。ウェブアプリをよりセキュアにするために、PKCEの実装をおすすめします。
PKCE未実装の場合 | PKCE実装済みの場合 |
---|---|
悪意のあるアプリが何らかの方法で認可コードを含むコールバックURLを取得した場合、アクセストークンを奪えてしまいます。 | 悪意のあるアプリにリダイレクト時に渡される情報を横取りされても、一意のcode_challenge を照合することでアクセストークンの横取りを防ぎます。 |
PKCE実装済みのLINEログインを組み込んだウェブアプリに、Yahoo! JAPANアプリ (opens new window)からアクセスすると、メールアドレスとパスワードによるログインの工程をスキップできる自動ログイン機能が有効になります。
# LINEログインにPKCEを実装する
LINEログインにPKCEを実装するには、通常のLINEログインの組み込みの手順に加えて以下の4つの手順を行います。
code_verifier
を生成する。- 手順1で生成した
code_verifier
を元にcode_challenge
を生成する。 - 手順2で生成した
code_challenge
とcode_challenge_method
をクエリパラメータに付与した認可URLにユーザーをリダイレクトさせる。 - 「アクセストークンを発行する」エンドポイントのリクエストボディに手順1で生成した
code_verifier
を加えて実行する。
PKCE対応のために、LINEログインの「認可URL」および「アクセストークンを発行する」エンドポイントに、以下のパラメータが追加されました。
code_verifier
code_challenge
code_challenge_method
各パラメータについて詳しくは、以下の各手順の説明を参照してください。
# 1. code_verifier
の生成
ウェブアプリ側で、ユーザーがLINEログインを実行したタイミングで、一意のcode_verifier
を生成します。code_verifier
の仕様はRFC7636 (opens new window)に準拠しています。
パラメータ
パラメータ | 仕様 | 例 |
---|---|---|
code_verifier | 使用可能文字種:半角英数字(a 〜z 、A ~Z 、0 ~9 )および記号(-._~ )からなるランダムな文字列文字数:43文字〜128文字 | wJKN8qz5t8SSI9lMFhBB6qwNkQBkuPZoCxzRhwLRUo1 |
サンプルコード
以下は、Node.jsを使ったcode_verifier
の生成のサンプルコードです。
// randomAlphaNumericString()は、使用可能文字(半角英数字および記号)で構成された
// ランダムな文字列を引数に指定した整数分(43〜128)生成して返す関数を想定
const code_verifier = randomAlphaNumericString(43);
# 2. code_challenge
の生成
生成したcode_verifier
をSHA256で暗号化したうえで、Base64URL形式にエンコードすることでcode_challenge
を生成できます。
パラメータ
パラメータ | 仕様 | 例 |
---|---|---|
code_challenge | code_verifier をSHA256で暗号化したうえで、Base64URL形式にエンコードした値 | BSCQwo_m8Wf0fpjmwkIKmPAJ1A7tiuRSNDnXzODS7QI |
code_challenge
の値は、URLクエリパラメータとして利用できるように、通常のBase64形式の文字列から以下の削除・置換を行う必要があります。詳しくは、『RFC 4648』の「5. Base 64 Encoding with URL and Filename Safe Alphabet (opens new window)」を参照してください。
- パディング(文字詰めの
=
)の削除 +
を-
に置換/
を_
に置換
Base64形式の例 | code_challenge 用に削除・置換を行った例 |
---|---|
BSCQwo_m8Wf0fpjmwk+KmPAJ1A/tiuRSNDnXzODS7== | BSCQwo_m8Wf0fpjmwk-KmPAJ1A_tiuRSNDnXzODS7 |
サンプルコード
以下は、Node.jsを使ったcode_challenge
生成のサンプルコードです。
// このサンプルコードでは、Node.jsの"crypto"モジュールを使用しています。
// 参照:https://nodejs.org/api/crypto.html#crypto_crypto
const crypto = require("crypto");
// BASE64形式をBASE64URL形式にエンコードします。
function base64UrlEncode(str) {
return str
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=/g, '');
}
// code_verifierをSHA256で暗号化し、BASE64URL形式にエンコードすることでcode_challengeを生成します。
const code_challenge = base64UrlEncode(crypto
.createHash('sha256')
.update(code_verifier)
.digest('base64'));
# 3. 認可URLのクエリパラメータにcode_challenge
とcode_challenge_method
を含める
通常のLINEログインの認可URLのクエリパラメータにcode_challenge
とcode_challenge_method
を含めます。
パラメータ
パラメータ | タイプ | 必須 | 説明 |
---|---|---|---|
code_challenge | String | 任意 | 手順2で生成したcode_challenge 。デフォルト値はnull です(値を指定しない場合、リクエストはPKCE対応されません)。 |
code_challenge_method | String | 任意 | S256 (ハッシュ関数SHA256 を表します。)注:RFC7636の「4.2. Client Creates the Code Challenge」 (opens new window)では、 code_challenge の生成方法として、S256 以外にplain (暗号化しない)が定義されていますが、LINEログインではセキュリティ上の観点からS256 のみをサポートしています。 |
認可URLの例
https://access.line.me/oauth2/v2.1/authorize?response_type=code&client_id=1234567890&redirect_uri=https%3A%2F%2Fexample.com%2Fauth%3Fkey%3Dvalue&state=12345abcde&scope=profile%20openid&nonce=09876xyz
&code_challenge={手順2で算出したcode_challengeの値}&code_challenge_method=S256
認可URLのその他のクエリパラメータについて詳しくは、「ユーザーに認証と認可を要求する」を参照してください。
# 4. リクエストボディにcode_verifier
を指定してアクセストークンを発行する
「アクセストークンを発行する」エンドポイントのリクエストボディに、code_verifier
を指定して実行します。
リクエストボディ
code_verifier
String
手順1で生成したcode_verifier
(例:wJKN8qz5t8SSI9lMFhBB6qwNkQBkuPZoCxzRhwLRUo1
)
リクエストの例
curl -v -X POST https://api.line.me/oauth2/v2.1/token \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'grant_type=authorization_code' \
-d 'code=1234567890abcde' \
--data-urlencode 'redirect_uri=https://example.com/auth?key=value' \
-d 'client_id=1234567890' \
-d 'client_secret=1234567890abcdefghij1234567890ab' \
-d 'code_verifier={手順1で生成したcode_verifier}'
「アクセストークンを発行する」エンドポイントについて詳しくは、『LINEログイン v2.1 APIリファレンス』の「アクセストークンを発行する」を参照してください。