------------------------------------------------------------------------
Subject: DeleGateのアクセス制御について (draft-v1)
------------------------------------------------------------------------
To: delegate@etl.go.jp
Message-ID: 
From: Yutaka Sato 佐藤豊 
URL: http://wall.etl.go.jp/delegate/howto/acl/
Date: 97/09/17

1.概要

DeleGateは、HTTP用プロキシ(HTTPクライアント向けのプロキシ)としてだけで
なく、FTP,POP,NNTP等、複数の応用プロトコル用のプロキシとして動作します。
あるプロトコル用のプロキシとして動作させるには、起動時のコマンド引数や環
境変数で「SERVER=プロトコル名」と指定します。SERVERが無指定の場合には、
DeleGate固有プロトコルのサーバと、HTTP用プロキシサーバを兼ねたものとなり
ます。DeleGate固有プロトコルのサーバ(MASTER-DeleGateあるいは"generalist"
と呼ばれる)は、DeleGateがサポートしている全ての応用プロトコルを中継でき
るものであり、セキュリティの観点から、この形態での利用は、DeleGateの多段
中継を行う場合に限定されるべきです。したがって、HTTP専用プロキシとして用
いる場合には「SERVER=http」と明示することを推奨します。

DeleGateにおけるアクセス制御は、DeleGateをどのようなプロトコルの中継に利
用するかによらず、「PERMIT」という共通のパラメタにより行います。これは
「どこから、どこへの、どんなプロトコルによる」アクセスを許可するかを指定
するもので、以下のような形式で記述します。(これはアクセス制御だけでなく
経路制御などにも共通して用いられる形式です)

  PERMIT=dstProtoList:dstHostList:srcHostList

右辺のパラメタの中で、dstProtoList はアクセス先サーバとの通信プロトコルを
(必要ならばポート番号も)限定するものです。dstHostList はアクセス先サー
バのホストを(必要ならばポート番号も)、srcHostList はアクセス元のクライ
アントのホストを(必要ならばユーザ名も)を限定するものです。これらはいず
れも要素を "," で区切って並べたリストの形式で表されます。また、「限定しな
い」すなわち「全て」を表すには、"*" を指定します。

PERMITが無指定の場合にはデフォルト値が適用されます。dstProtoList の部分の
デフォルト値は「SERVER=プロトコル名」で指定したプロトコルごとに決められて
います。一方 dstHostList および srcHostList の部分は、プロトコルによらず
共通のデフォルト値が決められています。例えば「SERVER=http」の場合には、

  PERMIT=http,https/{443,563},gopher,ftp,wais:*:./@,-/@,localhost"

がデフォルト値となっています。つまり、中継を許可するプロトコルは HTTP,
HTTPS, Gopher, FTP, Wais に限定され、また HTTPS はポート番号 443番と 563
番に限定されています。アクセス先サーバのホストはデフォルトでは限定されて
いません。アクセス元のクライアントのホストについては、DeleGateサーバが動
作しているホストから見て「ローカルなネットワーク(./@)、あるいは直接接続し
ているネットワーク(-/@)上のホスト、あるいはローカルホスト自身」のみ許可、
と限定されています。ここでのネットワークの単位は、IPアドレスのクラス A,B,
C を単位としています。このようなデフォルトになっているのは、IPアドレスを
取得する組織体にはこれらのクラス単位でアドレスが割り当てられるのが(少く
とも最近までは)一般的であり、IPアドレスを取得した各組織体において、組織
内部での相互アクセスを自由とすることが多いためです。
一つの組織内のユーザ全体に提供するHTTPプロキシサービスでは、多くの場合こ
のデフォルトのアクセス制限のままで十分なものと考えられます。

PERMITが明示的に指定された場合、上記のデフォルト値は無効となり、明示指定
されたものだけが許可されます。PERMITパラメタは複数指定することができ、い
ずれかのPERMITに適合すれば中継許可となり、いずれのPERMITにも適合しない場
合には不許可となります。以下に例を示します。

  PERMIT=ftp:*:*.my.dom  1)
  PERMIT=http,gopher:*:*.my.dom,*.peer.dom,!*.rascal.peer.dom  2)
  PERMIT=http:www.my.dom:!{*.my.dom,*.peer.dom},!*.rascal.outer.dom  3)

この3つのPERMIT指定はそれぞれ、以下のようなアクセス制限を表しています。

 1) my.dom に属する任意のホストから任意のFTPサーバへの接続を許可
 2) my.dom または peer.dom に属する(ただし rascal.peer.dom に属するもの
    を除く)ホストから、任意のHTTPおよびGopherサーバへの接続を許可
 3) my.dom にも peer.dom にも属さないホストについては、rascal.outer.dom
    に属するものを除き、www.my.dom へのアクセスのみを許可
 *) いずれにも適合しない rascal.outer.dom のホストについては、全て不許可
  
PERMITパラメタは、あるクライアントホスト(C)から、あるプロトコルによる、あ
るサーバホストへのアクセスを要求された時、それを許可するか否かを判定する
ために用いられます。例えば上の例に示したように srcHostList は左端から順に
走査される集合演算を表し、右端まで走査を終えた時に、求めた集合の中に、検査
対象のホスト(C)が含まれる時、そのPERMITパラメタが採用されることになります。
実装上は、リストの要素を左端から走査し、検査対象のホスト(C)が、リスト要素
のホスト名パターンに適合した時に、"!"が前置されていないならば適合ホスト集
合に「含まれる」、"!"が前置されていれば「含まれない」と判定し、これを右端
まで繰り返しています。例えば、

  "*.dom,!*.xxx.dom,*.yyy.xxx.dom"

は、「*.dom に適合するものは許可する、ただし*.xxx.dom に適合するものは不許
可、ただし *.yyy.xxx.dom に適合するものは許可」を意味します。このように通常、
"!"はそれより左側で「含まれている」としたものを打ち消すために使われますが、
3)の例のように、ホストリストの先頭が "!" で始まる場合、先頭に "*," が省略
されているものとして扱われます。つまり、通常は求める適合ホスト集合が空の状態
から走査が始まりますが、リストが "!" で始まる場合には全てのホストを含んだ集
合を初期状態として始まることになります。

なお、HostList をDeleGate起動時のコマンド引数として記述するとき、shell等の
コマンドインタプリタの多くでは "*" や "!"、あるいは "{" や "}" が予約文字で
あり、"'" で囲んだり "¥" などでエスケープする必要があることに注意して下さい。

★注★ ここでの記述は DeleGate/2.0 (95年1月版) 以降の版に関するものであり、
DeleGate/1.X (94年版) には当てはまりません。DeleGate/1.X でのアクセス制御方
法は上記のPERMITによるものではなく、またデフォルト値が PERMIT=*:*:* に相当
する危険な状態になっています。現在の版(4.X)と比べて性能的にも機能的にも著し
く劣る 1.X を利用するのは無意味であり、実際既にほぼ絶滅したと見られますが、
もし動作しているものを見かけられましたら、速やかに成仏させて下さい。


2.詳細

dstHostList および srcHostList の「hostList」は、ホストの名前またはアドレ
ス(のパターン)の並びであり、各々の要素は以下の例のように表されます。

  wall.etl.go.jp  … ホスト名
  192.168.1.1     … IPアドレス
  *.etl.go.jp     … ドメイン名が etl.go.jp であるホスト全て
  192.168.[16-32] … 192.168.16.0 〜 192.168.32.255
  192.168.16.*    … 192.168.16.0 〜 192.168.16.255
  192.168.*       … 192.168.0.0  〜 192.168.255.255
  ?               … ホスト名/IPアドレスの間の検索が出来ないホスト
  .               … DeleGateサーバのホスト(プライマリ名)
  -      … クライアントが接続したDeleGateサーバ・ホストのインターフェイス

各要素の前後には、以下のような修飾を加えて、さらに限定を狭める("/mask" の
場合は緩める)ことができます。

  [userList@] hostName [:portList] [/mask]

mask には、255.255.255.0のようなドット記法によるIPアドレス形式の他に、以下
のような省略記法が使えます。

  @  … デフォルトマスク
  @A … 255.0.0.0 と等価
  @B … 255.255.0.0 と等価
  @C … 255.255.255.0 と等価

例えば、デフォルトのアクセス制限に含まれる "-/@" は、「DeleGateサーバに接続
して来たクライアントのホスト(ネットワークインターフェイス)アドレスと、それ
受けたDeleGate側のネットワークインターフェイスのアドレス("-")が、同一の(ク
ラスA,B,またはCの)ネットワーク("@")に属する」場合を表しています。これは、
複数の異なるローカルネットに接続しているホスト上で、全てのローカルネットから
のアクセスをまとめて許可することを簡単に表現するために導入された記法です。

IPアドレスからホスト名が逆引きできないホストは "?" と表すことができ、また
Identプロトコルでクライアントのユーザ名を調べられなかったユーザは "?" と
表すことができます。これらを用いて「名無しのホスト、あるいはIdentで名乗らな
いユーザからのアクセスを拒否」することを、PERMITの srcHostList において
"!?,!?@*" のように記述できます。

PERMITに限らず、":" や "," で区切られた複数の値を持つDeleGateのパラメタに
おいて、値の中に現れる ":"や "," が区切り文字と解釈されないようにするには、
値を "{" と "}" で囲みます。例えば、
  PERMIT="http/{80,8080}:{sv1:80},{sv2:8080}:{user1,user2}@{host1,host2}"
のようにします。

以下に、DeleGateにおけるアクセス制御用パラメタの構文をまとめます。

   ACLparams:   *permit | *reachable | *reliable
   permit:      "PERMIT=" permitSpec
   permitSpec:  protoList [ ":" dstHostList ":" srcHostList ]
   protoList:   protoSpec [ "," protoList ]
   protoSpec:   protoName [ "/" portList ]
   protoName:   "*" | "http" | "https" | "ftp" | "gopher" | ...
   portList:    number | "{" number-list "}"
   dstHostList: hostList
   srcHostList: hostList 
   hostList:    [ "!" ] hostSpecs [ "," hostList ]
   hostSpecs:   hostSpec | "{" hostSpec *[ "," hostSpec ] "}"
   hostSpec:    [ userList "@" ] hostPort [ "/" mask ]
   userList:    [ "!" ] userSpec [ "," userList ]
   userSpec:    "*" | "?" | name | "{" name-list "}"
   hostPort:    hostName | "{" hostName ":" number-list "}"
   hostName:    host-name | namePat | ip-address | addrPat | "." | "-" | "?"
   namePat:     "*." domain-name
   addrPat:     number *[ "." number ] "." numPat
   numPat:      "*" | "[" number "-" number "]"
   mask:        ip-address | "@A" | "@B" | "@C" | "@"
   reachable:   "REACHABLE=" dstHostList
   reliable:    "RELIABLE=" srcHostList

   ip-address:  number "." number "." number "." number
   host-name:   name "." domain-name
   domain-name: name "." domain-name
   number-list: number [ "," number-list ]
   name-list:   name [ "," name-list ]

上の構文に示したように、プロトコル名、ホスト名、ポート番号など「通信の容れ
物」から得られる情報に基づくDeleGateのアクセス制御のためのパラメタとしては、
これまで説明してきた

   PERMIT=protoList:dstHostList:srcHostList

という3つの要素の組合せによる形式の他に、以下のものがあります。

   パラメタ形式           デフォルト値
   ---------------------  --------------------------------------
   PERMIT=protoList       SERVERに指定したプロトコルによる        … 1)
   REACHABLE=dstHostList  *                                       … 2)
   RELIABLE=srcHostList   ./@,-/@,localhost                       … 3)

以下では、上記1)の形式を便宜上PERMIT1、前述の3つ組のPERMITをPERMIT3と呼ぶ
ことにします。1)〜3)の各パラメタは複数個指定することができ、また、明示的に
指定された場合にはデフォルト値は無視されます。

1)〜3)が指定している内容はそれぞれ、PERMIT3 における protoList, dstHostList
そして srcHostList にそれぞれ対応しますが、PERMIT3 の指定より優先します。
すなわち、これらは PERMIT3 が無指定の場合のデフォルト値であるとともに、
PERMIT3 を明示指定する場合のアクセス許可範囲の上限を束縛し、PERMIT3 でその
範囲より広いアクセス許可を与えても無視されます。例えば、
  SERVER=http REACHABLE=only-you PERMIT="*:*:*"
とした時、この PERMIT3 の protoList 部分の "*" は、「SERVER=httpの場合に
デフォルトで許可されているプロトコル全て」という意味にないます。また、
dstHostList の部分の "*" は、REACHABLE で指定した only-you のみを意味します。

実装上、DeleGateは以下のような判定野アルゴリズムを実行した結果、『許可』と
なったものについてのみ、中継を行います。

   PERMIT1 に指定されたプロトコルによるサーバへのアクセスであり、
    REACHABLE に指定されたサーバへのアクセスであり、
     RELIABLE に指定されたクライアントからのアクセスである時、
      PERMIT3 が無指定であるか、または、
      PERMIT3 が一つ以上指定されていてそのいずれかに適合するなら『許可』

ここで、3) の RELIABLE については、それが明示的に指定されなかった場合に、
(srcHostListを限定している)PERMIT3 が1つ以上指定された時、RELIABLE は
無検査(RELIABLE="*"に相当)となります。この少し複雑な仕様は、DeleGateの
アクセス制御機能を段階的に拡張して来た各段階で、古いバージョンとの互換性を
保存するために生じています。ただし、現行のバージョンでは、REACHABLE や
RELIABLEを使う必要は無く、従って上述のように PERMIT3 と RELIABLE を併用
する際のDeleGateの振舞いを考慮する必要もありません。

ただし、PERMIT1 と PERMIT3 を併用する必要はあります。PERMIT1 のデフォルト値
は、SERVERで指定したプロトコルによって、以下のように決まります。

   SERVER  PERMIT1のデフォルト値
   ------  --------------------------------------------------
   http    "http,https/{443,563},gopher,ftp,wais"
   telnet  "telnet/23"
   socks   "socks,tcprelay"
   その他  "." (SERVERに指定したプロトコルそのものを意味する)

このため、例えば HTTP プロキシで NNTP/HTTP の変換中継も行いたい、という場合
には、以下の例のように PERMIT1 で nntp を明示指定してやる必要があります。

   PERMIT=nntp,http
   PERMIT=nntp:nntpServerList:srcHostList
   …

# PERMIT1 のデフォルト値をもとにして、加えたり、"!" で除外したりできると
# 良いと思いますが、現在までの版(DeleGate/4.3.3)では実現されていません
# (たぶん)
------------------------------------------------------------------------