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先生よりコメントをいただきました。
これはいい機能。ちなみにIP制限は、Nginxとかでやるのがお手軽で、plackで完結させたいのであれば、Plack::Middlewareで弾いてやればいいと思います。 / “Github::Hooks::ReceiverがX-…” http://t.co/NM0uQzW1s8
— songmu (@songmu) 2014年9月23日
確かにPlack::Middlewareとか使えばお手軽に弾けるので、 X-Hub-SignatureだけでなくIP制限もやっておくと良いですね。
String::Compare::ConstantTime
String::Compare::ConstantTime ですが、僕のprが取り込まれた 0.310 がリリースされました。
undef
を渡すとsegmentation fault で落ちるというバグが修正されています。
XS怖い。