2017年度 新卒技術部研修 〜講義編〜

はじめに

新卒技術部研修にするにあたって昨年の研修を振り返り

  • フロントエンジニア、フロントエンジニア(Unity)、サーバーエンジニア、と様々な職能の新卒メンバー全員が受ける研修でGo言語を使うのは配属後に使わない人がいるのでもったいない
  • 各講義毎にそれぞれ異なったお題を出すと、講義で学んだことがどのように関係してくるのか関係性を把握するのが大変そうだった

という反省がでました。

そこで今年は

  • カヤックではサーバー構築にChefを使用しているため、配属先がRuby以外の言語で開発していてもRubyを使う機会があり無駄にはならないということからRubyを使用する
  • 与えられたお題のWebApplicationを段階を踏んで作っていく体系的に学べるカリキュラムにする

ということになりました。

実際の研修ですが、以下の流れで研修をすすめていきました。

  • アプリを作る上で必要なgit,Rubyの基礎的な講義
  • Webアプリをつくるために基本となるTCP/HTTPの講義
  • Sinatraで作ったアプリでデータを保存するためにDBについての講義
  • KVSについて講義をし、ユーザー認証の機能を作る実習
  • 作ったアプリを公開するためにAWSの基本的な操作の講義と、サーバー構築の実習
  • お題のアプリにセキュリテイ的な穴を開けたものを用意し、実際に自分で攻撃してみる実習

この記事では各講義でどのようなことを行ったのかの概要を各講師にまとめてもらいました。

これから研修を行う方々の参考に少しでもなればと思います。

Git編

今回の研修は全体的に、Github上で課題の説明や提出を行っていくため、まずはgitを自由自在に扱うための講義を行いました。

  • Gitとはなにか
  • 実習
    • cloneする
    • 自分のブランチを切って作業
    • 現状の確認とpush
  • Github
    • Pull Requestとは
  • コンフリクト解決

Ruby編

  • Rubyの基本文法
  • gem, bundler の使い方
  • erb, slim の書き方
  • Rubyでurlにアクセスする
  • Rubyで正規表現
  • RubyでFileを扱う

TCP/HTTP編

TCP, HTTPの基礎について解説しました。

  • OSI参照モデルの紹介
  • TCPとHTTPの仕組み

講義に加えて実際にTCP, HTTPを見て触る実習を行いました。

  • TCP通信している様子をパケットキャプチャしてみる
  • telnetコマンドでクライアントとしてHTTPをしゃべってみる
  • ncコマンドでサーバーとしてHTTPをしゃべってみる

普段何気なく利用しているHTTPの仕組みを知ることができたということで、なかなか好評だったようです。

DB編

RDBMSについての概念的な説明と、その中でも社内で多く採用されているMySQLの特性と使い方について説明しました。

  • RDBMSについての説明
  • MySQLについての解説
    • クラスタインデックスの構造と特性
  • MySQLのデータベースとテーブルの関係とCREATE文の書き方、読み方
  • SELECT, INSERT, UPDATE, DELETEなどの基本的なSQLの説明

また実習として、大量のデータを入れたテーブルを用意し発行されるクエリから適切なインデックスを貼るべきカラムを調べて実際に張った上で速度が向上するかという体験も行いました。

  • インデックスの張り方
  • インデックスの使われ方とEXPLAINの結果の見方
  • 大量にデータを入れた際のフルスキャンした場合ととインデックスを使った場合を体験してみる

KVS編

KVSとは何か、RDBMSとの違いは何かを解説しました。

  • 適材適所でデータベースを選択すること
  • KVSの利用が有効なユースケース
  • 管理されていないKVSは魔窟

また、KVSの例としてRedisを用いて実習を行いました。

  • 基本的なコマンド(GET/SET/DELETE)
  • 集合操作(LIST/SET/SORTED SET)
  • TTLの設定

Redisを実環境上で使用する場合の注意点についても触れました。

  • コマンド実行時のブロック
  • Redis実行に必要なメモリ量
  • 永続化方法の違いによるデータ消失耐性とパフォーマンス

WebApp編

Ruby で Web アプリケーションを実装してもらいました。最初から Sinatra を使うと内部でどのようなことをしているのかわからないので、

  1. socket ライブラリを使って HTTP サーバを実装
  2. Rack で HTTP サーバを実装
  3. Sinatra で Webアプリケーションを実装

という順で進めました。実装したWebアプリケーションは、とあるWebサービスの簡易版で、社内ISUCONでも使用しています。

フロント編

ここまでに制作したWebアプリケーションのデザインをあてていく形で、 kayac-html5-starter を使ったフロント開発の講義・実習を行いました。配属後にフロントエンジニアの配属にならないメンバーにも、最近のWebフロントがどのように開発されているのかを体感してもらうことが主目的でした。

ここまでの流れとはやや独立した内容であること・サーバーサイドをメインで勉強していてフロントに慣れていない(あるいはその逆の)人もいたことから、新鮮な気持ちで取り組んでもらえたようです。

サーバー構築編

サーバー構築篇は、2016年の「ガチ授業をしてそのあと各自が演習するスタイルでやったらサーバーになじみのないフロントエンドエンジニアがみんなお手上げになってしまった」という反省を生かし、講師が実際にサーバー構築する様子を画面に映して、各自が手元で同じことを行って自分の環境を構築していく、ハンズオン形式で行いました。

具体的な流れとしては、以下のような感じです。

  • まず全部入り構成のEC2を作って1台で動かす
    • AWS ConsoleでEC2を起動
    • 自分のアカウントを作ってsudoersを設定
    • 課題のアプリをEC2上にデプロイ(ただしミドルウェアがないので起動しない)
    • ruby、mysql、redisをインストールし、データベースを作ってスキーマを投入
    • 無事1台構成で動くことが確認できました!
  • マネージドサービスとしてRDSとElasticacheを利用する構成に変更
    • 課題のアプリがRDSとElasticacheを使うように設定変更
    • これでストレージ関連をEC2から分離できたので、EC2を増やしてスケールアウトできるようになりました!
  • 別のEC2で同じ構成のEC2をchefで構築
    • 講師が用意した色々足りないchefレシピを実行
    • serverspecで足りない点が指摘されるので、各自レシピを書く
    • 徐々にヒントを出していき、最終的にserverspecで全てテストが通って課題完了

2017年はこれを2日間で行いました。

フリーダムに各自ガンバレ方式だった2016年とは違い、全員同じ手順をやっていくことで進度の足並みが揃いました。また、副次的効果としてサーバーが得意な人がフロントが得意な人にやり方を教えたりするなどよい効果がありました。

セキュリティ編

セキュリティの講義では実装によって簡単に脆弱性を生み出せてしまう、脆弱性の危うさを体験してもらうために

  • XSS
  • CSRF
  • SQL Injection
  • OS Command Injection

の4つの脆弱性について触れました。

もともと研修内でつくっていたアプリを修正(改悪?)し、挙げた4つの脆弱性が再現できる状態のアプリを用意しました。

講義では、各脆弱性ごとに

  1. 説明する脆弱性がどのようなものかの説明
  2. 用意したアプリをつかって実際に脆弱性を再現してみる
  3. 脆弱性の回避方法の講義
  4. 用意したアプリを講義を受けて終始し、脆弱性の再現ができないことを確認する

という流れで行いました。

実施の脆弱性を再現させるところでは

  • DOMを書き換え外部リソースを読み込む (XSS)
  • 入力済みのコメントを全て削除してみる (SQL Injection)

などを実際にやってもらうことで、簡単に脆弱性が生み出せ攻撃がされてしまうということを体験してもらうことが出来ました。

ログ編

ログの講義でアプリケーションはログを適切に吐こうというのを分かってもらうためにGoogle Spread SheetからCSVファイルにするというスクリプトを中途半端に実装した状態で渡し、最後まで実装してもらうということをやりました。

講師が作った、一見何の変哲もないライブラリを読み込みこんでいたためログが全く表示されない状態のため 解説のタイミングで「うわーーーー」、「なるほど…」という阿鼻叫喚な声が聞こえてきました。

その日の研修の振り返りにも

  • ログがでるという当たり前の大切さが見にしみた
  • 使うライブラリはきちんと調べたい

というようなことが書かれていたのでおおよそ狙い通りになったのではないかなと思いました。

トラブルシューティング編

トラブルシューティング実習では、運用しているWebアプリケーションに障害が発生した場合に、どうやって原因を特定し解消するのか、という講義と実習を行いました。

実際のトラブルは、お客さんの環境から自分らの使っている環境、通信経路のうちどこに発生しても障害に繋がりますが、今回の実習ではアプリケーションが動作しているサーバ(EC2インスタンス)の内部だけを対象としました。

原因追及のための各種stat系のコマンド、ログの出力場所などを講義、実習後、各自に割り当てられたサーバに対して講師が人為的にトラブルを発生させます。

課題の内容

  1. システムのどこに問題が発生しているのかを調査し、修正してください。以下の3項目を、発見、修正した問題点ごとに、手元に記録してください
  2. 発見した問題点
  3. 問題を確認できた理由(このログのこの部分、とかこのコマンドの実行結果から、とか)
  4. 修正するために対応した内容
  5. 修正後、また同じことが起きないように、システムを修正してください

講師が発生させたトラブル

  • Webアプリケーションのファイアップロード機能を利用し、攻撃用シェルスクリプトを画像ファイルに偽装してサーバに送り込む
  • Webアプリケーションのログイン機能にある OS Command Injection 脆弱性を利用し、先に配置した攻撃用 シェルスクリプトを実行する
  • シェルスクリプトの内容は下記のようなものです
    • MySQLのテーブルを (バックアップを取った上で) DROP
    • Redis に SHUTDOWN コマンドを発行して停止させる
    • god を利用して、stress コマンドを実行して永続的に負荷を掛ける

当然、その時点からWebアプリケーションはエラーを起こしますし、top コマンドなどでCPUを消費している stress プロセスを見つけて kill しても god が復活させます。

アクセスログ、アプリケーションログから

− ある時点でファイルがアップロードされていること - 同じIPアドレスから、ログアウト→ログインが行われていること

を見つけ、

  • Redisのログでその時刻に shutdown が発生していること、
  • その時刻から普段はいないはずのプロセス god が存在して、子プロセスに stress が動作していること

を確認し、アップロードされたファイルの内容を確認すれば、OS Command Injection の脆弱性があってそれを実行されたようだ、ということが分かるでしょう。

攻撃者は親切にもテーブルのバックアップを取ってくれているのでそれを書き戻し、Redisを起動し、god と stress をまとめて kill すれば、とりあえずは復旧できます。しかし、それだけではまた同様の攻撃を受けてしまうので、アプリケーションのソースコードを確認し、脆弱性を修正する、というところまでできれば、という実習でした。

さいごに

このような形で研修を行いました。

多少躓くところはあっても参加者全員がWebApplicationを作るために必要な知識や、技術、 更には、実際の仕事で気をつけなければいけないセキュリティの怖さも学ぶことができました。

そして、いよいよカヤックの研修恒例の社内ISUCONに続きます。

今年はどのような問題で、どのような結果になったのでしょうか?!

次の記事をお楽しみに!!

新卒じゃないけどカヤックにちょっと興味があるな・・・という方はこちらへ!

もちろん新卒採用もやってます!