概要
この記事はNssol2019AdventCalendarの14日目の記事です.忘年会で謎解きウェブアプリを作成することになり,そのサーバーサイド(Flask, AWS)を主に扱ったのでハマったポイントやサーバーサイドの構築でやったことを書いていきます.そもそもこのアプリとは?といった話やフロントエンドの話はこちらを参考にしてください.
開発が遅れていて,忘年会会場に行くタクシーの中で最終versionをデプロイしました笑
この記事の目的としては,忘年会のような場で発表するような,ある程度まともにアプリを作ろうとした人がどのような手順で構築したらいいかというのがわかるように書いていきたいと思います.
やったこと
今回,ぼくがやったことは主にAWSによるウェブサーバーの構築とウェブサーバー上で稼働するアプリケーションのサーバーサイドの開発です(下の図のオレンジ色の部分).この2つのトピックに分けて書いていきたいと思います.NSSOLの新入社員3人で,余興でウェブアプリを開発しました.工期は約2ヶ月です.業務時間外で開発のほとんどを行ったため,実時間的には分かりません.仲の良い3人が趣味で開発したという側面が強いです.
構成としては以下の図のような構成でした.レガシーって言わないでください゚゚(゚´ω`゚)゚。ピー
スケジュール
以下のようなスケジュールで開発を行いました.余暇で開発していたので比較的タイトなスケジュールになってしまいました...
10/19 アプリケーションの制作開始
11/2 AWS上でサーバー構築開始
11/7 はじめてのユーザテスト
11/10 スクラムもどき開発の開始
12/13 忘年会当日
11/2の時点でアプリケーションのサーバーサイドはほぼできていて,それを公開するためのサーバーを構築し始めた感じです.その後はじめてのユーザテストで結構ハードルが高めなコメントをいただき,このままだとまずいと思ってスクラム(もどき)開発を開始したという流れです.
AWS上ウェブサーバー構築
AWS上でのウェブサーバの構築について書きます.
大まかには
- EC2の立ち上げ
- セキュリティ対策
- 実行環境(python)の導入
- ウェブサーバの構築
- 負荷テスト
の5ステップからなります.
個別の技術要素についてはすばらしい記事たちがあるので割愛します.
EC2の立ち上げ
今回EC2を使おうと思った理由としてはLambda上では入れるのがめんどくさいライブラリ群を使いたいなという気持ちがあったからです(というのは建前でLambdaは使ったことがあったので,EC2やってみるかという興味です...).
ウェブサーバーを立ち上げるところまではここなどに詳しく書いてあります.
**ここでぼくが伝えたいのはインスタンスタイプは2つ用意しておこうねということです.**1つは実験用のt2.microでここで設定を入れて開発します.もう1つは本番稼働用のインスタンスで,t2microで行った設定を反映させるだけという形です.あとt2microはデフォルトだとHDDの容量が小さすぎてpyenvが入らなかったのでディスクの追加が必要でした...
セキュリティ対策
はい,意外と書かれているのが少ないセキュリティ関連ですが,AWSが最強なので任せましょう最低限下記の設定は入れておくといいかなと思います.
sshの設定
/etc/sshd/sshd_config
の中身をいじって以下の2つの設定はいれておきましょう.
- ルートログイン拒否
- パスワード認証の廃止(公開鍵認証のみにする)
firewallの設定
firewallについてですが,ウェブサーバとして使う場合は(当たりまえですが)httpを許可しておきましょう.
実行環境の導入
今回実行環境はpyenvを用いて構築しました.pythonで開発する場合は仮想環境を入れることをつよくおすすめします.rootの持ち物で入れてしまうとapacheユーザが使えなくなって大変なので,システム全体にインストールしました...
ウェブサーバの構築
pythonとapacheを連携させるためにwsgiを用いました.pythonで仮想環境を使っている場合のwsgiの導入は pipを経由していれてください.ここで結構ハマりました...この記事を参考に導入しました.
負荷テスト
これは意外とバカにできなくて本当にやったほうがいいと思います.実際マシンスペックを何も考えずにt2microで開発していたわけですが,負荷テストをしたらサーバが落ちてしまって,慌ててスペックの高いインスタンスに変更しました.今回は負荷テストツールにはApacheのabを使いました.使い方はここを参考にしています.
今回の忘年会は150人規模だったのでそれをもとにアクセス数を決めました.
アプリケーションのサーバーサイドの開発
アプリケーションのサーバーサイドの開発に関しては,主にフレームワークの選定とやっておくべきセキュリティ対策を書いていきたいと思います.個々のフレームワークごとの実装については詳しくは述べません.Flaskについての知見は後日別の記事にまとめようかなと思います.
フレームワークの選定
アプリケーションのサーバーサイドのフレームワークにはFlaskを採用しました.採用理由としては,1) データベースアクセスをしないでよい,2) 開発者がpythonを書きなれていたため,です.同じpythonのフレームワークではDjangoなどがありますが,今回の開発はDBを動かして連動するようなものではなかったのでFlaskのほうが向いていたと思います.
このようにフレームワークの選定には以下のような指標があるかなと考えています.
- DBをどの程度使うか?
- どれくらい開発者が言語に慣れているか?
- 開発環境の導入コストはどれくらいか?(Dockerを使えという話はある...)
- サーバをAPIサーバとして使うのかhtmlの作成までサーバで行うのか?
アプリケーションレイヤーでのセキュリティ対策
アプリケーションレイヤーでのセキュリティは以下のようなことを注意しました.
セキュリティはなんでもかんでも対応しないと!と思っていると大量にやることが増えます...忘年会のアプリ程度ならどの攻撃がクリティカルかを知っておけばそれだけ対策すればなんとかなることもおおいと思います!笑
それぞれ重要なセキュリティ対策ではありますが,作成するアプリケーションの性質によっては対策をとってなくてもそこまで問題にならないものもあるので,対策のコストと相談しながら開発しましょう.
SQLインジェクション
問題となる場面: DBを使うとき全般
これはユーザーからの入力をSQLに埋め込みたいときに問題になります.ただし直接自分で埋め込もうとせずフレームワークの関数を利用していれば,危険な文字のエスケープ処理を行ってくれているはずです.
XSS(クロスサイトスクリプティング)
問題となる場面: HTMLをユーザの入力に基づいて動的に生成している,かつあるユーザの入力をほかのユーザの画面でも表示するとき(Twitterの投稿など)
これはユーザが入力欄にjavascriptのコードをうめて送信したときにそのコードが実行されてしまうという脆弱性です.
CSRFトークンの付与
問題となる場面: 第三者がなりすましてPOSTなどのフォームで情報を送ると致命的な問題があるとき
少しウェブアプリを触った方なら耳にはしたことがあると思います.詳しい解説はここを参考にしてください.
実は今回のアプリは第三者に謎解きの答えを送信されてもあまり気にならないため(利用者が意図せずして問題をクリアしてしまうことはある)優先度は低めだと思います,
クッキーの改ざん防止
問題となる場面: クッキーの情報を簡単に改ざんできる場合
今回のアプリではどの謎を解いたか?という情報をクッキーに保存していたので改ざんされないようにRSAで暗号化しました.セッションのIDなどはデフォルトで暗号化してくれるフレームワークなどが多いので通常はあまり気にしなくていいかなと思います.
クッキーの不正利用防止
問題となる場面: 第三者にクッキーの情報を使ってリクエストを作成されると問題がある場合
これはクッキーのSecure属性(httpsのみに制限)やhttponly(Ajax利用の禁止)などで対策ができます.サーバ側でクッキーを焼く場合は,フレームワークにこのような属性を付与する関数があるため調べるようにしてみましょう.
テンプレートインジェクション
問題となる場面: ユーザからの入力を利用して動的にhtmlを作成している場合
これはテンプレートエンジンと呼ばれるものの脆弱性を突いた攻撃です.フレームワークで採用されているテンプレートエンジンは調べてみてください.Flaskの場合はjinja2が有名です.
バッファオーバーフロー
問題となる場面: メモリの制御を開発者がおこなう場合
これは結構古典的な攻撃なのでメモリ管理をフレームワークなどに任せている場合は,そこまで気にしなくてもいいと思います.
コマンドラインインジェクション
問題となる場面: ユーザからの入力を用いて別のプロセスでコマンドを実行する場合
ユーザからの入力をエスケープすることで防げます.あと忘年会アプリ程度のもので別プロセスを立ててコマンドを実行したいときってなかなか少ないと思うので,設計を見直すのもいいと思います.
まとめと感想
忘年会当日はなんだかんだみなさんに楽しんでもらえたみたいでとてもよかったです(小並感).自分自身,つくったアプリケーションを公開してだれかに遊んでもらうという経験がはじめてだったのでいい経験をしたなと思っています.普段あまりUIとか気にしないタイプなのですが,やはり遊んでもらうとなると色々考えるところがありました.
ちょっとというかかなり申し訳なかったのが,ぼくがサーバサイドを構築したところで燃え尽きてフロントを丸投げしてしまったとこです...フロント開発をしてくれた同期のみなさんありがとう...最後にユーザテストをしていただいた方々をはじめアプリ制作に関わっていただいた皆様に感謝です!