このページは福井県立大学の田中求之が2006年1月まで運用していた Mac のサーバ運用に関する会議室 「Web Scripter's Meeting」の記録です。情報が古くなっている可能性がありますのでご注意ください。

CGI 中で Realm を定義する方法

発言者:田中求之
( Date Sunday, April 27, 1997 21:28:10 )


Realm (保護領域)によって、アクセスの際にユーザー名とパスワードの入力を
要求する(認証を行う)のは、サーバーで設定を行うわけですが、CGI において、
その CGI 自身がユーザー名とパスワードの管理を行う形で、認証を行うことが
できます。これは Autorized ヘッダーを利用します。

CGI では HTTP ヘッダーを自分でかかなければならないのはご存知でしょうが、
このヘッダーを適切なものにすることで、さまざまなアクセスのコントロールが
可能になります。この CGI による認証もその一例です。

---- Sample Script ---

property crlf : (ASCII character 13) & (ASCII character 10)

property http_10_header : "HTTP/1.0 200 OK" & crlf ツ
  & "MIME-Version: 1.0" & crlf ツ
  & "Content-type: text/html" & crlf ツ
  & crlf

on ヌevent WWWスsdocネ path_args ツ
  given ヌclass userネ:username, ヌclass passネ:password
  
  if (username = "web" and password = "scripter") then
    
    return http_10_header & "<TITLE>Welcome!</TITLE>" & crlf ツ
      & "<H1>Welcome to my realm</H1>"
    
  else
    
    return "HTTP/1.0 401 Unauthorized" & crlf ツ
      & "MIME-Version: 1.0" & crlf ツ
      & "WWW-Authenticate: Basic realm=\"CGI Realm\"" & crlf ツ
      & crlf ツ
      & "<title>Not Authorized!</title>" & crlf ツ
      & "<h1>Not Authorized!</h1>" & crlf ツ
      & "Sorry, you aren't authorized to access this information."
    
  end if
end ヌevent WWWスsdocネ

-----


このスクリプトを、たとえば myRealm.acgi という名前でセーブして、アクセス
してみてください。ユーザー名とパスワードの入力を要求されるはずです。この
場合、ユーザー名 = web, パスワード = scripter を入力すると、welcome
が表示されます。

ユーザー管理は、ユーザー名、パスワード、realm (Basic Realm) の名前によって
行うことになります。これによって、たとえば、ファイルメーカーに登録されている
ユーザーのみにサービスを提供する CGI といったものがつくれることになります。


このように、HTTPヘッダーについて知識を得ることで、CGI をさまざまに使いこなす
ことが可能になりますので、ぜひ、一度は HTTP プロトコルについて研究される
ことをお勧めします。

loony さんからのコメント
( Monday, April 28, 1997 19:57:30 )

非常に参考になりました。
HTTPプロトコルについて調べるにはどんな参考文献がありますか?

田中求之 さんからのコメント
( Monday, April 28, 1997 21:56:15 )

HTTP/1.1 が Proposed Standard の状態で RFC2068 として公開されていますので、
それを入手されると、今後の HTTP (Web)の方向がわかると思います。まだ Internet
Standard ではなく、あくまでも proposed の段階ですが、すでに HTTP/1.1 対応を
うたったサーバーが出てきているような状況ですしね。

なお、テキストなのに 380K バイトほどあるという、とんでもないドキュメントになって
ますから、覚悟してください。

RFC は、多くのサイトで手に入れることができますが、日本でしたら

ftp://ftp.nic.ad.jp/pub/rfc/

とか

ftp://ftp.lab.kdd.co.jp/internet-doc/rfc/

などから入手できます。

また、W3C には、HTTP や HTML に関する資料(へのリンク)もそろっていますし、
状況などもわかるようになっていますから、プロトコルに関心が出てきた場合には、
要チェックのサイトです。


なお、私が自分用に書いた、ヘッダーに関するメモを、近いうちに公開する予定です。

→  W3C

loony さんからのコメント
( Tuesday, April 29, 1997 12:08:09 )

どうもありがとうございます。早速手に入れました。
これからじっくり読んでみるつもりです。

上記のヘッダをうまく使えば外部アクセスにはパスワード要求、内部アクセスなら素通り
なんてこともできちゃいますね。

田中求之 さんからのコメント
( Tuesday, April 29, 1997 12:58:14 )

そうですね。スクリプトは多少面倒になるでしょうが、IP, ユーザー名, パスワード
などを動的に組み合わせたアクセス管理の仕組みを組めることになります。昼間だけ
アクセスの制限を行うなんてのもできますね。


小林 さんからのコメント
( Wednesday, April 30, 1997 09:19:12 )

cgiでユーザ認証がコントロールできるとのお話、大変興味を持ちま
した。

しかし、Apple Script を理解していない者ですので、どなたかperl
でmyRealm.acgiを書き直せばどのようになるのか教えていただけません
でしょうか。given... のところがどうなるのかがよくわかりません。

rfcを読めばわかることとは思いますが、よろしくお願いいたします。

田中求之 さんからのコメント
( Wednesday, April 30, 1997 12:28:08 )

Perl の具体的なスクリプトの書き方は私にはフォローできませんが、ポイントは
どの言語で開発される場合でも一緒ですので、その点をまとめておくと

1:Username と Password は、Web サーバーからパラメーターで渡される。
Perl の場合は、環境変数として渡されるようになっているはずです。

2:認証を行いたい場合には、以下のHTTPヘッダーを返すようにする。

HTTP/1.0 401 Unauthorized
MIME-Version: 1.0
WWW-Authenticate: Basic realm="Realm名"

<title>Not Authorized!</title>
<h1>Not Authorized!</h1>

認証のけっか、アクセスが認められない場合には、<title> 以降の
ページが相手に表示されます。

CGI のスクリプトは、Username と password を見て、アクセスが認められない
場合は、上の Not Authorized ヘッダーを返すようにするようにしておけば、
あとの処理はブラウザ側で行われます。(ユーザーにusernameとpasswordの
入力を要求し、その入力をもとに再度アクセスを行うという処理をブラウザが
行います)。

小林 さんからのコメント
( Wednesday, April 30, 1997 16:00:19 )

早速のフォローをどうもありがとうございます。

>1:Username と Password は、Web サーバーからパラメーターで渡される。
>Perl の場合は、環境変数として渡されるようになっているはずです。

Unix版のNetscape社のサーバの場合は、remote_userという環境変数でユーザ
名がcgiに渡されます。しかし、当のcgiが起動される以前にユーザ認証が済ん
でいなければ、この環境変数は空白です。
WebSTARの日本語版マニュアルのcgiパラメータのUsernameとPasswordの説明
のところには、「認証が必要な場合に、ユーザ名/パスワードを渡します」と
あります。

田中先生のサンプルの"myRealm.acgi"も、呼び出される前にユーザ認証がおこ
なわれているか、myRealm.acgi自身が保護領域に含まれる設定がなされていな
いとUsernameとPasswordが通知されないのではないでしょうか?

仮にそうだとしても、myRealm.acgiが起動できたということは、サーバが認証
で許可したことになります。サーバがcgiの起動をOKしたのに、その
cgi自身が再度認証をおこなうのは何か変な感じがします。

私自身が何か大きな勘違いをしているような気がしてきました。そうであれば
どうぞお許しを。

loony さんからのコメント
( Wednesday, April 30, 1997 16:46:19 )

上のサンプルを動かしてみました。
サーバーでは認証関係の設定はして無くてもユーザー名、パスワードを聞かれました。
CGIの中の

if (username = "web" and password = "scripter") then

の部分でパスワード要求されてるのでしょうか?それとも

on ヌevent WWWスsdocネ path_args ツ
  given ヌclass userネ:username, ヌclass passネ:password

の部分なのでしょうか?気になります。

小林 さんからのコメント
( Wednesday, April 30, 1997 18:12:53 )

>サーバーでは認証関係の設定はして無くてもユーザー名、パスワードを聞かれました。

やっぱりできるんですね。

>if (username = "web" and password = "scripter") then
>
>の部分でパスワード要求されてるのでしょうか?それとも
>
>on ヌevent WWWスsdocネ path_args ツ
>  given ヌclass userネ:username, ヌclass passネ:password
>
>の部分なのでしょうか?気になります。

私もそこが一番気になります。
同じことが本当にUNIX上のCGIでもできるとありがたいのですが。

田中求之 さんからのコメント
( Wednesday, April 30, 1997 19:10:49 )

認証が行われるプロセスに関して説明が必要のようですね。

ブラウザでは1回のアクセスのようにみえますが、実は2回サーバー(CGI)に対して
アクセスしている、という点がポイントになります。

最初に CGI にアクセスしたときには、当然のことながら username も password
も空になっています。ですから、CGI はブラウザにたいして Not Authorized の
ヘッダーを返します。

すると、このヘッダーを受け取ったブラウザは、この時点でユーザーに対してUsername 
と password の入力を求めます。そして、そこで入力された username と password
を使って、再度、同じ CGI に対してアクセスを行うのです。

今度の場合は、ブラウザから username と password が渡されますから、それを
もとにチェックを行い、もしアクセスを認めているユーザーであれば、then 以下の
ページ(データ)を表示します。もしアクセスが認められないユーザーであった場合は
再度 Not Authorized ヘッダーを返します。

2度目の Not Authorized ヘッダーを受け取ったブラウザは、そのヘッダーに
続いて書かれている、「アクセスは認めないよ」という内容のデータを表示する
わけです( その前にAuthorized Failed といったダイアログが出ますが)。


以上のプロセスは、Web サーバーが Realm で行っているのと同じ処理です。
ですから、サーバー側で Realm の設定をしてなくても、CGI 側で同じような
アクセス管理ができるわけです(サーバーに任せていたことを CGI が全部行う
と考えてもらって結構です)。

この動作は HTTP プロトコルでの Realm のプロセスですから、開発言語や
機種に関係なく、適切なヘッダーを返す CGI さえ作れば利用可能のはずです。

田中求之 さんからのコメント
( Wednesday, April 30, 1997 19:22:40 )

>ブラウザでは1回のアクセスのようにみえますが、実は2回サーバー(CGI)に対して
>アクセスしている、という点がポイントになります。

Web サーバーのログを見れば、

04/30/97  OK  157.6.48.3  /realm.acgi  205  GET  
04/30/97  OK  157.6.48.3  /realm.acgi  116  GET  

のように、2度のアクセスが続けて行われているのがわかるはずです。

loony さんからのコメント
( Wednesday, April 30, 1997 20:09:30 )

なるほど、2回アクセスしてたんですね。
これはCGI一つに対してですから、ユーザー定義アクションで設定したCGI(複数の処理を一つのCGIで処理する)
でも最初のアクセスでユーザー認証が通ればあとは大丈夫なんですよね。

例えば掲示板なんかで最初にパスワードを入れれば後は何度CGIを呼び出してもその度に
パスワードを聞かれることは無いと自分では思っているのですが。

>2度目の Not Authorized ヘッダーを受け取ったブラウザは、そのヘッダーに
>続いて書かれている、「アクセスは認めないよ」という内容のデータを表示する
>わけです( その前にAuthorized Failed といったダイアログが出ますが)。

でも何で二度目って分かるんでしょうか。不思議。

くどい質問ですいません。

loony さんからのコメント
( Wednesday, April 30, 1997 20:13:18 )

あ、そうか。ユーザー名とパスワードを入力したんだからデーターがCGIに渡ってるんだった。

田中求之 さんからのコメント
( Wednesday, April 30, 1997 20:58:03 )

>例えば掲示板なんかで最初にパスワードを入れれば後は何度CGIを呼び出してもその度に
>パスワードを聞かれることは無いと自分では思っているのですが。

そのはずです(確かめてはないですが)。

>でも何で二度目って分かるんでしょうか。不思議。

ブラウザの動作とサーバーのアクセス記録を見ていればわかります。ちゃんと確かめた
ければ CGI の中にアクセスをカウントする機能を追加して表示すればいいわけです。
以下のようなスクリプトの CGI を走らせれば…

-----
property crlf : (ASCII character 13) & (ASCII character 10)

property http_10_header : "HTTP/1.0 200 OK" & crlf ツ
  & "MIME-Version: 1.0" & crlf ツ
  & "Content-type: text/html" & crlf ツ
  & crlf

property acCount : 0

on run
  set acCount to 0
end run

on ヌevent WWWスsdocネ path_args ツ
  given ヌclass userネ:username, ヌclass passネ:password
  
  set acCount to acCount + 1
  
  if (username = "web" and password = "meeting") then
    
    return http_10_header & "<TITLE>Welcome!</TITLE>" & crlf ツ
      & "<H1>Welcome to my realm</H1>" & crlf ツ
      & "<h3>" & (acCount as string) & "</H3>"
    
  else
    
    return "HTTP/1.0 401 Unauthorized" & crlf ツ
      & "MIME-Version: 1.0" & crlf ツ
      & "WWW-Authenticate: Basic realm=\"CGI Realm 2\"" & crlf ツ
      & crlf ツ
      & "<title>Not Authorized!</title>" & crlf ツ
      & "<h1>Not Authorized!</h1>" & crlf ツ
      & "Sorry, you aren't authorized to access this information."
    
  end if
end ヌevent WWWスsdocネ

----

アクセスに成功した時点で、

Welcome to my realm

2

と表示されます。

田中求之 さんからのコメント
( Wednesday, April 30, 1997 21:03:02 )

あ、失敗したときに2度目が表示されることの確認でしたね。でしたら、以下のような
スクリプトで、わざと間違ったユーザー名/パスワードを使うと、

---

property crlf : (ASCII character 13) & (ASCII character 10)

property http_10_header : "HTTP/1.0 200 OK" & crlf ツ
  & "MIME-Version: 1.0" & crlf ツ
  & "Content-type: text/html" & crlf ツ
  & crlf

property acCount : 0

on run
  set acCount to 0
end run

on ヌevent WWWスsdocネ path_args ツ
  given ヌclass userネ:username, ヌclass passネ:password
  
  set acCount to acCount + 1
  
  if (username = "web" and password = "meeting") then
    
    return http_10_header & "<TITLE>Welcome!</TITLE>" & crlf ツ
      & "<H1>Welcome to my realm</H1>" & crlf ツ
      & "<h3>" & (acCount as string) & "</H3>"
    
  else
    
    return "HTTP/1.0 401 Unauthorized" & crlf ツ
      & "MIME-Version: 1.0" & crlf ツ
      & "WWW-Authenticate: Basic realm=\"CGI Realm 2\"" & crlf ツ
      & crlf ツ
      & "<title>Not Authorized!</title>" & crlf ツ
      & "<h1>Not Authorized!</h1>" & crlf ツ
      & "Sorry, you aren't authorized to access this information." & crlf ツ
      & "<h3>" & (acCount as string) & "</H3>"
    
  end if
end ヌevent WWWスsdocネ

----


Not Authorized!

Sorry, you aren't authorized to access this information. 

2

と表示されますよ。

loony さんからのコメント
( Wednesday, April 30, 1997 21:22:59 )

あ、質問の仕方がまずかったようです(^^;。
え〜二回目のアクセス(二回目もダメな場合)で

Sorry, you aren't authorized to access this information.

が表示されるってことは、CGIかブラウザーかが2回目のアクセスだと認識しているの
かと思ったんです。

つまり最初のアクセスだとパスワードを聞いてきて2回目だとSooryが表示されるには
CGIが2回目のアクセスだということを知らないとだめなのでは?もしそうならどうやって
最初と2回目を判断しているんだろう?と思ったわけです。

が…最初も2回目もelse以下のヘッダは返しているんですね。ということは判断して
いるのはサーバーかブラウザーなのでしょうか?あ、でもサーバーのやることをCGI
がやってるわけだからブラウザーかな?

何かだんだん分け分からなくなってしまいましたが…つまりは最初のアクセスはパスワード
を求めてくるのに何故2回目はsorryが表示されるのかというのが疑問だったんです。

田中求之 さんからのコメント
( Wednesday, April 30, 1997 23:12:03 )

あ、なるほど、そういうことでしたか。

判断はブラウザが行っています。

正確に言うと、入力された uername / password が正しくなかった時には、
ユーザーに対して別のユーザー名/パスワードを入力するかどうかを確認します。
そこでユーザーが入力をあきらめると、その時点で、すでにヘッダーと一緒に
送られてきていたページのデータを表示します。新しいユーザー名/パスワード
が入力された場合には、それを使ってもう一度トライするわけです。

言葉で説明するとややこしいようですが、CGI で自分で実験してみてください
(そのとき、Web サーバーのアクセス記録を見ながら行うことを忘れずに)。

小林 さんからのコメント
( Tuesday, May 06, 1997 08:44:26 )

連休中、さぼってしまい申し訳ありませんでした。

>ブラウザでは1回のアクセスのようにみえますが、実は2回サーバー(CGI)に対して
>アクセスしている、という点がポイントになります。

これで私の疑問が無事に解決しました。
ブラウザから正しいusernameとpasswordが渡されるまで、何度でも同じcgiが
呼び出されるわけですね。

すっきりしました、どうもありがとうございました。

loony さんからのコメント
( Tuesday, May 06, 1997 18:35:59 )

納得しました。
これから今使ってるCGIを書き換えようと思います。
今までは外部アクセスと内部アクセスの切り替えにかなり強引な方法を採っていた
のとセキュリティーが全然だったので大変役に立ちました。

ありがとうございました。