ようやく研究が始まってだんだん忙しくなってきたぴのです。最近単発ネタや日記の投稿が多いのはそういうことです。ゲームをする時間はあります。
結構前に作ったLINEBotですが、脆弱性があったので対策を施しました。ついでによく使う関数をまとめてライブラリっぽくしたので、それらを投稿として残しておこうと思います。前回までの記事はこちら。
安全性の向上を図る
問題点
前回までのプログラムだと、LINEサーバー以外からの悪意あるアクセスを検出できないという問題点がありました。その場合、LINEBotが乗っ取られる可能性があるため、放置しておくわけにはいきません。
解決策
署名検証を行い、LINEサーバー以外からのアクセスを検出する関数を作成しました。channelSecretは自分とLINEサーバーだけが知っているキーのことです。データと一緒にハッシュ化されたものが「X-Line-Signature」として送られてくるので、こちら側で同様に作成したハッシュ値と比較するとLINEサーバーからの転送であることを検出することができます。
//署名検証
function signature_validation($body){
global $channelSecret;
$hash = hash_hmac('sha256', $body, $channelSecret, true);
$sig = base64_encode($hash);
$headers = getallheaders();
$compSig = $headers["X-Line-Signature"];
if ($sig != $compSig) {
exit('bad request.');
}
}
利便性の向上を図る
コードの見やすさや今後のことを考えて、LINEサーバーとのやりとりの部分を関数としてまとめました。
//一斉送信
function broadcast_exec($messages){
$ch = curl_init('https://api.line.me/v2/bot/message/broadcast');
$line = [
'messages' => $messages
];
send_exec($ch, $line);
}
//返信
function reply_exec($replyToken, $messages){
$ch = curl_init("https://api.line.me/v2/bot/message/reply");
$line = [
'replyToken' => $replyToken,
'messages' => $messages
];
send_exec($ch, $line);
}
function send_exec($ch, $line){
global $channelToken;
$line = json_encode($line);
$headers = [
'Authorization: Bearer ' . $channelToken,
'Content-Type: application/json; charset=UTF-8',
];
$options = [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => $headers,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HEADER => true,
CURLOPT_POSTFIELDS => $line,
];
curl_setopt_array($ch, $options);
curl_exec($ch);
curl_close($ch);
}
最終的な本体はこんな感じになりました。line-bot-utilities.phpを読み込むことで、署名検証部分と返信実行部分が1行で書けるようになります。また、今回は省略しますが、line-bot-functions.phpに受信内容に応じて返信内容を決定する処理を記述しています。
http_response_code(200);
require_once ('./line-bot-utilities.php');
require_once ('./line-bot-functions.php');
$channelToken = ''; //チャンネルトークン
$channelSecret = ''; //チャンネルシークレット
$jsonString = file_get_contents('php://input');
signature_validation($jsonString); //署名検証
$jsonObject = json_decode($jsonString);
$replyToken = $jsonObject->{"events"}[0]->{"replyToken"};
$messages = reply_type_select($jsonObject); //受信内容に応じて返信内容を決定する関数
reply_exec($replyToken, $messages); //返信実行
おわりに
なんやかんや改造してきましたが、「公式LINEに記事の投稿を知らせる」「ユーザーの入力に応じた返信をする」という当初の目標が達成できたので、LINEBotの開発はしばらくお休みにしたいと思います。これから忙しいしね。
これまで脆弱性とかを考えてプログラミングするような機会はあまり無かったので、よい経験になったと思います。サーバー上に配置するプログラムなんかは特に気を付けないと、何されるかわかったもんじゃないです。皆さんも気を付けましょう。
別の話ですが、ローカル上のVSCode(テキストエディタ)でレンタルサーバー上のファイルを読み書きできるようにしたかったのですが、どうやらOSのバージョンが古くて(CentOS 6)リモート操作に必要なライブラリがインストールされておらず、できませんでした。コマンドライン(背景が黒いやつ)で編集するのは御免被りたいので、仕方なくローカルのVSCodeからコピペしています。もっといい方法があればいいのですが。
コメント