webセキュリティについて勉強中なので、学習内容を公開します
スカスカ記事ですがお許しください
#演習環境
- Ruby (2.6.6)
- Rails (5.2.4.3)
- database adapter mysql2 (0.5.3)
- mysql (5.7.30)
記事投稿、コメント投稿、ブックマークなどが出来る演習用アプリ「TARGET」
GitHubリポジトリ https://github.com/Fumitaka1/target
#SQLインジェクション脆弱性とは
外部から受け取ったパラメータからSQL文を作成し、DBを操作しているプログラムに起こりうる脆弱性のこと
例 ユーザーの一覧を表示できるサイトがあります
'小'で検索するとユーザー名に'小'を含むユーザーが表示されます
発行されるSQL文 SELECT `users`.* FROM `users` WHERE (name LIKE '%小%')
以下の攻撃用文字列で検索するとハッシュ化されたパスワードが表示されます。
&&') UNION SELECT 1, encrypted_password, 3,4,5,6,7,8,9,10,11 FROM target_development.users;#
発行されるSQL文
SELECT `users`.* FROM `users` WHERE (name LIKE '%&&') UNION SELECT 1, encrypted_password, 3,4,5,6,7,8,9,10,11 FROM target_development.users;# %')
※攻撃文字列に必要なデータベース名やカラム名はinformaiton_schemaから取得可能です
#なぜ発生するのか
外部からのパラメータにSQLの特殊文字が含まれていて、想定外のSQL文が発行されることが原因
上記の例では
1.検索文字列の&&')
によって正規のSELECT文が不正に終端される。
2.続きの文字列UNION SELECT 1, encrypted_password, 3,4,5,6,7,8,9,10,11 FROM target_development.users;
がそのままSQLとして発行される。
演習用サイトでは外部からのパラメータをそのまま受け取ってSQL文を発行する脆弱な処理が含まれている
def index
@users = User.where("name LIKE '%#{params[:q]}%'")
end
#どう防ぐか
###1.外部からのパラメータに含まれる特殊文字を安全な文字に置き換える
def index
sanitized_q = params[:q].gsub(/\'/,'\\\'') if params[:q]
@users = User.where("name LIKE '%#{sanitized_q}%'")
end
###2.プレースホルダを利用してSQL文を発行する
def index
@users = User.where("name LIKE ?","%#{params[:q]}%")
end
###RailsにはSQL特殊文字のフィルタが用意されている
- Model.find(id)
- Model.find_by_hoge(fuga)
- Model.where(hoge: fuga) #ハッシュを使うとプレースホルダと同等
##学んだこと
SQLインジェクションはよく知られた脆弱性であるため、フレームワーク側で対応策が用意されているが、外部パラメータからSQL文を作成する場合には十分注意を払う。
ORMのおかげでSQLを書く機会が少なかったが、この機会にSQLを掘り下げることが出来た。