SysAd班の@xxarupakaxxです。普段は、部内サービスの開発・運用を担当するSysAd班というチームで活動していたり、Game班としてゲームを作ったりしています。
今回のSysAdTechBlogはサークル内における制度についてです。
前回のSysAdTechBlogはこちらから読めます。
BugBountyとは?
バグバウンティは、サービスやプログラムの提供者がサービスの脆弱性報告に対してインセンティブを設けることで、外部の開発者による脆弱性診断を促進する制度です。これに習い、traPでもSysAd班が開発しているサービスの脆弱性を発見すると、タダ飯もしくはそれ相当のアマゾンギフト券がもらえるという仕組みでバグバンティを導入しています。
具体的には、以下のように報酬が分類されています。
焼肉級(~5000円)
- 機密性への影響が高い
- 機密情報や重要なシステムファイルが参照可能
- 完全性への影響が高い
- 機密情報や重要なシステムファイルの改竄が可能
- 可用性への影響が高い
- リソース(ネットワーク帯域、プロセッサ処理、ディスクスペースなど)を完全に枯渇させたり、完全に停止させることが可能
Ex.
- 他人のDMを見る
- 重要な設定ファイルを見る
- 他人の投稿を書き換える
- サーバプロセスを起動不可にする
- 不正に他人になりすましできる
拉麺級(~1000円)
- その他、インシデントに繋がる可能性のある想定されていない挙動
Ex.
- ブラウザ上でのJavaScriptコードの実行
- サーバープロセスを一時的に落とす
無等級
- 仕様
- 一部妥協してセキュリティレベルを下げている場合
実際にはBugBounty制度が始まってからの2年間で、6回の報告がありました。
導入した経緯
サービスに求められる項目のうち、セキュリティの重要度は年々上がってきています。もちろんSysAd班でも、セキュリティには気を配りながら開発や運用[1]を行っています。一方で、どれだけ開発中に気をつけていても実装の不備による脆弱性を完全に防ぐことは難しく、依存しているプログラムの脆弱性が後から発覚することもあります。
このような脆弱性を発見するとともに、セキュリティに対する意識や技術の向上を狙いに、BugBountyを導入しました。
実際の事例1
traPでは部内SNSであるtraQや部内アンケートanke-toなどのサービスを開発・運用しています。BugBounty制度によって、このふたつのサービスでReDos脆弱性が報告されました。ここではanke-toの例を紹介します。
ReDoS攻撃ってなに?
ReDoS攻撃はDoS攻撃の一種です。
DoS攻撃は、マシンやネットワークのリソースを正常に使用できない状態にすることで、サービスの可用性を侵害するような攻撃手法です。DoS攻撃は主に、大量のリクエストや巨大なデータを送りつけるなどしてサービスを利用不能にするFlood型の攻撃と、今回のReDoS攻撃のようにサービスの脆弱性を利用するタイプの攻撃に分類できます。
ReDoS攻撃では、正規表現を入力として受け取るようなサービスの機能に、処理に長い時間を必要とする入力を与えることでマシンリソースを占有します。
一般的な対策としては「入力文字数を制限する」「特定の正規表現を用いない」「タイムアウトを設定する」などがあげられます。
概要
anke-toには作成したアンケートを検索するという機能があります。その実装は与えられた文字列を解析し正規表現を用いて検索ができるというものでした。[2]つまり処理時間のかかる正規表現を検索欄に書くことで処理時間が多くかかる入力を簡単にリクエスト可能だったということです。例えば、
- タイトルがaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaアンケートを何個か作成する
- ([a-z]?){0,50}[[a-z]]{50} を検索欄に入れて検索を実行する
上記の正規表現の処理が高負荷になる仕組みについてはここでは割愛しますが、上記のような操作によってanke-toがデプロイされているサーバーのマシンリソースを占有することが可能です。その場合、他のリクエストに対して正常に応答できない可能性があります。また、同じサーバーに存在する他のサービスが影響を受けることも考えられます。
対応
anke-toのサーバーはGoで実装されていてechoというWebフレームワークを使用しています。echoが提供しているミドルウェアを使って、ユーザーID単位でのレートリミットを設けると同時に、正規表現の実行時間に制限を設ける事で対応しました。この脆弱性を見つけた方には、サーバープロセスを一時的に落とす可能性があったため拉麺級の報酬を差し上げました。
実際の事例2
traPでは認証の一つにtraP_tokenという署名のようなものを使用して認証を行う方法があります。そのtraP_tokenが流出した場合、そのtokenを使用してtraPの部員になりすますことが可能です。流出した事例は確認できる範囲で一度あり、その際の対応として流出したtokenと完全一致したものについては検証側で無効と判断するという対応を施しました。ですが、jwt-goの実装を確認すると
// Decode JWT specific base64url encoding with padding stripped
func DecodeSegment(seg string) ([]byte, error) {
if l := len(seg) % 4; l > 0 {
seg += strings.Repeat("=", 4-l)
}
return base64.URLEncoding.DecodeString(seg)
}
となっており、シグネチャが4の倍数の長さでなかったときは4の倍数にするために=でパディングの付与を行っています。
つまり、traP_tokenのシグネチャの長さが4の倍数でないときはtokenの最後に=を1つ付与するなど上記の関数と同じような処理をすることで、tokenの無効化を回避することが可能でした。
補足として今回の場合、jwt-goのバージョンがv3.2.2以降ではパディングを付与されているものはデコードできない実装に変更されたため、実際には上記の攻撃は不可能でした。
最後に
今回挙げた事例は最近に発見されたものです。これらを機にtraP全体でBugBounty制度というものが周知されたかと思います。
今後、BugBounty制度を通してtraP全体でセキュリティ意識を高めていきたいですね。