Shogo's Blog

Sep 23, 2014 - 1 minute read - perl

Github::Hooks::ReceiverがX-Hub-Signatureをサポートしました

Github::Hooks::ReceiverにX-Hub-SignatureをサポートするPull Requestを送ったら、 速攻取り込まれ、さらにGithubのコミット権とPAUSEのco-maintパーミッションをもらったというお話。

X-Hub-Signature

GithubのWebhookは大変便利なんですが、特に対策をしないままだと 他の人にcurlとかで叩かれてしまう可能性があります。 本来であればIPアドレスで制限をかけるべきなんですが、 iptablesの設定とかよくわからないし・・・と思ってGithubのドキュメントを読んでいたら、 もっとお手軽な方法発見。

GithubからのリクエストにはX-Hub-Signatureというのがついていて、 これを使うとPayloadの検証ができるらしい。 Github::Hooks::Receiverは このヘッダを全くみていないようだったのでPull Requestを送ってみた

Github::Hooks::Receiver 0.02以降で、以下のようにsecretの指定ができるようになります。

use Github::Hooks::Receiver::Declare;
my $receiver = receiver {
    secret 'secret1234'; # Webhookの設定画面のsecretの項目と同じものを入力
    on push => sub {
        # レポジトリにPushされた時の処理とかをゴニョゴニョ書く
    };
};
my $psgi = $receiver->to_app;
$receiver->run;

これでsecretを知らない人がリクエストを偽装できなくなるので安心です。 secretはエントロピーが高いほうがいいので ruby -rsecurerandom -e 'puts SecureRandom.hex(20)' みたいなコマンド使うといいらしいですよ。

String::Compare::ConstantTime

Signatureの比較にはRubyのsecure_compareのような関数を 使ったほうがいいらしい。 Github::Hooks::Receiverでは、そのPerl版のString::Compare::ConstantTimeを使ってみた。 ちょっと引数のチェックに甘いところがあって、segmentation fault場合があったので、こちらにもPull Requestを送っておきました。 Github::Hooks::Receiverは使う前にチェックを入れてあるので、現行バージョンでも問題なく動くはず。

String::Compare::ConstantTimeはXSで書かれたモジュールなんですが、 この手のバグが入り込みやすいのでXS難しいですね。

まとめ

  • XS怖い
  • Github::Hooks::Receiverにsecretを指定できるようになったので、IP制限がかけられない場合でも安心
  • でも、可能であればIP制限もしましょうね
  • XS怖い

追記

IP制限について

Songmu先生よりコメントをいただきました。

確かにPlack::Middlewareとか使えばお手軽に弾けるので、 X-Hub-SignatureだけでなくIP制限もやっておくと良いですね。

String::Compare::ConstantTime

String::Compare::ConstantTime ですが、僕のprが取り込まれた 0.310 がリリースされました。 undef を渡すとsegmentation fault で落ちるというバグが修正されています。 XS怖い。

SEE ALSO