関連記事
【開発実況シリーズ】Web日報登録システムを作る #15 セキュリティ対策
この記事の動画版はこちら(画像クリックでYoutubeに飛びます)
今回は、開発実況シリーズ「Web日報登録システム」の第15回ということで、前回の続きを進めていきたいと思います。
前回は・・・
前回から、細かい部分の調整を行ってアプリの品質をさらに高めていくための「仕上げ作業」を進めています。
仕上げ作業では、大まかにこのようなことを行っていきます。
①エラー処理の実装
②セキュリティ対策
③リファクタリング&最終調整
前回は、①のエラー処理の実装を行いました。
ユーザーが入力した値をチェックする「バリデーション」の実装や、try-catchを使ったエラー画面遷移の実装を行いました。
今回は、②のセキュリティ対策を行っていきましょう!
セキュリティ対策とは?
Webアプリのセキュリティ対策とは、アプリに対して不正な操作が行われたり、外部からの攻撃などが行われた場合に、プログラムが誤動作を起こしたり、個人情報などの大切な情報が流出してしまわないように対策を行うことです。
セキュリティ対策が不足していたり、プログラムやサーバーに不具合や欠陥があると、そこを利用して攻撃され、システムをクラッシュさせられてしまったり、情報を抜き取られてしまう危険性があります。
ちなみに、こういった欠陥のことを「セキュリティホール」や「脆弱性」と言います。
Webアプリを作る際は、こういった脆弱性を出来るだけ少なく出来るよう、適切な対策を行っていきます。
ただし、脆弱性はプログラムの作り方だけでなく、ミドルウェアやサーバーの不具合や、人為的なミスなどが原因になる場合もあります。
そのため、「脆弱性を少なくして攻撃から守る」という対策と併せて「万が一、情報が抜き取られた場合にも被害を最小限に留める」といった、両面からの対策が大切です。
今回のアプリにも、その両面からこのような対策を行っていきます。
【今回のセキュリティ対策で行うこと】
・パスワードの暗号化
・個人情報の暗号化
・Webアプリの脆弱性対策(XSS/CSRF)
それでは上から順番に実施していきましょう。
パスワードの暗号化
まずは、パスワードの暗号化から行っていきます。
現在、パスワードはこのようにそのまま登録されています。
ちなみに、このように暗号化されずに目で見てそのまま分かる形式のことを「平文」と言ったりします。
現在、パスワードは平文で保存されている訳ですね。
これでは、万が一このデータベースのデータが抜かれてしまった場合に、ユーザーのパスワードが丸わかりになってしまいます。
また、サービス運営者や開発者が、ユーザーのパスワードを知ってしまうというのも、セキュリティ上よろしくありません。
よって、パスワードは暗号化するようにしましょう。
暗号化する方法は色々ありますが、PHPではパスワードを暗号化するための便利な関数が備わっています。
今回は、それを使って暗号化を行っていきましょう。
新規PHPファイルを作成します。
このように、PHPの「password_hash」という関数を使うと、引数で指定したパスワードを暗号化してくれます。
実行すると・・・
passwordという文字列が、このように暗号化されました。
生成された暗号化パスワードを、ユーザーのパスワードとして登録しておきます。
今回のアプリにはユーザー登録機能が無いため、このように手動登録していますが、アプリにユーザー登録機能を実装している場合は、ユーザー登録時に入力されたパスワードを自動的に暗号化して保存する形になりますね。
次は、ログイン処理の部分です。
パスワードが暗号化されたことにより、これまでの方法ではログインが出来なくなっていますので
ログイン処理のほうも調整していきます。
こちらは「password_verify」という関数を使ってチェックします。
こうすることで、ログイン画面からユーザーが入力したパスワードを自動的に暗号化し、データベースから取得した暗号化パスワードと照合してくれます。
これでOKですね。
これで、ユーザーのパスワードは「その人にしか」分からないようになりました。
ユーザーのパスワードと言うのは、たとえサービス運営者であろうとも知ってはいけない情報なんです。
個人情報の暗号化
次に、個人情報の暗号化も行っていきましょう。
本アプリの個人情報は、ユーザーの「名前」ですね。
userテーブルの「name」カラムに保存されています。
こちらも、現在は平文で保存されている状態です。
ユーザー名は、アプリによってはそのまま平文で持っているケースもあると思いますが、万が一データを抜かれてしまった場合に、個人情報流出につながる危険があるので、個人情報に当たるデータは出来るだけ暗号化して保存するようにしましょう。
ただし、こちらは先程のパスワードと異なり、このように、画面上にデータを表示する必要があります。
暗号化したデータを、元の状態に戻すことを「復号化」と言いますが、このデータは復号化する必要があるため、複合化出来る方法で暗号化を行います。
こちらの暗号化手順については、少し複雑なので、今回はスクラッチではなく、以前自作した関数を読み込んで再利用します。
実際の開発でも、こういった共通関数系は毎回ゼロから作るようなことはせず、自分のプログラム資産を活用して作っていきます。
こんな感じで「encrypt()」という関数に、暗号化したい文字列を渡すと、
暗号化した文字列を生成してくれます。
これを、userテーブルの「name」カラム値に置き換えます。
2人目のユーザーも同様に暗号化しておきます。
このまま画面を表示してしまうと、このように暗号化文字列が表示されてしまうため、
表示する際は復号化して表示するようにします。
これで良いですね。
これで、userテーブルのデータが万が一抜かれてしまった場合も、このような暗号化されたデータしか見ることが出来ないためデータ流出の危険性を減らすことが出来ます。
セキュリティ対策の両軸の1つ「万が一、情報が抜き取られた場合にも被害を最小限に留める対策」につながりますね。
XSS対策
続いて、セキュリティ対策のもう一方の軸である「脆弱性を少なくして攻撃から守る」を行っていきましょう。
まずは、クロスサイト・スクリプティング(XSS)対策です。
現在は、例えば業務内容にこのようにHTMLタグが入力されると
このように、表示する際にタグとして認識されてしまいます。
文字の色を変える程度であれば、大きな被害はありませんが、例えば、このようにJavaScriptコードを入力した場合、
スクリプトとして認識され、実行されてしまいます。
この状態では、悪意のあるスクリプトが実行されてしまう危険性があります。
この脆弱性を利用した攻撃手法を「クロスサイト・スクリプティング(XSS)攻撃」と言います。
ちなみに、講座の方では、自分で作った課題アプリに対して実際にXSS攻撃を行い、具体的にどのようにして他のユーザーのアカウントを乗っとるのか?という実験を行いながら、その対策方法を学んでいきます。興味があれば是非こちらからチェックしてみてください。
XSS対策は、データを画面表示する際に行います。
PHPの場合は、このように「htmlspecialchars()」という関数を使ってエスケープ処理を行えばOKです。
毎回この長い関数を記述するのは大変ですし、ソースコードも読みづらくなってしまうので
共通関数として定義して、簡単に呼び出せるようにしておきましょう。
これでOKですね。
CSRF対策
続いて、クロスサイト・リクエスト・フォージェリ(CSRF)対策も実装しておきます。
CSRF攻撃とは、アプリにログインしているユーザーに対して、悪意のあるリンクを踏ませることで意図しないリクエストをアプリケーションに送信させる攻撃手法です。
これを対策するには、リクエストを受けて処理を行う際に、正常な呼び出し元の画面なのかどうか?をチェックするようにします。
CSRF対策は、ワンタイムトークンとセッションを使って実装します。
まず、ワンタイムトークンを生成して、それをセッションと、
呼び出し元の画面のhiddenタグに保存しておきます。
そして、リクエストを受け付ける処理側のプログラムにて、画面から送信されたhiddenタグのトークンと、セッション保存されているトークンが一致するかどうかをチェックします。
一致しなければ、不正呼び出しと判断してエラー画面に遷移させます。
これでOKですね。
正常な画面遷移の場合は、このようにサーバー側処理が動きますが
hiddenのワンタイムトークンを消してアクセスすると、エラー画面に遷移します。
つまり、正しいワンタイムトークンが設置された画面からしか、サーバー側処理は呼び出せなくなっているということですね。
CSRF対策についても、講座にて実際に実験を行いながら学んでいきます。
データ更新処理が行われる他の画面にも実装しておきましょう。
今回は、シンプルなアプリなので最低限の対策のみを実施していますが、実装するアプリの機能によって、適切な対策を行っていくようにしましょう。
なお、セキュリティ対策については、IPAからガイドラインが公開されています。
今回紹介した以外にも様々な対策方法が掲載されていますので、是非一度目を通してみてください。
次回予告
今回は「②セキュリティ対策」を行いました。
ただ作って終わりではなく、このような見えない部分の品質もしっかり高めていきましょう。
①エラー処理の実装
②セキュリティ対策
③リファクタリング&最終調整
次回はソースコードを整えて綺麗に、効率的にしていく作業「リファクタリング」を行っていきます!