セキュリティ基礎勉強会#1(PHP)

AWS Cloud9で準備しよう

AWS Cloud9とは?

学習環境は、基本AWS Cloud9というオンライン上の開発環境を使います。

Cloud9を使うことのメリットは、「誰でも開発環境が同じとなる」からです。
MacユーザでもWindowsユーザでも開発環境に差異はなく、原則みなさん同じ環境で作業できます。
また、エディタやMySQLなどの環境も最初から入っているため、環境構築の手間を極力抑えることができてとても便利です。

とは言うものの、環境構築もエンジニアの大事なスキルですので、環境構築を学びたい方は「PHP QUEST」の受講をオススメします。

AWSアカウントを作成しよう

Cloud9の利用には、まずAWSアカウントが必要です。
下記のページにアクセスして、下記登録手順を参考に、自分のアカウントを作りましょう。

※作成にはクレジットカードが必要ですが、講義で使うCloud9ワークスペース1つなら
 仮に「1年間」毎日フルで使い続けても無料です。

AWS公式ページ アカウント登録
https://aws.amazon.com/jp/cloud9/

※参考
AWS公式ページ アカウント登録手順
https://aws.amazon.com/jp/register-flow/

Cloud9 ワークスペースを作成しよう

AWSアカウントが作成できたら、下記サイトを参考に、講義用の「ワークスペース(開発スペース)」を作ってみましょう!

【AWS Cloud9 の使い方】最初に覚えておくべき機能まとめ

https://26gram.com/how-to-use-cloud9

※参照:初心者向け完全無料プログラミング入門

LAMP環境の構築

ワークスペースにPHPをインストールしていきます。

その前に、CentOSのパッケージ管理ツールであるyumを更新していきましょう。

CentOSを用いた環境構築において、一番初めに行うべき操作となります。

(CentOSのyumは、DebianやUbuntuではapt-get、macなどではbrewが一般的)

ターミナル

$ sudo yum -y update

続いてインストールされているPHPのバージョンを確認していきましょう。

PHPコマンドの動作有無によって、PHPのインストール確認にも用いることが出来ます。

ターミナル

$ php -v

するとおそらく、PHP5.6が既に入っている内容が出力されると思います。

この講座ではより新しいバージョンである7系のPHPを利用して開発をしていきたいと思います。
5系と7系はかなり仕様が異なるので、気をつけていきましょう。

まずは、PHPインストールのために、ワークスペースにリポジトリを追加します。
下記コマンドをCloud9のターミナル(コマンドライン)に打ちましょう。

ターミナル

$ sudo yum -y install http://rpms.famillecollet.com/enterprise/remi-release-6.rpm

次に、こちらのコマンドを入力して、PHP7.2をインストールしていきます。
下記はコピペでも構いません。

ターミナル

$ sudo yum -y install php72 php72-mbstring php72-pdo php72-mysqlnd

↑ PHP 7.2  をインストールします。

$ sudo unlink /usr/bin/php

↑  リンクが、PHP5.6に貼られている状態を解除します。

$ sudo ln -s /etc/alternatives/php7 /usr/bin/php

↑  リンクを、PHP7.2に貼り替えています。

$ php -v

バージョン確認して、下記の様に「PHP7.2~」と表示されればリンク設定まで完了です!

ターミナル

PHP 7.2.24 (cli) (built: Oct 31 2019 18:03:13) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies

データベースをつくろう

では早速、データベースにログインしてみましょう!

まず、データベースサーバが起動しているかどうかを確認して、

ターミナル

$ sudo service mysqld status

データベースサーバがまだ起動していない場合は起動して下さい。

ターミナル

$ sudo service mysqld start

データベースサーバの自動起動設定をしておきましょう。

ターミナル

$ sudo chkconfig mysqld on

そして、下記コマンドでMySQLにログインします。
(rootは先ほど設定したユーザ名ですね)

ターミナルで、下記コマンドを実行して、文字化け対策を行います。

ターミナル

$ sed -e "/utf8/d" -e "/client/d" -e "/^\[mysqld_safe\]$/i character-set-server=utf8\n\n[client]\ndefault-character-set=utf8" /etc/my.cnf |sudo tee /etc/my.cnf

/etc/my.cnfに、SQLの設定が追加されて、日本語でデータを保存可能となりますので、SQLを再起動します。

ターミナル

$ sudo service mysqld restart

ターミナル

$ mysql -u root

文字化けの対策がされているかどうかを確認できます。

mysql> show variables like "chara%";

下記のようになればOKです。

では、下記の「データベース作成」以降のコマンドを打ち込みましょう。

ターミナル

mysql> CREATE DATABASE bbs;
mysql> USE bbs;
mysql> USE databases;
mysql> CREATE TABLE posts(id int NOT NULL AUTO_INCREMENT, title varchar(20), body varchar(140), index(id));
mysql> DESCRIBE posts;
mysql> INSERT INTO posts(title, body) VALUES("PHP", "セキュリティ勉強会");
mysql> SELECT * FROM posts;

これで、MySQLを接続するための準備完了です。
一旦、MySQLから下記コマンドでログアウトしましょう。

control(Ctrl)キー + Cキー を押す

(あえて)非セキュリティ対策アプリを作って攻撃してみよう

下記のファイルを新規作成して記述してみましょう。

AWSで作ったワークスペース直下の環境で作成頂ければOKです!

ファイルの作り方などは、下記サイトを参照下さい。

【AWS Cloud9 の使い方】最初に覚えておくべき機能まとめ

https://26gram.com/how-to-use-cloud9

non-security.php <HTML部分>

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>PHP掲示板</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="PHPのフルスクラッチ開発で作られた掲示板です">
    <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"  rel="stylesheet">
</head>
<body>
    <header class="navbar navbar-dark bg-dark">
        <div class="container">
                <div>
                    <a class="navbar-brand" href="/">
                        PHP Security
                    </a>
                </div>
        </div>
    </header>
    <div class="container my-5">
        <h1 class="h5 mb-4">
            投稿一覧
        </h1>
        <?php //foreach($results as $result): ?>
            <section class='card my-4'>
                <div class='card-header'>
                    <h5><?php //echo $result["title"] ?></h5>
                </div>
                <div class='card-body'>
                    <p class='card-text'>
                        <?php //echo $result["body"] ?>
                    </p>
                </div>
                <div class='card-footer'>
                </div>
            </section>
        <?php //endforeach; ?>
        <section class="container">
            <div class="border p-4">
                <h1 class="h5 mb-4">
                    新しい投稿
                </h1>
                <form method="POST" action="non-security.php" class="mb-0">
                    <div class="form-group">
                        <label for="title">
                            タイトル
                        </label>
                        <input name="title" class="form-control" type="text">
                    </div>
                    <div class="form-group">
                        <label for="body">
                            本文
                        </label>
                        <textarea type="textarea" name="body" class="form-control" rows="4"></textarea>
                    </div>
                    <input type="submit" class="btn btn-primary" value="投稿する">
                </form>
            </div>
        </section>
    </div>
    <footer class="footer bg-dark">
        <div class="container">
            <p style="color:white; text-align:right;">
                ©QuestAcademia All rignts reserved
            </p>
        </div>
    </footer>
</body>
</html>

記述できたら、下記コマンドでPHPビルトインサーバを立ち上げて、アプリの見た目が正しくできているか確認しましょう。

ターミナル

$ php -S 127.0.0.1:8080

プレビューを表示させてみましょう。
Cloud9画面上のメニューの Preview を押し、「Preview Running Application」を実行すると下記のようなプレビューが表示されるはずです。

※URLの最後に、「/non-security.php」と記述がないと、
 対象のページは表示されませんので、ご注意下さい。

また、下の画像の右上の赤丸で示しているボタンを押すと、プレビュー画面を別タブで見ることができます。
今後、動作確認をする場合には、原則プレビューを別タブで見ながら行うようにしましょう。

なお、コマンドラインで新たなコマンドを実行するために「サーバを停止したい」場合などは、下記のコマンドを入力すれば、サーバを止めることが可能です。

  • Mac control + C キー同時押し
  • Windows Ctrl + C キー同時押し

non-security.php  <PHP部分(上のコードに追記)>

<?php
    // MySQLサーバ接続に必要な値を変数に代入
    $username = 'root';
    $password = '';
    // PDO のインスタンスを生成して、MySQLサーバに接続
    $dbh = new PDO('mysql:host=localhost;dbname=bbs;charset=UTF8;', $username, $password);
    if ($dbh == null){
        print('接続に失敗しました。<br>');
    }else{
        print('接続に成功しました。<br>');
    }
    $title = $_POST['title'];
    $body = $_POST['body'];
    try{
        echo $title."<br>";
        echo $body;
        //$sql = 'INSERT INTO posts(title, body) VALUES("'. $title .'","'. $body .'");';
        //$stmt = $dbh->query($sql);
    }catch(PDOException $e){
        print($e->getMessage());
    }
    $sql = 'SELECT * FROM posts';
    $stmt = $dbh->query($sql);
    // 結果レコード(ステートメントオブジェクト)を配列に変換する
    $results = $stmt->fetchAll();
?>
<!DOCTYPE html>
<html lang="ja">
//(以下省略)

上記コードはセキュリティ対策できていないので、あえて攻撃者の気持ちになって攻撃を仕掛けてみましょう・・・!