More Related Content
Similar to Railsエンジニアのためのウェブセキュリティ入門 (20)
More from Hiroshi Tokumaru (20)
Railsエンジニアのためのウェブセキュリティ入門
- 3. 徳丸浩の自己紹介
• 経歴
– 1985年 京セラ株式会社入社
– 1995年 京セラコミュニケーションシステム株式会社(KCCS)に出向・転籍
– 2008年 KCCS退職、HASHコンサルティング株式会社(現社名:EGセキュアソリューションズ株式会社)設立
• 経験したこと
– 京セラ入社当時はCAD、計算幾何学、数値シミュレーションなどを担当
– その後、企業向けパッケージソフトの企画・開発・事業化を担当
– 1999年から、携帯電話向けインフラ、プラットフォームの企画・開発を担当
Webアプリケーションのセキュリティ問題に直面、研究、社内展開、寄稿などを開始
– 2004年にKCCS社内ベンチャーとしてWebアプリケーションセキュリティ事業を立ち上げ
• 現在
– EGセキュアソリューションズ株式会社 代表 https://www.eg-secure.co.jp/
– 独立行政法人情報処理推進機構 非常勤研究員 https://www.ipa.go.jp/security/
– 著書「体系的に学ぶ 安全なWebアプリケーションの作り方」(2011年3月)
同 第2版が 2018年6月21日発売
「徳丸浩のWebセキュリティ教室 」(2015年10月)
– 技術士(情報工学部門)
Copyright © 2017-2019 Hiroshi Tokumaru 3
- 4. 基本的なこと
• Ruby on Railsは基本的な脆弱性(SQLインジェクション、XSS、CSRF
等)はデフォルトで対応している
• Ruby on Railsでアプリケーションを開発していて脆弱性になるパター
ンは以下の通り
– Ruby on Railsが対応していない脆弱性
• 実装レベルもの…Railsが対応できない例外的なもの
• 設計に依存するものや、脆弱な仕様…これはRailsと言えども救いようがない
– Ruby on Railsのルールに従わずに書いた場合
Copyright © 2017-2019 Hiroshi Tokumaru 4
- 5. 3分間クッキングデモ
• 極小のブックマークアプリを作ります
$ rails new bookmark_app
$ cd bookmark_app
$ rails generate scaffold bookmark site:string url:string
$ rails db:migrate
• Viewを修正して、リンク表示になるよう link_to メソッドを使う
Copyright © 2017-2019 Hiroshi Tokumaru 5
- 18. 正規表現の ^ $ は「行の先頭末尾」を示す
• Rubyに限らず、正規表現の ^ と $ は「行の」先頭と末尾
• でも、PHPやPerlでは問題になりにくい
– PHPやPerlの場合、データ内の改行を無視して「一行のデータ」として扱う
– Rubyの場合、データ内の改行が有効化して、複数行のデータとして扱う
• その結果、以下のようになる
javascript:alert(1)/*
http://example.jp/*/ ← こちらが、 /^http:/// にマッチ
Copyright © 2017-2019 Hiroshi Tokumaru 18
行の先頭
- 22. 以下のエラーが表示される
Copyright © 2017-2019 Hiroshi Tokumaru 22
この正規表現は複数行のアンカー(^または$)を使用
しているため、セキュリティ上のリスクが生じる可能性
がある。
Aと zを使うつもりだったか、または
:multiline => trueオプションを追加するのを忘れた
か?
- 25. ここまでのまとめ
• マイクロブックマークアプリを作った
• Ruby on Railsの機能により、SQLインジェクション対策やHTMLエス
ケープ処理はなされていた
• Javascriptスキームを用いたXSSは対策されていなかった
• 正規表現によるバリデーションを追加したが、行頭一致の ^ を使った
ために脆弱性が残った
• Ruby on Railsのバリデータで ^ $ を使うとエラーになる
• ^ の代わりに A を使うと、脆弱性は解消された
• 教訓: 自己流でやらずにRailsの流儀に(レールに乗る)従う方が安全
性が高い
Copyright © 2017-2019 Hiroshi Tokumaru 25
- 31. シェルにおける ; の意味は?
Copyright © 2017-2019 Hiroshi Tokumaru 31
Open3.capture3("echo a; sort >&2", :stdin_data=>"foo¥nbar¥nbaz¥n")
; sort は echo コマンドに続けてsort コマンドを実行するという意味
Open3.capture3("cmd #{params[:p]}", :stdin_data=>"foo¥nbar¥nbaz¥n")
params[:p] に ; xxx を入れたら、xxxコマンドが実行できる
- 32. シェルにおける ; の意味は?
Copyright © 2017-2019 Hiroshi Tokumaru 32
Open3.capture3("echo a; sort >&2", :stdin_data=>"foo¥nbar¥nbaz¥n")
; sort は echo コマンドに続けてsort コマンドを実行するという意味
Open3.capture3("cmd #{params[:p]}", :stdin_data=>"foo¥nbar¥nbaz¥n")
params[:p] に ; xxx を入れたら、xxxコマンドが実行できる
Open3.capture3("echo a; sort >&2 "
- 33. シェルにおける ; の意味は?
Copyright © 2017-2019 Hiroshi Tokumaru 33
Open3.capture3("echo a; sort >&2", :stdin_data=>"foo¥nbar¥nbaz¥n")
; sort は echo コマンドに続けてsort コマンドを実行するという意味
Open3.capture3("cmd #{params[:p]}", :stdin_data=>"foo¥nbar¥nbaz¥n")
params[:p] に ; xxx を入れたら、xxxコマンドが実行できる
Open3.capture3("echo a; sort >&2 "#{params[:p]}
ここを変数にすると
OSコマンドインジェクション脆弱性
- 35. OSコマンドインジェクションの影響と対策
• 影響
– 任意のコマンドが実行されてしまうので影響は非常に大きい
– wgetコマンド等を利用して攻撃スクリプトを外部からダウロードされる
– 外部からは攻撃できないが、内部からは攻撃できる脆弱性による権限昇格(Local Exploit) → root
権限の奪取
– ファイルの更新(改ざん)、削除、作成
– システムの停止
– 外部のサーバーに対する攻撃(踏み台)
• 対策:以下のいずれかを実施する
– 外部コマンドを起動する実装を避ける
– シェルの呼び出し機能のある関数を避ける
Open3.capture3(‘command’, parameter, …) # コマンドとパラメータを分離する
Kernel#open() や File.read() (Ruby 2.6未満)はパイプ記号でコマンドを起動できる
例: File.read("|cat /etc/passwd")
– 外部からのパラメータをコマンドラインに渡さない
例: sendmailコマンドの –t オプション
35Copyright © 2017-2019 Hiroshi Tokumaru
- 38. クロスサイト・リクエストフォージェリの原理
Copyright © 2017-2019 Hiroshi Tokumaru 38
POST /45/45-003.php HTTP/1.1
Referer: http://example.jp/45/45-002.php
Content-Type: application/x-www-form-urlencoded
Host: example.jp
Cookie: PHPSESSID=isdv0mecsobejf2oalnuf0r1l2
Content-Length: 9
pwd=pass1
POST /45/45-003.php HTTP/1.1
Referer: http://trap.example.com/45/45-900.html
Content-Type: application/x-www-form-urlencoded
Host: example.jp
Cookie: PHPSESSID=isdv0mecsobejf2oalnuf0r1l2
Content-Length: 9
pwd=pass1
正常系のHTTPリクエスト
CSRF攻撃時のHTTPリクエスト
Referer
以外は変
わらない
- 39. CSRFはなぜ危険か?
• CSRFとは…
– FORMのACTIONってクロスドメインで指定できるよね
– だから、FORMを踏ませる罠が作れるよね
– 投稿、パスワード変更、購入、設定変更…
– 攻撃者はFORMの実行結果は見られないので、DB更新や削除などが問題となる
• 最悪ケースの危険性は、SQLインジェクションやXSSほどではない
• 脆弱性のあるページの機能の悪用にとどまる
• 脆弱性の発見が容易
• 脆弱性の悪用が容易
• 実際に悪用されている
Copyright © 2017-2019 Hiroshi Tokumaru 39
- 40. CSRF対策の方法は?
• Ruby on RailsはGET以外のリクエスト全てにトークンを要求する
• 素直にRuby on Railsを使う限り、CSRF脆弱にする方が難しいw
• 脆弱性が混入する主なパターン
– トークンのチェックを無効化してしまった
– Railsの流儀に従わずに処理を書いた(例: GETメソッドで更新処理を受け取る)
– わざとCSRFチェックを無効化する
protect_from_forgery :except => :create # デモを見よう
Copyright © 2017-2019 Hiroshi Tokumaru 40
- 43. Ruby on RailsでXSS脆弱にする方法
• 3分間クッキングで説明したように、基本的にRuby on Railsで開発し
たアプリケーションはXSS対策がなされている
– …が、例外もある
– URLを指定する href 属性や src 属性に javascript: スキームを入力する
– その他、後述の状況
• 以下を使えば、HTMLエスケープされないのでXSS脆弱になる
– <%== 文字列 %>
– <% raw 文字列 %>
– <% 文字列.html_safe %>
Copyright © 2017-2019 Hiroshi Tokumaru 43
- 45. XSSのデモ
• 先ほどのCSRF対策済みの掲示板でなりすまし書き込みをやってみよう
• 実行するスクリプトは下記のもの
Copyright © 2017-2019 Hiroshi Tokumaru 45
var s = document.body.innerHTML;
if (s.indexOf('<h1>徳丸' + '浩</h1>') >= 0 &&
s.indexOf('〇〇小学校を襲撃して' + '皆殺しにしてやる') < 0) {
var token = document.getElementsByName('authenticity_token')[0].value;
var req = new XMLHttpRequest();
req.open('POST', '/microposts');
req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
data = 'utf8=%E2%9C%93&commit=Postµpost%5Bpicture%5D=µpost%5Bcon
tent%5D=〇〇小学校を襲撃して' + '皆殺しにしてやる&authenticity_token='+encodeURICo
mponent(token);
req.send(data);
}
- 46. XSSはなぜ危険か?
• XSSは、
– 利用者(被害者)のブラウザ上で
– 攻撃対象のドメイン(オリジン)で
– 攻撃者が自由にJavaScriptを実行できる
• これって、ウイルス?
– ウイルスではないが、結果としてウイルスと同じような被害
– XSSを悪用したウイルス(ワーム)はいくつかある
• ブラウザを乗っ取られたのと同じ
– 影響範囲はXSS脆弱性のあるページと同じドメイン(オリジン)
– 同一オリジン上はすべてのページが影響を受ける
※オリジン=ホスト名+スキーム+ポート番号
Copyright © 2017-2019 Hiroshi Tokumaru 46
- 48. XSSの対策
• 基本的にRuby on Railsの流儀に従えば大半の箇所を対策してくれる
• 以下に注意
– src属性、href属性等URLを受け取る属性 → URLのバリデーション
– JavaScriptの動的生成(とくに文字列リテラル)
– DOM Based XSS
Copyright © 2017-2019 Hiroshi Tokumaru 48
- 50. イベントハンドラ動的生成XSSの原理
• onclick="foo('<%= @msg %>')" にて以下を指定
@msg = "');alert('Cracked!')//"
• HTMLとしては以下が生成される
onclick="foo('');alert('Cracked!')//')"
• JavaScript処理系にはHTMLエスケープをデコードしてから渡される
foo('');alert('Cracked!')//')
Copyright © 2017-2019 Hiroshi Tokumaru 50
- 52. Dom Based XSS
Copyright © 2017-2019 Hiroshi Tokumaru 52
<body>
<script>
window.addEventListener("hashchange", chghash, false);
window.addEventListener("load", chghash, false);
function chghash() {
var hash = decodeURIComponent(window.location.hash.slice(1));
var color = document.getElementById("color");
color.innerHTML = hash;
}
</script>
<a href="#赤">赤</a>
<a href="#緑">緑</a>
<a href="#青">青</a>
<p id="color"></p>
</body>
脆弱な例: フラグメント識別子を表示するだけのスクリプト
- 53. DOM Based XSSの攻撃例
• Script要素による攻撃は有効にならない
<script>alert(1)</script> など
• img 要素のonerror属性などは攻撃に使える
<img src=# onerror=alert(1)>
• 上記を含むHTMLをinnerHTMLに挿入すると、JavaScriptが実行される
• document.writeであれば、script要素でも攻撃可能
Copyright © 2017-2019 Hiroshi Tokumaru 53
- 54. 対策: Dom Based XSS
• 『DOM Based XSS』に関するレポート に詳しい
• document.writeやinnerHTMLの使用を避ける
• DOM操作APIを用いる or 適切なエスケープ処理
• jQueryを用いる場合は html()メソッドではなく、text()メソッドを用いる
function chghash() {
var hash = window.location.hash;
var color = document.getElementById("color");
// color.innerHTML = decodeURIComponent(window.location.hash.slice(1)); // 脆弱
color.textContent = decodeURIComponent(window.location.hash.slice(1)); // 対策
}
Copyright © 2017-2019 Hiroshi Tokumaru 54
- 57. 脆弱なスクリプト例
• Ruby on Ralisを正しく使っていればSQLインジェクションは防げる
• だめな例1 whereメソッドの引数に値を埋め込んでいる
– @books = Book.where("price >= #{params[:price]}")
• だめな例2 演算子として外部パラメータを埋め込み
– @books = Book.where("price #{params[:op]} ?“, params[:price])
• だめな例3 orderメソッドに外部パラメータを指定
– @books = order ? Book.order(params[:order])
Copyright © 2017-2019 Hiroshi Tokumaru 57
Demo
- 59. SQLインジェクション対策
• Ruby on Railsの機能を素直に使うこと(原則)
• 以下に注意
– whereメソッドはプレースホルダを使う
– whereメソッドの式に外部からの値を含めない
Book.where("price <= ?", price)
– 演算子等はバリデーションか、配列参照で
– orderメソッドにも注意(以下のいずれか)
• 列名のバリデーション
• 列名をシンボルに変換する(シンボルだと列名としてエスケープされる)
※to_symによる対策の妥当性について意見をください!
Copyright © 2017-2019 Hiroshi Tokumaru 59
- 64. どうして暗号化ではなくてハッシュなの?
• 暗号化の場合、鍵の管理が難しい
• アプリケーションは鍵を使わなければならないが、攻撃者には鍵を見せたくない
• PSNの事件では、権限昇格されたことになっているので、暗号鍵も盗まれている
と想定せざるを得ない
• ハッシュだと鍵を使わないので、鍵管理のわずらわしさがない
• パスワードをサイト管理者にも知られたくないというニーズも
– 暗号化されたパスワードだと、サイト管理者やヘルプデスク担当者がパスワードを知り得るの
が嫌だ
– ヘルプデスクに見せないようにするには、サポート用画面の機能次第で可
– 管理者の悪事は総合的な対策が必要で、パスワードの問題だけではない
• PCI-DSS2.0 8.4項には「8.4 強力な暗号化を使用して、すべてのシステムコンポー
ネントでの伝送および保存中のすべてのパスワードを読み取り不能にする」とあ
り、ハッシュを求めてはいない
© 2016-2018 EG Secure Solutions Inc.
- 65. ハッシュで保存されたパスワードは本当に安全なの?
• 一般的に、(暗号論的)ハッシュ値から平文を「復元する」ことはできない
– 「password」のMD5ハッシュ: 5f4dcc3b5aa765d61d8327deb882cf99
• しかし、パスワードの場合は特別な事情がある
• 例:4桁の暗証番号をハッシュ値で保存している場合
– 全ての可能性は1万通りしかないのだから、総当たりで確認すれば、平文の暗証番号はすぐに
判明する
– 参考: https://z.tokumaru.org/2014/02/6php025.html
• 原理は8桁パスワードでも同じ
• ハッシュ保存の場合、アルゴリズムは攻撃者が知っている前提で安全な設計とす
る
– 平文パスワード以外は、すべて「ばれている」想定を置く
• 攻撃者にとって未知であることが保証された情報があれば、それを鍵として暗号
化すればよい。現実にはそのような保証がないから暗号化を用いない
© 2016-2018 EG Secure Solutions Inc.
- 70. 対策
• Ruby on Railsはパスワードの安全なハッシュ保存機能がある
• Rails Tutorialを勉強しましょう…余計なことはしない方が無難です
70
https://railstutorial.jp/chapters/modeling_users?version=5.1#sec-a_hashed_password
- 73. Ruby や Ruby on Railsの脆弱性も
https://gist.github.com/mala/bdcf8681615d9b5ba7814f48dcea8d60 より引用 73
- 74. プラットフォームの脆弱性対応
• 使用ソフトウェアのサポートライフサイクルポリシーを確認する
– 例: RHEL/CentOSは10年サポート、Debian/Ubuntu(LTS)は5年サポート
– CentOS6 : 2020年11月30日まで
– CentOS7 : 2024年6月30日まで
• OSのアップデート
$ sudo yum update # or yum upgrade
$ sudo apt upgrade
• Ruby on Railsのアップデート
$ sudo bundle update
Copyright © 2017-2019 Hiroshi Tokumaru 74