この記事は GMOアドマーケティング Advent Calendar 2020 14日目の記事です。
はじめに
こんにちは、GMOアドマーケティングのR.Yです。今回はタイトルの通り、Railsで作った脆弱性をOWASP ZAPで診断してみたいと思います。
自分は主にRailsを使ったWebアプリの開発やWebアプリの脆弱性診断を行うことが多いので、この記事を書くことによってRailsのセキュリティ周りや脆弱性診断を行うツールについての理解をより深められたら良いなと思います。
1.用意するもの
Ruby On Rails 5.2.3
OWASP ZAP 2.9.0
2.調べる脆弱性
- SQLインジェクション
2-1.SQLインジェクション
SQLインジェクションとはWebアプリのリクエストで送られるパラメータを意図的に操作し、データベースを操作するクエリに対して行われる攻撃手法です。
例:
1 |
User.where("name = '#params[:name]'") |
例えば↑のような名前を入力してユーザーを検索するフォームがある場合、
‘OR 1) — のような文字列を入力すると、実行されるSQLは
1 |
SELECT * FROM users WHERE (name = '' OR 1 )--' |
このようになります。
検索条件を入れたいセミコロンがすぐに閉じられ全てのデータにマッチする条件が加えられています。また「- -」により以降がコメントとして扱われるので構文エラーも出ません。これにより全てのユーザーを不正に取得することができてしまいます。
また、入力の文字列を‘ OR 1); DELETE FROM user; — ‘にすれば、
1 |
SELECT * FROM users WHERE (name = '' OR 1); DELETE FROM user; --' |
DBに登録されている全ユーザーを消滅させるクエリを生成することもできてしまいます😱
2-2.Railsでの対策
RailsではwhereなどのSQLフラグメントを使う場合、SQLを直接文字列で作るような書き方をしない限り「’」「”」などの特殊文字は自動でエスケープされます。
- 良い書き方の例:
1 2 |
User.where(name: params[:name]) User.where("name = ?", params[:name]) |
この書き方をした場合、先ほどの‘OR 1) —で入力によって生成されるSQLは
1 |
SELECT * FROM users WHERE name = '\' OR \'1\) --' |
このようにエスケープされます。
3.作業手順
続いて脆弱性を実際のRailsアプリに忍ばせて脆弱性診断を行っていきます。
以下の手順で説明していきます。
- 脆弱性診断を行うWebアプリをRailsで開発する
- 脆弱性を仕込む
- OWASP ZAPで脆弱性診断する
4.脆弱性診断を行うWebアプリをRailsで開発する
まずお好みのディレクトリに移動し以下を実行します。
1 |
rails new test-app |
これでtest-appアプリケーションが作成されます。
4-1.データベースとモデルの作成
test-app/に移動し、データベースを以下のコマンドによって作成します。
1 |
rake db:create |
次に今回使用するユーザーモデルを作成します。
1 |
rails generate model user |
これによってapp/models/にuser.rbが作成されました。
しかし、まだデータベース上には反映されていないのでマイグレーションを流します。
先ほどのコマンドでdb/migrate/に#{作成された日時}_create_users.rbというファイルが作成されたので
1 2 3 4 5 6 7 8 9 |
class CreateUsers < ActiveRecord::Migration[5.2] def change create_table :users do |t| t.string :name #追加した箇所 t.timestamps end end end |
t.string :nameを追加して保存します。
最後に
1 |
rake db:migrate |
このコマンドによって作成したマイグレーションファイルをデータベースに反映させます。
これでデータベースとモデルの作成はOKです!
4-2.コントローラーの作成
test-app/に移動し以下を実行します。
1 |
rails generate controller user |
これでユーザーコントローラーが作成されました。
そして、app/controllers/に移動し、先ほどのコマンドで作成されたusers_controller.rbを以下のように編集します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
class UserController < ApplicationController # 以下を追加 def index if params[:name].present? @users = User.where('name LIKE ?', "%#{params[:name]}%") else @users = User.all end end def new end def create user = User.new(name: params[:name]) user.save redirect_to user_index_path end # ここまで end |
コントローラーはこれでOKです!
4-3.ビューの作成
今回作るのはユーザー一覧画面と新規作成画面の二つなので、app/viewsに移動しuserディレクトリを作成しておきます。
そしてapp/views/user/に以下の二つのファイルを入れておきます。
- index.html.erb
1 2 3 4 5 6 7 8 9 10 11 |
<h1>脆弱性診断用サイト!!</h1> <%= link_to "ユーザー新規作成", user_new_path %> <br><br> <h3>ユーザー一覧</h3><%= form_with method: :get, local: true do |f| %> <%= f.text_field :name %> <%= f.submit :search %> <% end %> <% @users.each do |user| %> <%= user.name %> <% end %> |
- new.html.erb
1 2 3 4 5 6 |
<h1>ユーザー新規作成</h1> <%= form_with model: @user, url: user_create_path do |f| %> <%= f.label :name, '名前' %> <%= f.text_field :name %> <%= f.submit "送信" %> <% end %> |
これで簡単なアプリケーションができました。
1 |
rails s |
でサーバを起動してから、http://localhost:3000/やhttp://localhost:3000/newにアクセスし、
こんな感じの画面が出てきたらOKです!
5.脆弱性を仕込む
今回はSQLインジェクションの脆弱性を確かめるために、users_controller.rbのindexメソッドを
1 2 3 4 5 6 7 8 9 10 |
def index if params[:name].present? # 変更前 # @users = User.where('name LIKE ?', "%#{params[:name]}%") # 変更後 @users = User.where("name LIKE '#{params[:name]}'") else @users = User.all end end |
このように変更します。
これによって検索フォームの入力の文字列から直接SQLが生成されるので、「2-1.SQLインジェクション」のようなSQLインジェクションに対しての脆弱性を作ることができました。
6.OWASP ZAPで脆弱性診断する
続いて作った脆弱性をOWASP ZAPで診断していきます。
6-1.OWASP ZAPとは
OWASP ZAPとはOWASP(The Open Web Application Security Project)という国際的なコミュニティによって作られたセキュリティ診断ツールになります。OWASP ZAPを使うことで誰でも無料でWebアプリケーションの脆弱性診断を行うことができます。
※OWASP ZAPのインストール手順は省略します。
OWASP ZAPのダウンロード
6-2.プロキシの設定
OWASP ZAPでは、自身をプロキシとすることで脆弱性診断の対象サイトにリクエストを送信し返ってきたレスポンスから脆弱性を診断します。そのためWebブラウザとOWASP ZAPで設定をする必要があります。
6-2-1.OWASP ZAPの設定
まずOWASP ZAP起動後メニューバーの「ツール」→「オプション」をクリックします。するとオプション画面が開くので、
「ローカル・プロキシ」を↑のように変更後OKを押します。これでOWASP ZAP側のプロキシ設定が完了しました!
6-2-2.Webブラウザの設定
今回はfirefoxを使用していきます。まずfirefoxを開き「設定」から、
「一般」の一番下にあるネットワーク設定の「接続設定…」をクリックします。
ポートをOWASP ZAPの8084に合わせたいので画像のように入力しOKを押します。これでWebブラウザ側の設定も完了です!
6-3.脆弱性診断
まずはじめにモードがプロテクトモードになっていることを確認しましょう!
攻撃モードや標準モードに選択されている場合、自身が管理していない別のサイトも一緒にスキャンしてしまう恐れがありますので、ここは常に確認しておきましょう。
モードの確認が終わったところで「クイックスタート」の中の「Manual Explore」をクリックします。
先ほど作ったWebアプリが起動していることを確認後、↑のように入力し「Launch Browser」をクリックします。これによって行われる静的スキャンでは次に行う動的スキャンの準備を行います。firefoxで対象のサイトが開くと思うので、一覧画面や新規作成画面、またはユーザーの検索や新規作成を行いサイトを巡回しましょう。
これによりOWASP ZAPのサイドバーに対象のサイトが表示されるかと思います。
このままでは動的スキャンできないので一度対象のサイトをコンテキストに含める必要があります。対象サイトを右クリックで「コンテキストに含める」→「New Context」をクリックし、そのままOKを押しましょう。これによってコンテキストの箇所に対象のサイトが加わったはずです。
ここまで出来たら一度SQLインジェクション診断用のアドオンをインストールします。メニュー欄にある↓のマークをクリックしましょう。
すると「アドオン管理」のウィンドウが出てくるので「マーケットプレイス」から「Advanced SQLInjection Scanner」をインストールしましょう。
インストール済みに「Advanced SQLInjection Scanner」があることが確認できれば準備OKです。
それでは準備ができたので動的スキャンしていきます。先ほどコンテキストに含めた自身のサイトを右クリックしましょう。すると動的スキャンがあるのでクリックすると動的スキャンの設定画面が出るはずです。
特に何もせず「スキャン開始」を押しましょう!これで動的スキャンが開始されます。
6-4.アラートの確認
動的スキャンが終了すると「アラート」に検出された脆弱性が表示されます。
見事SQLインジェクションが検出されました!🎉
他にもたくさんのアラートがありますがSQLインジェクションが確認できればOKです。
6-5.実際に脆弱性診断してみる
お試しSQLインジェクションをするために以下のようなユーザーを作成しました。
‘ OR id = 3) —入力して、
SQLインジェクションが成功しidが3のユーザーのみ取得することができました!
ログでみると
SELECT “users”.* FROM “users” WHERE (name = ‘ ‘ OR id = 3) –‘)
が実行されていることがわかります。
まとめ
今回はRailsの脆弱性診断について書いてみました。
脆弱性診断をやっていく中で、既存の脆弱性やその対策などいろいろ勉強になったのでこれからの開発に役立てていきたいです。また、今回書けなかった他の脆弱性についても今後書いていけたらなと思います。
ここまで読んでいただきありがとうございました!
明日は、KazuakiMさんによる「Header Bidding導入」です。
引き続き、GMOアドマーケティング Advent Calendar 2020 をお楽しみください!
■エンジニア採用ページ ~福利厚生や各種制度のご案内はこちら~
https://www.gmo-ap.jp/engineer/
■noteページ ~ブログや採用、イベント情報を公開中!~
https://note.gmo-ap.jp/
Ruby on Railsを使った開発、プロダクトの脆弱性診断などをやってます
オレンジ色と犬と猫と食べることと歌うこととピアノが好きです。