パーミッションと実行権限

前へ << ヘッダ CGI のセキュリティ >> 次へ

パーミッション

CGI プログラムを配布しているサイトの説明書には、 「パーミッションは 755 で」とか「700」で、などと書かれています。 この意味は

しかし、実際はサーバごとに設定すべきパーミッションは異なります。 具体的には「CGI の実行権限」によって違うわけです。 大まかにわけて、CGI の実行権限には 2通りのポリシーがあります。

  1. nobody 権限で動かすべし
  2. 各ユーザの権限で動かすべし
1 の場合は、http://X68000.q-e-d.net/、 http://X68000.q-e-d.net/~68user/、 http://X68000.q-e-d.net/~hogehoge/ など いずれの URL にアクセスしても nobody というユーザの権限で動きます。 一方、2 の場合は で動きます。

これは、どちらが正しいという問題ではありません。 例えば大学などでは、各ユーザはメールを読み、プログラムを書き、 レポートを書き、研究成果を書きます。これらのファイルは 各ユーザの権限で置かれています。

もし 2 のように WWW サーバを各ユーザの権限で動かすと、 WWW サーバにバグがあったり CGI プログラムにセキュリティホールがあった場合は、 メールやレポートが外部から読まれたり消去されてしまう可能性があります。 このような場合は nobody 権限で動かすのが適当です。

しかし、一般のプロバイダのような web を公開するだけのサーバでは、 web 以外のファイルは存在しません。 つまりメールなどのような守るべきデータは存在しません。 というより、web コンテンツこそが守るべきデータであると言った方がよいでしょうか。 こういう場合は 各ユーザの権限で実行する方がいいでしょう。

実行権限を確かめる

自分のサーバでは、CGI が nobody 権限で動いているのか、 あるいは各ユーザ権限で動いているのかを確かめましょう。

whoami.cgi (実行結果)

    1: #!/usr/local/bin/perl
    2: 
    3: print "Content-type: text/plain\n\n";
    4: printf "I am %s.\n",(getpwuid($>))[0];
このスクリプトを設置し、実行します。 このサーバ (X68000.q-e-d.net) では、CGI は nobody 権限で動いていますので、
I am nobody.
と表示されます。「I am www.」となるサーバもあるでしょうが、 これも nobody と同じく、どのユーザでも www の権限で動くということです。

もし、各ユーザの権限で動いているならば、「I am 68user.」のように、 自分のユーザ名と同じ表示になるはずです。

suExec と cgiwrap

CGI・SSI を各ユーザの権限で動かしたいなら、 suExec か cgiwrap をインストールして下さい。 ただし、このインストールは管理者しかできません。

一般ユーザが取れる対策: suidperl 編

「うちのサーバはnobody 権限で動く。でも何とかして自分の権限で CGI を動かしたい」 という人もいるでしょう。 そういう場合は、suid という仕組みを使います。まずは UNIX の部屋: setuid をよく読んで下さい。

理解したら、

whoami-suidperl.cgi (実行結果)

    1: #!/usr/local/bin/perl
    2: 
    3: print "Content-type: text/plain\n\n";
    4: printf "I am %s.\n",(getpwuid($>))[0];
を実行してみて下さい。このスクリプトの内容は whoami.cgi と全く変わりません。しかし「I am 68user.」と 所有者権限で動いていることがわかるでしょう。

その理由は (言うまでもありませんが) setuid です。 whoami-suidperl.cgi のパーミッションは 4755 になっています。 perl スクリプトのパーミッションを 4755 にするだけで

という流れになり、めでたく所有者権限で動作します。

なお、スクリプトなのに suid が効くのは、perl と suidperl が気をきかせてくれるからです。sh スクリプトや csh スクリプトではできません。

一般ユーザが取れる対策: wrapper 編

suid-wrapper.cgi (実行結果)

    1: #include <stdio.h>
    2: #include <unistd.h>
    3: #include <sys/types.h>
    4: #include <pwd.h>
    5: 
    6: main(){
    7:     struct passwd *pw;
    8:     uid_t euid;
    9:     char *home_dir;
   10:     char target[128];
   11:     int len;
   12: 
   13:     euid = geteuid();           /* 実効 UID を取得 */
   14:     pw = getpwuid(euid);        /* 実効 UID のホームディレクトリを取得 */
   15:     if ( pw == NULL ){
   16:         fprintf(stderr,"Can't get home directory.\n");
   17:         return 1;
   18:     }
   19:     
   20:     home_dir = pw->pw_dir;
   21: 
   22:     /* /home/foo/public_html/webcgi/sample/perl/whoami.pl を target に */
   23:     len = snprintf(target,sizeof(target),"%s/public_html/webcgi/sample/perl/whoami.pl", home_dir);
   24: 
   25:   
   26:     if ( len >= sizeof(target) ){     /* バッファが小さすぎる */
   27:         fprintf(stderr,"Buffer is too short.\n");
   28:         return 1;
   29:     }
   30: 
   31:     execl(target,target,NULL);  /* 実行 */
   32:   
   33:                                 /* exec からは戻ってこないはずなのに…エラー */
   34:     fprintf(stderr,"Can't exec %s\n",target);
   35:     return 1;
   36: }

前へ << ヘッダ CGI のセキュリティ >> 次へ

$Id: permission.html,v 1.4 2004/06/28 15:51:45 68user Exp $