Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Bootcamp 2018 Web Application Hardening

Bootcamp 2018 Web Application Hardening

2018年4~5月開催「ブートキャンプ特別講座」の資料になります。

Recruit Technologies

July 19, 2018
Tweet

More Decks by Recruit Technologies

Other Decks in Technology

Transcript

  1. • Ruby on RailsͰ࡞ͬͨ੬ऑੑͨͬ΀Γͷ؆қSNS • ڈ೥ͷ՝୊ͱ͸੬ऑੑͷ಺༰͕શͯҧ͍·͢ʂ • ίʔυ͸GitHubʹஔ͍ͯ͋Γ·͢ https://github.com/recruit-tech/bootcamp_secuirty_2018 •

    TwitterɺFacebookΈ͍ͨͳΞϓϦͰ͢ • 140จࣈ·ͰͷςΩετ౤ߘͱɺը૾౤ߘػೳɻ஥ؒಉ࢜Ͱͭͳ͕Δ • ༑ਓͱ1ର1ͷνϟοτ΋Ͱ͖·͢ɻ • FirefoxɺChromeʹͯಈ࡞Λ֬ೝ Bad SNS 2
  2. • Ubuntu Server 16.04 LTS • Ruby 2.4.4 • Ruby

    on Rails 5.1.4 • Bootstrap 3.3.7 • jQuery 3.2.1 • Nginx 1.10.3 • Unicorn 5.4.0 • ImageMagick 6.8.9.9 • SQLite 3.11.0 αʔόͷߏ੒ 3
  3. • ౿Έ୆΁ϩάΠϯ • $ ssh [email protected] -i ~/.ssh/bcsec_rsa -p 22

    • User: xxxxxx • ౿Έ୆͔ΒWebαʔό΁ϩάΠϯ • $ssh 10.0.0.xx (νʔϜA) • $ssh 10.0.0.xx (νʔϜB) • $ssh 10.0.0.xx (νʔϜC) • $ssh 10.0.0.xx (νʔϜD) • $ssh 10.0.0.xx (νʔϜE) • ※ ޡͬͯଞνʔϜͷαʔόʹೖΒͳ͍Α͏ʹؾΛ͚ͭͯԼ͍͞ɻ ೝূ৘ใ 4
  4. • Bad SNSΞϓϦͷىಈ • $ cd /var/www/app/sns/ • $ sudo

    bundle exec unicorn_rails -c config/unicorn.rb -E production –D • ΞϓϦ΁ΞΫηε • http://xx.xx.xx.xx/ ʢνʔϜAʣ • http://xx.xx.xx.xx/ (νʔϜB) • http://xx.xx.xx.xx/ (νʔϜC) • http://xx.xx.xx.xx/ (νʔϜD) • http://xx.xx.xx.xx/ (νʔϜE) • ※ ޡͬͯଞνʔϜͷΞϓϦը໘ʹΞΫηε/ૢ࡞͠ͳ͍Α͏ʹؾΛ͚͍ͭͯͩ͘͞ɻ ૢ࡞ํ๏ 1 5
  5. • ϑΝΠϧͷमਖ਼ • ੬ऑੑΛ୳ͭͭ͠ɺमਖ਼ํ๏ʢHardeningʣ΋ݕ౼͠ɺ࣮ࡍʹΞϓϦʹద༻ͯ֬͠ೝͯ͠Լ͍͞ɻ • $ sudo cd /var/www/app/sns/ •

    $ sudo vi <मਖ਼͍ͨ͠ϑΝΠϧ> • ϑΝΠϧमਖ਼ΛΞϓϦʹ൓ө • $ sudo kill -QUIT `cat /var/www/app/sns/tmp/pids/unicorn.pid` • $ sudo bundle exec unicorn_rails -c config/unicorn.rb -E production –D • Deployͷํ๏ • ֤νʔϜͰ΍Γ΍͍͢ํ๏Ͱߦ͍ͬͯͩ͘͞ɻ • DeployલʹɺDocker؀ڥͰςετΛߦͬͯɺຊ൪ͷ҆શՔಇΛ৺͕͚͍ͯͩ͘͞ɻ ૢ࡞ํ๏ 2 6
  6. • sshͰWebαʔόʹϩάΠϯ͠ɺҎԼͷखॱͰ෮چ͍ͯͩ͘͠͞ ΋͠΋WebΞϓϦ͕յΕͨΒ $ sudo rm -rf /var/www/app/sns $ sudo

    cp -r ~/bootcamp_secuirty_2018/files/sns /var/www/app/sns $ cd /var/www/app/sns $ sudo bundle install $ sudo bundle exec rake db:create RAILS_ENV=production $ sudo bundle exec rake db:reset RAILS_ENV=production $ sudo chown www-data.www-data -R /var/www/app/sns $ sudo systemctl restart nginx $ sudo bundle exec unicorn_rails -c config/unicorn.rb -E production -D 7
  7. ログイン名 パスワード ログイン Boot Camp SNS 新規利⽤はこちら (エラー出⼒) ログイン/認証エラー 新規利⽤はこちら

    ログイン名 パスワード 利⽤開始 ユーザ登録 (エラー出⼒) 表⽰名 画像 アップ ロード ログイン/成功 利⽤開始/成功 利⽤開始/エラー 認証エラー・ ログアウト 読み込み ㊯׷俑㶵⟃ⰻ ח׃׬י֮ ײתך   ח׃׬י֮   爡㆞鏾זֻ׃׋ "QQMFJ1IPOFחג乆䕦 ⟝ך倜滠䫎珲 ׮׏ה铣׬ 8
  8. 喋る(140⽂字以内) にしむねあ ゆまの 2017.03.28 09:25 にしむねあ 2017.03.28 09:20 社員証なくしたwww Apple

    / iPhone 7 にて撮影 10件の新着投稿 もっと読む 画像を投稿 友⼈を登録 友⼈を検索 ログアウト 9
  9. ㊯׷俑㶵⟃ⰻ ח׃׬י֮ ײתך   ח׃׬י֮   爡㆞鏾זֻ׃׋ "QQMFJ1IPOFחג乆䕦

    ⟝ך倜滠䫎珲 ׮׏ה铣׬ ログイン名 パスワード ログイン Boot Camp SNS 新規利⽤はこちら (エラー出⼒) ログイン/認証エラー ログイン名 パスワード 利⽤開始 ユーザ登録 (エラー出⼒) 表⽰名 画像 アップ ロード ログイン/成功 利⽤開始/成功 利⽤開始/エラー 認証エラー・ ログアウト 読み込み 'ϑϨʔϜදࣔ 'ϩάΠϯը໘ 'Ϣʔβొ࿥ը໘ 'ϩάΠϯ 'ϓϩϑΟʔϧը૾ొ࿥ 'Ϣʔβొ࿥ 'ϑϨʔϜඇදࣔ 'ϑϨʔϜදࣔ ϝΠϯը໘ʢ࣍ทʣ 新規利⽤はこちら 12
  10. 喋る(140⽂字以内) にしむねあ ゆまの 2017.03.28 09:25 にしむねあ 2017.03.28 09:20 社員証なくしたwww Apple

    / iPhone 7 にて撮影 10件の新着投稿 もっと読む 'ςΩετ౤ߘ '৽ண౤ߘϩʔυ 'ϓϩϑΟʔϧը૾දࣔ '౤ߘϩʔυ 'աڈ౤ߘϩʔυ 13 画像を投稿 友⼈を登録 友⼈を検索 ログアウト 'ը૾౤ߘ '༑ਓొ࿥ 'ϩάΞ΢τ '4༑ਓݕࡧ
  11. 喋る(140⽂字以内) にしむねあ ゆまの 2017.03.28 09:25 にしむねあ 2017.03.28 09:20 社員証なくしたwww Apple

    / iPhone 7 にて撮影 10件の新着投稿 もっと読む 14 'νϟοτ 'νϟοτ ͷ։࢝
  12. 16 • ϝΠϯը໘ʢpublic/index.htmlʣ͸ϩʔυ௚ޙɺlocalStorageʹϢʔβ৘ใ͕ ؚ·Ε͍ͯΔ͜ͱΛ֬ೝ • Ϣʔβ໊͕֨ೲ͞Ε͍ͯͳ͚Ε͹ɺϑϩʔςΟϯάiframeΛ։͖ɺ ϩάΠϯը໘(F02)Λදࣔ͢Δ • ϝΠϯը໘͸ɺAPIͷϨεϙϯείʔυ403͕ฦ٫͞Εͨ৔߹ɺCookieͷηογϣϯ৘ใ͕ແ ޮԽɾ͋Δ͍͸ࣦޮͨ͠΋ͷͱ൑அ͠ɺڧ੍తʹϩάΞ΢τ(F13)Λߦ͏

    • ϩάΞ΢τ(F13)͕ਖ਼ৗऴྃͨ͠৔߹͸ɺlocalStorageʹ֨ೲ͞ΕͨϢʔβ৘ใΛ࡟আ͠ɺ ϑϩʔςΟϯάiframeͰ࠶౓ϩάΠϯը໘(F02)Λදࣔ͢Δ • ϑϩʔςΟϯάiframeදࣔத͸ɺϝΠϯը໘ͷૢ࡞ΛϒϩοΫ͢Δ F01. ϑϨʔϜදࣔ
  13. 17 • ϩάΠϯ໊ͱύεϫʔυͰϩάΠϯՄೳͱ͢Δ • ೖྗՄೳจࣈ͸ɺUnicodeͷBasic LatinʢU+0020 ʙ U+007Fʣ ͷൣғͱ͢Δ •

    ϩάΠϯ໊ͱύεϫʔυ͸࠷େ20จࣈͱͳΔΑ͏ʹϑΥʔϜͰ੍ݶ͢Δ • ϩάΠϯϘλϯΛԡ͢ͱɺඇಉظͰϩάΠϯ(F03)Λ࣮ߦ͢Δ • ϩάΠϯ(F03)͕ਖ਼ৗऴྃͨ͠Βɺαʔό͔Βฦ٫͞ΕͨϢʔβ৘ใΛlocalStorageʹ ֨ೲ͠ɺϑϨʔϜඇදࣔ(F07)Λ࣮ߦͯ͠ϩάΠϯը໘Λด͡ɺϝΠϯը໘ʹભҠ͢Δ • ϩάΠϯ(F03)͕ҟৗऴྃͨ͠Βɺฦ٫͞ΕͨΤϥʔจݴΛදࣔ͢Δ F02. ϩάΠϯը໘ʢlogin.htmlʣ
  14. 18 実装例 POST /sessions リクエストボディ user : ログイン名(必須・⽂字列) pass :

    パスワード(必須・⽂字列) レスポンスコード 200:正常終了 400:異常終了 レスポンスボディ (application/json) 正常終了 name : ログインユーザの表⽰名 icon : プロフィール画像URL token:Androidアプリのユーザ認証で使うJWT 異常終了 errors : エラーメッセージ(配列) 備考 • セッション情報(ユーザID)をCookieに記録します • JWTでユーザ認証する場合は、リクエストヘッダに Authorization: Bearer {JWT} を付加します F03. ϩάΠϯʢPOST /sessionsʣ
  15. 19 • ද໊ࣔɺϩάΠϯ໊ɺύεϫʔυͷೖྗϑΥʔϜΛදࣔ͢Δ • ϩάΠϯ໊ͱύεϫʔυͷೖྗՄೳจࣈ͸ɺUnicodeͷBasic LatinʢU+0020 ʙ U+007Fʣ ͷൣғͱ͢Δ •

    ϩάΠϯ໊ɺύεϫʔυɺද໊ࣔ͸࠷େ20จࣈ·Ͱͱ͢Δ • ද໊ࣔʹ͸೚ҙͷจࣈྻΛར༻Մೳ • ϓϩϑΟʔϧը૾ొ࿥(F05)ͷͨΊɺը૾Λυϩοϓ͢ΔۣܗΤϦΞΛදࣔ͢Δ • ը૾͕υϩοϓ͞ΕͨΒɺඇಉظͰϓϩϑΟʔϧը૾ొ࿥(F05)Λ࣮ߦ͢Δ • ϓϩϑΟʔϧը૾ొ࿥(F05)͕ҟৗऴྃͨ͠Βɺฦ٫͞ΕͨΤϥʔจݴΛදࣔ͢Δ • ར༻։࢝Ϙλϯ͕ԡ͞ΕͨΒɺඇಉظͰϢʔβొ࿥(F06)Λ࣮ߦ͢Δ • Ϣʔβొ࿥͕ਖ਼ৗऴྃͨ͠Βɺαʔό͔Βฦ٫͞ΕͨϢʔβ৘ใΛ localStorageʹ֨ೲ͠ɺϑϨʔϜඇදࣔ(F07)Λ࣮ߦ͢Δ • Ϣʔβొ࿥(F06)͕ҟৗऴྃͨ͠Βɺαʔό͔Βฦ٫͞ΕͨΤϥʔจݴΛදࣔ͢Δ F04. Ϣʔβొ࿥ը໘ʢregister.htmlʣ
  16. 20 実装例 POST /icons リクエストボディ filename:画像ファイル名(必須・⽂字列) file:画像ファイル(必須・バイナリ) resize_max_pixel:リサイズ時の最⼤ピクセル数(任意・整数) レスポンスコード 200:正常終了

    400:異常終了 レスポンスボディ (application/json) 正常終了 file_name:アップロードされたプロフィール画像のファイル名 異常終了 errors : エラーメッセージ 備考 • resize_max_pixelに有効な値が指定された場合、指定されたピクセル以内に収まるよう画像をリサイズする • 画像ファイルがPNG、GIF、JPEG以外であれば、異常終了する F05. ϓϩϑΟʔϧը૾ొ࿥ʢPOST /iconsʣ
  17. 21 実装例 POST /users リクエストボディ user[user]:ログイン名(必須・⽂字列) user[pass]:パスワード(必須・⽂字列) user[name]:表⽰名(必須・⽂字列) user[icon_file_name]:プロフィール画像のファイル名(任意・⽂字列) レスポンスコード

    200 : 正常終了 400 : 異常終了 レスポンスボディ (application/json) 正常終了 name : ログインユーザの表⽰名 icon : ログインユーザのプロフィール画像URL token:Androidアプリのユーザ認証で使うJWT 異常終了 errors : エラーメッセージ 備考 • Cookieにセッション情報(ユーザID)を記録します • プロフィール画像が指定されていないか、正しい画像ファイルでない場合、 サーバ側で⽤意したデフォルト画像をプロフィール画像に設定します • JWTでユーザ認証する場合は、リクエストヘッダに Authorization: Bearer {JWT} を付加します F06. Ϣʔβొ࿥ʢPOST /usersʣ
  18. 23 実装例 GET /users/1/icon リクエストボディ id:ユーザID(必須・整数) レスポンスコード 200 :正常終了 400

    :異常終了 レスポンスボディ (application/json) 正常終了 プロフィール画像 異常終了 デフォルト画像 備考 F11. ϓϩϑΟʔϧը૾දࣔʢGET /users/:id/iconʣ
  19. 24 • ϑϩʔςΟϯάiframeʹͯɺ༑ਓͷొ࿥ϑΥʔϜΛදࣔ͢Δ • എ໘ͷϝΠϯը໘͕ԡԼ͞Εͨ৔߹ɺϑϩʔςΟϯάiframeΛด͡Δ • ొ࿥͍ͨ͠༑ਓͷϩάΠϯ໊ΛϑΥʔϜʹೖྗ͠ɺొ࿥ϘλϯΛԡ͢͜ͱͰɺ ༑ਓొ࿥͕׬ྃ͢Δ • ຊԋशͰ͸ɺ༑ਓͷొ࿥͢ΔࡍʹɺͦͷϢʔβຊਓͷڐՄΛٻΊͳͯ͘ྑ͍࢓༷ͱ͢Δ

    • ༑ਓͷొ࿥ʹ͸ɺ࣍ϖʔδͷAPIΛ༻͍Δ • ༑ਓొ࿥API͸ඇಉظͰ࣮ߦ͠ɺ੒ޭͨ͠৔߹͸ϖʔδΛϦϩʔυ͠ɺ౤ߘΛ৽نऔಘ͢Δɻ ࣦഊͨ͠৔߹͸ϑϩʔςΟϯάiframe্ʹΤϥʔϝοηʔδΛදࣔ͢Δ F12. ༑ਓొ࿥
  20. 25 実装例 GET /friends/search_word リクエストボディ なし レスポンスコード 200:正常終了 400:異常終了(不正なリクエスト) 403:異常終了(不正なセッション)

    レスポンスボディ (application/json) 正常終了 ユーザ情報の⼀覧 異常終了 errors : エラーメッセージ 備考 FS2. ༑ਓҰཡऔಘɺݕࡧʢGET /friendsʣ
  21. 27 実装例 DELETE /sessions リクエストボディ なし レスポンスコード 200 : 正常終了

    403 : 異常終了(不正なセッション) レスポンスボディ (application/json) なし 備考 F13. ϩάΞ΢τʢDELETE /sessionsʣ
  22. 28 実装例 POST /feeds リクエストボディ feed_type:'text'(必須・⽂字列) comment:コメント(必須・⽂字列) レスポンスコード 200:正常終了 400:異常終了

    (不正なリクエスト) 403:異常終了 (不正なセッション) レスポンスボディ (application/json) なし 備考 • feed_typeが'text'以外の場合、⽂字列が141⽂字以上の場合は異常終了する F21. ςΩετ౤ߘʢPOST /feedsʣ
  23. 30 実装例 POST /feeds リクエストボディ feed_type:image'(必須・⽂字列) image:画像ファイル (必須・バイナリ) レスポンスコード 200:正常終了

    400:異常終了 (不正なリクエスト) 403:異常終了 (不正なセッション) レスポンスボディ (application/json) なし 備考 • feed_typeが'image'以外の場合、投稿されたファイルが正しい画像でない場合は異常終了する F22. ը૾౤ߘʢPOST /feedsʣ
  24. 31 • ϝΠϯը໘͸ɺ࣍ϖʔδͷ৽ணϩʔυAPIΛ6ඵஔ͖ʹൃߦ͠ɺ৽ண౤ߘͷ਺Λऔಘ͢Δ • ৽ண౤ߘͷ਺͕1݅Ҏ্͋Ε͹ɺը໘ʹʮN݅ͷ৽ண౤ߘʯϘλϯΛදࣔ͢Δ • ৽ண౤ߘ͕0݅ͷ৔߹ɺ·ͨ͸ҟৗऴྃͨ͠৔߹͸ɺϘλϯΛը໘͔Βফڈ͢Δ • ϘλϯΛԡͨ͠৔߹ɺ৽ண౤ߘAPIΛൃߦ͠ɺ৽ண౤ߘͷϩʔυΛߦ͏ •

    ݱࡏϩʔυ͍ͯ͠Δ౤ߘҎ߱ʹొ࿥͞Εͨશͯͷ౤ߘΛϩʔυ͢Δ • APIൃߦޙɺʮN݅ͷ৽ண౤ߘʯϘλϯΛը໘͔Βফڈ͢Δ • ϩʔυͨ͠౤ߘΛը໘ʹදࣔ͢Δ • find_newͱfind_oldͷAPIͷج఺ͱ͢ΔͨΊɺը໘ʹදࣔ͞Ε͍ͯΔ࠷৽ͱ࠷ݹͷϑΟʔυID͸JavaScriptͰ؅ཧ͢Δ F31. ৽ண౤ߘϩʔυ
  25. 32 実装例 GET /feeds/1/find_new?include_items=1 リクエストボディ feed_id : 基点とするフィードID(必須・整数) include_items :

    投稿内容を取得するか否か(任意・integer) レスポンスコード 200:正常終了 400:異常終了 (不正なリクエスト) 403:異常終了 (不正なセッション) レスポンスボディ (application/json) 後述の「投稿ロード機能のレスポンスボディ」を参照 備考 • include_itemsが存在しない、または値が1以外の場合、countのみ返却する • ユーザ本⼈とその友⼈の投稿のみ取得可能とする F31. ৽ண౤ߘϩʔυʢGET /feeds/:feed_id/find_newʣ
  26. 33 • ϝΠϯը໘͸ɺաڈ౤ߘϩʔυAPIΛൃߦ͠ɺը໘ʹදࣔ͞Ε͍ͯͳ͍ աڈ౤ߘͷ਺Λऔಘ͢Δ • աڈ౤ߘͷ਺͕1݅Ҏ্͋Ε͹ɺը໘ʹʮ΋ͬͱಡΉʯϘλϯΛදࣔ͢Δ • ৽ண౤ߘ͕0݅ͷ৔߹ɺ·ͨ͸ҟৗऴྃͨ͠৔߹͸ɺϘλϯΛදࣔ͠ͳ͍ • ϘλϯΛԡͨ͠৔߹ɺաڈ౤ߘAPIΛൃߦ͠ɺաڈ౤ߘΛϩʔυ͢Δ

    • ݱࡏϩʔυ͍ͯ͠Δ౤ߘͷલʹొ࿥͞Ε͍ͯΔ30݅෼ͷ౤ߘΛϩʔυ͢Δ • APIൃߦޙɺʮ΋ͬͱಡΉʯϘλϯΛը໘͔Βফڈ͢Δ • ϩʔυͨ͠౤ߘΛը໘ʹදࣔ͠ɺ࠶౓ɺաڈ౤ߘͷ਺Λऔಘ͢Δ • աڈ౤ߘ͕·ͩଘࡏ͢Δ৔߹͸ɺʮ΋ͬͱಡΉʯϘλϯΛ࠶ͼදࣔ͢Δ F32. աڈ౤ߘϩʔυ
  27. 34 実装例 GET /feeds/1/find_old?include_items=1 リクエストボディ feed_id : 基点とするフィードID(必須・整数) include_items :

    投稿内容を取得するか否か(任意・integer) レスポンスコード 200:正常終了 400:異常終了 (不正なリクエスト) 403:異常終了 (不正なセッション) レスポンスボディ (application/json) 後述の「投稿ロード機能のレスポンスボディ」を参照 備考 • include_itemsが存在しない、または値が1以外の場合、countのみ返却する • ユーザ本⼈とその友⼈の投稿のみ取得可能とする • ⼀度にロードする過去投稿は最⼤30件とする F32. աڈ౤ߘϩʔυʢGET /feeds/:feed_id/find_oldʣ
  28. 35 実装例 GET /feeds/1/find_old?include_items=1 リクエストボディ なし レスポンスコード 200:正常終了 400:異常終了 (不正なリクエスト)

    403:異常終了 (不正なセッション) レスポンスボディ (application/json) 後述の「投稿ロード機能のレスポンスボディ」を参照 備考 • ユーザ本⼈とその友⼈の投稿のみ取得可能とする • ⼀度にロードする過去投稿は最⼤30件とする F33. ౤ߘϩʔυʢGET /feedsʣ
  29. 37 実装例 GET /cable (WebSocket) リクエストボディ channel:チャンネル名(「ChatChannel」の固定値) channel_id:暗号化されたチャンネルID レスポンスコード ー

    レスポンスボディ (application/json) ー 備考 • WebSocketによる通信(通知、1対1チャット) • 通信⽅法はAction Cableの仕様に準ずる F34. νϟοτʢGET /cable (WebSocket)ʣ
  30. 38 # パス メソッド アクション名 対応する機能 1 /sessions POST create

    F03. ログイン 2 /sessions DELETE clear F13. ログアウト 3 /users POST create F06. ユーザ登録 5 /users/:id/icon GET icon F11. プロフィール画像表⽰ 6 /icons POST create F05. プロフィール画像登録 2S /friends GET index FS2. 友⼈⼀覧の取得、検索 7 /friends POST create F12. 友⼈登録 8 /feeds GET index F33. 投稿ロード 9 /feeds POST create F21. テキスト投稿 F22. 画像投稿 10 /feeds/:feed_id/find_new GET find_new F31. 新着投稿ロード 11 /feeds/:feed_id/find_old GET find_old F32. 過去投稿ロード 12 /cable GET - F34. チャット APIҰཡ
  31. 39 ϞσϧҰཡ VTFST id integer login_id string name string pass

    string icon_file_name string GSJFOET id integer from_user_id integer to_user_id integer GFFET id integer type string user_id integer image_file_name string exif string comment string user has_many from_user from_user belongs_to user user has_many to_user to_user belongs_to user user has_many to_user through friends source to_user user has_many from_user through friends source from_user user has_many feed feed belongs_to user