04 Python Flask 教學10 所有文章

淺談 LINE-Bot 中的驗證機制 (HMAC & Bearer Token)

Line bot 驗證機制_Max行銷誌

這篇將是 LINE Bot 教學系列的最後一篇,前面兩篇我們實作了 Heroku 和 GCP 兩種部署方式,最後將帶大家閱讀 LINE Bot SDK 中的 Authentication 驗證機制 (HMAC、Bearer Token),如何來確保訊息傳遞上的完整性 (integrity),以及是否有權限可以對 LINE Platform 發送請求。

關於 LINE Bot 教學系列的前面四篇文章可以參考:

一. 簡單的 Flask + LINE Bot 範例

首先寫一個簡單的 Flask + LINE Bot 的 ehco 範例機器人,我們接下來會針對這份程式碼,來讀 LINE-Bot SDK 背後做了些什麼事

import os
from datetime import datetime

# Flask
from flask import Flask, abort, request

# LINE Bot SDK
from linebot import LineBotApi, WebhookHandler
from linebot.exceptions import InvalidSignatureError
from linebot.models import MessageEvent, TextMessage, TextSendMessage

app = Flask(__name__)

line_bot_api = LineBotApi(os.environ.get("CHANNEL_ACCESS_TOKEN"))
handler = WebhookHandler(os.environ.get("CHANNEL_SECRET"))

# Signature Validation
@app.route("/", methods=["POST"])
def callback():
    if request.method == "POST":
        signature = request.headers["X-Line-Signature"]
        body = request.get_data(as_text=True)

        try:
            handler.handle(body, signature)
        except InvalidSignatureError:
            abort(400)

        return "OK"

# Message Response
@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
    get_message = event.message.text

    # Send To Line
    reply = TextSendMessage(text=f"{get_message}")
    line_bot_api.reply_message(event.reply_token, reply)

二. 淺談 LINE-Bot 中的驗證機制

1. HMAC

▍什麼是 HMAC ?

Providing a way to check the integrity of information transmitted over or stored in an unreliable medium is a prime necessity in the world of open computing and communications.

RFC 2104

HMAC (Hash-based message authentication code) 是一種訊息驗證機制,可以確保傳遞訊息的完整性 (integrity) 和傳送人是否正確,HMAC 支援多種雜湊演算法 (MD5、SHA-256),並藉由 hash 要傳遞的 message 和 secret key 來產生 signature (如下圖左邊綠色區塊)。

當接收方接收到 傳送方 (例如:LINE platform) 傳送的 message 和 signature 後,會透過接收到的 message + 持有的 secret key 進行 hash 產生 signature (如下圖右邊灰色區塊)。

最後再將兩組 signature 進行比較,如果兩者不相同,代表傳遞的訊息有被竄改過。

▍LINE Bot SDK 如何使用 HMAC ?

當有人呼叫 Flask 的 API 時,首先從請求的 header 中拿到 X-Line-Signature (如下範例 code 第四行)

@app.route("/", methods=["POST"])
def callback():
    if request.method == "POST":
        signature = request.headers["X-Line-Signature"]
        body = request.get_data(as_text=True)

接下來會放到 handler.handle 進行 Signature 的驗證,如果失敗則返回錯誤訊息:

        try:
            handler.handle(body, signature)
        except InvalidSignatureError:
            abort(400)

        return "OK"

關於 handler.handle 可以從 LINE GitHub Python SDK 文件中 linebot > webhook.py > class SignatureValidator 第 85 行看到:

將請求中 body 的資料和我們持有的 Channel Secret 進行 hmac 後:

    hmac.new(
        self.channel_secret,
        body.encode('utf-8'),
        hashlib.sha256
        ).digest()

與請求 header 中的 X-Line-Signature 比較,如果兩者不相符則則 raise signature_validator 的錯誤 (文件第 134行)。

▍小補充:關於 Custom Header

HTTP Header 使用 X- 前綴字來區隔 header 中的參數是標準參數或代表是 Custom 參數的參數,像這邊就是使用 X-Line-Signature,但於 RFC 6648 中提到此方法已經不鼓勵 (discouraged) 使用 X-前綴字來命名。

2. Bearer Token

▍什麼是 Bearer Token ?

首先看看 RFC 6750 如何定義 Bearer Token:

Any party in possession of a bearer token (a “bearer”) can use it to get access to the associated resources (without demonstrating possession of a cryptographic key).

RFC 6750

Bearer Token 是由 Authorization Server 在 Resource Owner 的允許下核發給 Client ,Resource Server 只要認這個 Token 就可以認定 Client 已經經由 Resource Owner 的許可。

簡單來說 Bearer Token 就像是火車票,車票上會寫著搭乘的範圍 (例如台北到宜蘭)、有效的時間;而車長只認車票,只要持有的人都視為付過車票錢的人。

而為了防範 Token 在傳輸的過程外洩,須使用 SSL/TLS 來防護,也因此 LINE 的 Webhook URL 僅能填入 HTTPS URL

▍LINE Bot SDK 如何使用 Bearer Token ?

申請 LINE Developers 後,會拿到 Channel access tokenChannel secret,從剛剛 demo 的範例程式中,可以看到在一開始就會將這兩個參數傳給 LineBotApi 和 WebhookHandler 並實例化。

import os
from flask import Flask, abort, request
from linebot import LineBotApi, WebhookHandler

app = Flask(__name__)

line_bot_api = LineBotApi(os.environ.get("CHANNEL_ACCESS_TOKEN"))
handler = WebhookHandler(os.environ.get("CHANNEL_SECRET"))

可以從 LINE GitHub Python SDK 文件中 linebot>models>api.py 第61行 看到,LineBotApi 會將 channel_access_token 放到 'Authorization': 'Bearer ' + channel_access_token 中,未來當發送 request 請求給 LINE Platform 時,會驗證此 Token,來確認身份。

以上就是今天要介紹的 LINE-Bot 中使用到的驗證機制 HMAC 和 Bearer Token,那文章就到這邊告一個段落囉!有任何問題可以在以下留言~


關於 Flask 教學的延伸閱讀:

▍ Flask 教學系列目錄:

▍其他 Flask 相關教學:

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *