ユーザの ID、IPアドレスをそれぞれ User, Addr とすると、
プロトコルは以下のようになる:

セッション確立:
 1. client:
    User を送信。
 2. server:
UserPubKey = lookup(User)
    SessionID = encrypt(ServerPrivKey, {random(), time(), Addr})
    Challenge = encrypt(UserPubKey, SessionID) を送信。
 3. client:
    SessionID = decrypt(UserPrivKey, Challenge)
    を得てセッション確立。

セッション中:
 1. client:
    SessionID とリクエストを送信。
 2. server:
    {random(), t, a} = decrypt(ServerPubKey, SessionID)
    (time() < t+TIMEOUT && a == Addr であれば valid なセッションであると
    みなしてリクエストを処理する。

セッション終了:
 (開始後一定時間がたった SessionID は invalid とみなされるので、
 明示的なセッション終了手続きはない)

…ということで、1セッションごとにサーバ側でなんらかの復号をおこなう
必要があると思うんだけどどうだろう。結構重いんじゃないかと思うが、
ただサーバ側での暗号化・復号化はただ単に「サーバさえわかればいい」
レベルのものなんで、べつに RSA なんかをわざわざ使う必要は
ないのかもしれないな。ただしその場合はサーバ側のプログラムを
極秘にしておく必要があるし、なおかつその (valid な ID かどうかを判定する)
アルゴリズムが絶対に解析されないという自信がないとだめだろうね。

公開プロキシの問題は依然として残るな。