ebiebievidence.com

私について  /  RSS

LINE Messaging API の「Webhook との通信でエラーが発生しました。」エラーについて

October 30, 2018

B!

目次

LINE Messaging API

LINE Messaging APIとは、LINE で Bot を提供するための API。1 対 1 トーク・グループトークの両方に対応している。こちらからユーザにメッセージをプッシュ送信することもできるし、ユーザからのメッセージにリプライを送信することもできる。選択肢のあるボタンや、写真付きのカード形式でリンクなど、リッチな UI を提供することもできる。

やったこと

  1. AWS EC2で t3.micro を借りる
  2. Google Domainsで独自ドメインを取得する
  3. Let’s Encryptで SSL 証明書を取得する
    ※ LINE Messaging API の Webhook は、当然ながら SSL にのみ対応している。
  4. nginxで HTTPS サーバを建てる
  5. LINE 公式ドキュメントを参考にアクセストークン・シークレットキーを取得する
  6. LINE 公式の Flask によるサンプルコードに、アクセストークンとシークレットキーを入力した上で動かす

発生した問題

  • 以下のように、 「Webhook との通信でエラーが発生しました。」 というエラーが表示される。 https://i.imgur.com/2rJUg8W.png
  • 上記の接続確認を行っても、EC2 サーバ内にアクセスされたログは残らない。
  • ただし、Web ブラウザ上からは問題なく該当ドメインへアクセス出来る。 また、同サーバ内にアクセスログはきちんと残っている。

結論

nginx のssl_certificateが、中間証明書を含んでいなかった。 cert.pem ではなく、fullchain.pem を指定する。

学び

  1. サーバの証明書に関する設定によっては、Web ブラウザからは問題なく表示出来ても、wget や curl からは SSL 証明書の検証に失敗する場合がある。
    追記: 2018/10/30: 最近のモダンな Web ブラウザは、中間証明書をキャッシュしたり、Authority Information Access 拡張から欠けている証明書を持ってきたりしてくれる。一方で、curl では Authority Information Access 拡張のサポートはTODOに追加されているものの、未だ実装されていない。
  2. ssl_certificateには、サーバ証明書だけではなく、きちんと中間証明書も含めて指定する。

試したこと

アクセストークン・Channel Secret を再発行する

参考: LINE Developers から webhook URL の登録に関して| teratail

アクセストークンが無効になっている可能性を考えたが、問題は解消しなかった。

ちなみに、同サンプルコードはアクセストークンや Channel Secret が誤っていても、何かしら LINE API とやり取りするまではエラーを吐かない。LineBotApiのインスタンスを生成したらすぐにline_bot_api.get_profile(自分自身のUser ID)を叩くことで、認証情報が正しいかどうかをチェックすることが出来る。

後々考えてみれば、そもそも LINE Developer コンソールの「接続確認」ボタンを押しても、私のサーバへアクセス出来ていないのだから、ここをどうこうしてもしょうがないのは当然だった。

wget する

証明書関連において嫌な予感がしたので、wget した。 (以下では、とりあえず当該サーバのドメイン名を example.com とする。)

$ wget -O - example.com
example.com (example.com) をDNSに問いあわせています... 23.34.96.213
example.com (example.com)|23.34.96.213|:443 に接続しています... 接続しました。
エラー: example.com の証明書(発行者: `‘CN=Let’s Encrypt Authority X3,O=Let’s Encrypt,C=US')の検証に失敗しました:
  発行者の権限を検証できませんでした。
example.com に安全の確認をしないで接続するには、`--no-check-certificate' を使ってください。
$ LANG=C wget -O - example.com
Resolving example.com (example.com)… x.x.x.x
Connecting to example.com (example.com)|x.x.x.x|:443… connected.
ERROR: cannot verify example.com’s certificate, issued by ‘CN=Let’s Encrypt Authority X3,O=Let’s Encrypt,C=US’:
Unable to locally verify the issuer’s authority.
To connect to example.com insecurely, use `–no-check-certificate’.

中間証明書が見当たらないようだ。 ここで nginx の設定を見直す。 (問題の説明に不必要な設定は全て省いた。)

server {
    listen 443 default ssl;
    ssl on;

    ssl_certificate /etc/letsencrypt/live/example.com/cert.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    location / {
        proxy_pass http://line_sample_bot;
    }
}

ssl_certificateが、サーバ証明書と中間証明書の両方を結合させたfullchain.pemではなく、サーバ証明書のみであるcert.pemを指している。

正しく修正する。

server {
    listen 443 default ssl;
    ssl on;

    # ssl_certificate /etc/letsencrypt/live/example.com/cert.pem;
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    location / {
        proxy_pass http://line_sample_bot;
    }
}

動いた。

https://i.imgur.com/W8CeZ21.png

「Webhook が無効な HTTP ステータスコードを返しました(期待されるステータスコードは 200 です)」という表示がされるが、これはあくまで疎通していることを確認するためだけのものであって、認証に必要なX-Line-Signatureヘッダーが付与されたリクエストではないため、正常に動作する状態でもこの表示がされる場合がある。 https://i.imgur.com/EqFDP3Z.png

私について

EbiEbiEvidence
株式会社ディー・エヌ・エーでエンジニアをしています。もっと詳しく

よかったらこの記事をシェアしてください:
B!