効果的な簡単のWebサーバセキュリティ対策「PHP編」

今日では、PHPを使って開発されたウェブサイトやウェブアプリケーションは、世界のインターネットの80％を占めています。PHPは登場以来、多くの問題を抱えています。その中に最も重要なのは、様々なセキュリティ問題です。

確かに、PHPのカーネルには非常に多くの脆弱性がありるですが、でも今まで、セキュリティ問題のほとんどは、PHPカーネルではなく、ウェブアプリケーションのロジック自身の脆弱性に起因しています。

Webアプリケーション自身の問題を置いといて、サーバー内のPHP環境の設定が間違っていることがもう一つの原因だ。

# セキュリティ対策前提条件

**`FastCGI`モードや`apache2handler`モードなど、どのような方法でphpを実行しても、`root`ユーザーとしてphpを実行することはいけません。そうでなければ、すべてが無意味になってしまう。**

# できるだけ、最新バージョンのPHPを使用する

PHPの最新版は一般的に多くの脆弱性を修正しています。

セキュリティエンジニアとしての私の視点では、例えば今最新版のPHPは7.4.7、それバージョンのPHPを使われば、利用できるの脆弱性がほとんどありません。

でも、なぜその部分のタイトルは「できるだけ」をかいていますか？

あなたもPHPアプリケーションの開発者なら、もしマイナー版のバージョン番号が20以下のバージョン使用するとき、たくさん知らないのバグはあなたを待てているそのようなことがあります。

# PHP環境のセキュリティ設定

それでは、PHP環境のセキュリティ設定を始めましょう。

## リスク関数を無効化

以下のPHP関数は、ほとんどのWebShellが利用している。 そのため、それらを無効にする必要があります。

    passthru exec system chroot 
    chgrp chown shell_exec proc_open 
    proc_get_status popen ini_alter ini_restore 
    dl openlog syslog readlink 
    symlink popepassthru stream_socket_server 

そのため、`php.ini`ファイルの disable_functions パラメータを変更する：

    disable_functions = passthru,exec,system,chroot,chgrp,chown,shell_exec,proc_open,proc_get_status,popen,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,stream_socket_server

**ただし、この設定では「`eval()`」関数を無効にすることはできません。なぜなら、これはPHPのカーネルエンジン「ZendEngine」が提供するの関数だからです。**

## PHPバージョン番号を非表示

デフォルトでは、サーバーは使用しているのPHPバージョンの番号をHTTPのレスポンスヘッダ部分で見せる。

例えば:

![Snipaste_2020-07-08_23-52-55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/668967/a299907f-08bc-865f-b31a-934ce4d159a2.png)

これは、特定のバージョンPHPの脆弱性に対する攻撃をもたらす可能性があります。だから、安全のためには、PHPバージョン番号の表示をオフにする必要があります。

同じに、`php.ini`ファイル内の設定に変更する：

    expose_php = Off

## エラーメッセージの表示を非表示

エラーメッセージには攻撃者が利用できる情報が大量に含まれており、だから、本番環境ではエラーメッセージの非表示するも必要だ。

同じに、`php.ini`ファイル内の設定に変更する：

    display_errors = Off

また、エラーを見つけやすくするために、ローカルのエラーログ機能を有効にすることもできます。

    log_errors = On
    error_log  = /var/log/php_error.log

## リモートファイルへのアクセス禁止

この機能を使うことで、PHPアプリケーションの脆弱性を利用することがもっとやすい。

特に最近では、ほとんどの攻撃でPHPのデシリアライズが利用している。 この機能を使用すると、Pharのデシリアライズ攻撃のために、問題がある Phar ファイルパッケージを簡単にロードすることがもっとやすい。

同じに、`php.ini`ファイル内の設定に変更する：

    allow_url_fopen =  Off
    allow_url_include = Off

もし、リモートダウンロード機能を使いたいとき、cURL関数を使いでください。

## PHPアプリケーションのフォルダアクセス権限をリミット

PHPのデフォルト設定では、PHPスクリプトプログラムがサーバー中の任意のファイルにアクセスできる。これはとでも危険なことだ。

このリミットを指定するなら、サーバー侵入による被害を大幅に軽減することができます。

通常、`php.ini`ファイル内の設定に変更するができる：

    open_basedir = /data/www-data:/tmp/:/var/tmp/:/proc/

しかし、私はこのパラメータをWebServerのWebホスト設定ファイルに設定することをお勧めします。

Apacheではこのように設定しています:

    <VirtualHost *:80>
    ......
    php_admin_value open_basedir "/data/www-data:/tmp/:/var/tmp/:/proc/"
    ......
    </VirtualHost>

nginxのfastCGIモードで使用するのとき、このWebホストのデフォルトディレクトリにある「.user.ini」ファイルを修正するか、作成する必要があります。 

通常、このファイルを直接修正することはできません。そこで、このファイルのロックを解除するため、まず以下のコマンドが必要です:

    chattr -i /data/www-data/.user.ini

そして、このファイルの内容を変更します:

    open_basedir=/data/www-data:/tmp/:/var/tmp/:/proc/

変更後、再度このファイルをロックします:

    chattr +i /data/www-data/.user.ini

ロックが完了した後、設定の自動有効が有効にするまでに最大5分程度かかる場合があります。 あるいは、PHP-FPMを再起動して設定をすぐに有効にすることもできます。

## `session.upload_progress.enabled`を禁止する

この機能を使うことで、PHPアプリケーションの脆弱性を利用することがもっとやすい。大体効果と`allow_url_fopen`や`allow_url_include`同じだ。

同じに、php.iniファイル内の設定に変更する：

    session.upload_progress.enabled = Off

## PHP-FPM(Nginx.FastCGIなど)モードで、chrootとchdirを設定する

chrootとchdir設定は、PHP-FPMモードで専門な設定です。その設定の効果簡単に説明なら、それはopen_basedirのパワー強化版。この機能は、各WEBホストの作業ディレクトリを完全に分離します。

しかし、それは使用するための巨大な障壁を作ることになる。例えば、「sendmail」の機能が使えなくなります。 また、任意のドメインにアクセスすることもできませんなど。

chroot 機能を使用するためには、他にも変更が必要な設定がたくさんあるので、ここでは詳しく説明しません。その後、chrootedの設定方法を記事にします。

また、こちら([PHP Documentation chroot](https://www.php.net/manual/ja/install.fpm.configuration.php#chroot))をクリックすると詳しい説明が表示されます。

## PHP アプリケーションの管理用バックエンドのパスを予測不可能な名前に変更します。

この対策も実はとても重要です。

世界のインターネット中には、悪質な脆弱性スキャナーがたくさん存在します。

例えばたくさん悪い脆弱性スキャナーはphpmyadminのデフォルトパスにスキャナーしたいです。

正直言ば、phpmyadminがバグフリーであることを保証できない。

なお、一番簡単な方法は、phpmyadminを簡単にスキャンアウトさせらねないことです。

例えば、「.../1ba286020e414afb/...」このようなみたいを変更します。

同じに、WordPressのWP-adminようなのコントロールパネルは同じの方法に対応する。

# 結論

上記のセキュリティ設定したばいは、PHPサーバーのセキュリティを最大化したり、サーバーが侵害された後の被害を最小限に抑えたりするためのものです。

しかし、PHPアプリケーションの開発者が十分にセキュリティを意識がなければ、サーバーへの侵入の可能性を防ぐことはできません。

    
もしあなたがPHP開発者であれば、ひとつ覚えておいてください: 

**「eval()」関数、絶対に使わないでください。**