Railsアプリケーションの
脆弱性動的自動検査
2019-08-16 Cookpad 夏季就業型インターン成果発表会 中間報告
@hakatashi
(中間成果報告)
@hakatashi
- 大学4年生
- インターン (高難易度技術コース, ~8/30)
- Webエンジニア
- フロントエンド得意マン
- 趣味
- ルービックキューブ
- 小説
- CTF
- アイマス
- Twitter: @hakatashi
- GitHub: @hakatashi
- hakatashi.com
脆弱性に対処する
- 脆弱性を生まない
- 適切なフレームワークを使う
- 脆弱性を発見する
- 人間が頑張る
- エンジニアが頑張る
- 報奨金制度
- 自動で脆弱性を見つける
- 静的検査
- 動的検査 ←今回のターゲット
- 人間が頑張る
静的検査
特にRailsに特化した静的脆弱性検査ツールとして、
brakemanが有名
class UsersController < ApplicationController
def update
id = params[:user][:id]
user = User.where("id = '#{id}'")[0]
end
end
静的検査の限界
複雑な脆弱性に対しては
検出されない or
確証を持って脆弱と言えない
# app/controllers/admin_controller.rb
class AdminController < ApplicationController
def analytics
if params[:field].nil?
fields = "*"
else
fields =
params[:field].map {|k,v| k }.join(",")
end
if params[:ip]
@analytics =
Analytics.hits_by_ip(params[:ip], fields)
else
@analytics = Analytics.all
end
end
end
# app/models/analytics.rb
class Analytics < ApplicationRecord
scope :hits_by_ip, ->(ip, col = "*") {
select("#{col}")
.where(ip_address: ip)
.order("id DESC")
}
end
/admin/analytics?field[(select+group_concat(password)+from+users+where+admin=%27t%27)]=f で発火 →
静的検査の限界
一般的な静的解析ツールでは、
「確実に脆弱と言えるもの」だけでなく、
「部分的に見れば脆弱かもしれない」ものまで報告される
→検出の精度が低い
動的脆弱性解析
動的脆弱性解析
実際に動いているアプリケーションに対して
攻撃を仕掛け、脆弱性が存在するかどうか
確認する
動的解析の利点
-
実際に攻撃が通ったかまで検証できるので、
偽陽性を極力少なくすることができる- 逆に、偽陰性は増える
- つまり、動的解析で発見された脆弱性は
「確実に直さないとヤバい」
欠点
- 到達不能なアドレスは検知できない
- 到達不能なパラメーターは検知できない
- 重い
Ruby on Rails に特化した
動的脆弱性検査
インターンでの成果物
Railsアプリケーションの良さ
- Rails way に則っていれば
アプリケーションの構成は
基本的にどれも一緒 - Rails固有の処理に対応した
脆弱性検査が可能
動的解析の欠点に対応
- 到達不能なアドレスは検知できない
- →Railsならroutes.rbを見れば一発
- 到達不能なパラメーターは検知できない
- →静的解析を組み合わせて対処
- 重い
- →Controllerのメソッド単位の呼び出しで
オーバーヘッドを最小限に
- →Controllerのメソッド単位の呼び出しで
デモ
対象の
Railsアプリ
DB
③アクセス
を監視
ファイル
システム
攻撃
スクリプト
②攻撃
ペイロード
①静的解析でURLと
パラメーターを取得
④実際に攻撃が発火したか
確認する
レスポンス
(XSSなどを検証)
今後
- 汎用的なRailsアプリケーションに対して
実行可能なgemにまとめる - SQLインジェクション以外の脆弱性にも
対応する - パラメーターの抽出精度を上げる
- Railsのいろんなバージョンに対応する
おまけ (時間があれば)
URLパラメーターの抽出
残念ながらRailsのURLパラメーターは
統一的なインタフェースでアクセスできない。
現在、パラメーターの抽出はRubyのコードをパースして
静的解析で抽出している。
一言で言うとparams変数を見るだけだが⋯⋯
if params[:hoge] == 'fuga'
# ここに脆弱なコードを入力
end
user = User.find_by(id: params[:user_id])
return not_found unless user.present?
# ここに脆弱なコードを入力
if params[:password] == params[:password_confirm]
# ここに脆弱なコードを入力
end
if params[:user][:password].present?
# ここに脆弱なコードを入力
end
class UserController
before_action :set_user
def show
# ここに脆弱なコードを入力
end
private
def set_user
@user = User.find_by(id: params[:user_id])
return not_found unless @user.present?
end
end
%i[user password].each do |keyword|
return bad_request if params[keyword].nil?
end
# ここに脆弱なコードを入力
class UserController
def show
parameters = user_params
# ここに脆弱なコードを入力
end
private
def user_params
params.require(:user).permit(:name, :email)
end
end
パターンが多くて大変!
→rspec-mockのdoubleみたいな手法で
paramsへのアクセスも動的に解析する?
パラメーターの抽出は今後の課題
おわり
Railsアプリケーションの動的脆弱性自動検査 (中間成果報告)
By Koki Takahashi
Railsアプリケーションの動的脆弱性自動検査 (中間成果報告)
2019-08-16 Cookpad 夏季就業型インターン成果発表会 中間報告
- 1,281