0

CentOS 6.4 と PostgreSQL 9.0 で mod_perl2.0.4 / Apache2.2 Web アプリを実行しています。

最近まで、私はこのセットアップを持っていました: Apache::DBI と DBI->connect_cached すべての接続に対して、FATAL: sorry, too many clients already私が唯一のユーザーである私の開発領域でも提供し始めていました。

これをデバッグするために、Apache::DBI へのすべての参照を削除し、最新の DBI にアップグレードし、connect_cached のすべての出現箇所を単純な DBI->connect に置き換えました。今では接続がやや少なくなり、その後離れているように思え<IDLE>ます。しかし、すべてのステートメント ハンドルで disconnect() を呼び出していないことに気付きました。なぜなら、Apache::DBI の下では違いがないように聞こえたからです。

現在、私の接続はすべて同じユーザーとして接続されており、SET SESSION AUTHORIZATION を介してどのユーザーであるかに基づいて権限を下げています。データベースを使用する他の一部のアプリでは、資格情報をデータベースに直接渡すことができるパスワード付きログインが許可されているため、この方法を使用しますが、この特定の Web アプリでは、名前をクリックするだけでログインできるようにするシステムのログイン画面を使用します。したがって、将来のセキュリティに対応していますが、現時点では便利です。また、履歴などのデータベース トリガーは、セッション ユーザーが正しく設定されているかどうかに依存して、誰が何をしたかを追跡します。

間違ったセッション ユーザーでデータベース ハンドルが再利用されることを懸念していたので、{ private_user_login => $login_role_name, PrintError => 0, RaiseError => 1, AutoCommit => 1}connect_cached に渡して、各接続をユーザーごとに区別します。しかし、私は常に接続直後にセッション認証を設定するprivate_user_loginので、特定の Apache プロセスに対して、最終的にはユーザーと同じ数の DB 接続が作成され、アイドル状態のままになる可能性があるように、すべてのハッシュが行うことだと思います。すべてのユーザーは、特定の Apache プロセスをランダムに使用することができます。その間、ハンドルは一切切らないので、そのうち使い切ってしまいます。

私の質問は、すべての接続ハンドルが同じように見えるようにするため、開いたままの接続の数を減らすために を取り出しても安全ですprivate_user_loginか、それとも、接続ハンドルが途中で再利用される可能性があるかということです。別のユーザーが (セッション ユーザーを設定した後に) スクリプトを作成して、競合状態を作成しますか? また、Apache::DBI のドキュメントには呼び出しを削除する 必要はないと書かdisconnect()れていますが、Apache::DBI が切断するかどうかを決定できるように、すべてのスクリプトの最後にそのような呼び出しを行う必要がありますか?

言い換えれば、プライベート接続変数がなければ、次の Apache::DBI->connect() が既存の接続を再利用するとき、SET SESSION AUTHORIZATION の効果は持続しますか? もしそうなら、あるリクエストが現在実行されているが、現在データベースハンドルを使用していない間に、接続が別のリクエストによって再利用される可能性はありますか?

4

2 に答える 2

3

可能であれば、多少異なるタックをお勧めします。

Apache ではシンプルに保ちます。安全で信頼できるものにするのが最も簡単な場合は、ユーザーごとにプライベート セッションを使用します。

次に、PostgreSQL サーバーと Apache インスタンスの間に PgBouncer を配置します。トランザクション プーリング モードに設定します。喜んで接続を多重化し、接続がユーザー間で切り替わるたびに DISCARD ALL の呼び出しを処理します。

PgBouncer 経由の接続では、引き続き SET SESSION AUTHORIZATION を使用できると思います。

于 2013-12-13T03:42:11.383 に答える
0

安全そうです。「検証」するには、次のような人為的な競合状態を作成できます。

use Apache2::RequestUtil;
use Apache2::RequestRec;
my $r = Apache2::RequestUtil->request;
$r->headers_out->add('Cache-control' => "must-revalidate, no-cache, no-store");
require Apache2::Request;
my $req = Apache2::Request->new($r);
$r->content_type("text/html");
my $login_role_name = $req->param('u');
$r->print($u);
$r->print('<br>' . $$);
use DBI;

my $dbh = DBI->connect_cached("dbi:Pg:dbname=......,{ RaiseError => 1, AutoCommit => 1});
$dbh->do("set session authorization ?; ", undef, $login_role_name);
{
    use warnings NONFATAL => 'all';
    my $rows = $dbh->selectall_arrayref('select pg_backend_pid(), current_user::text');
    warn "pg ${$$rows[0]}[0] mp $$ auth: ${$$rows[0]}[1] original auth: $login_role_name";
    sleep 10;
    $rows = $dbh->selectall_arrayref('select pg_backend_pid(), current_user::text');
    warn "pg ${$$rows[0]}[0] mp $$ auth: ${$$rows[0]}[1] original auth: $login_role_name";
}

...そして、2 つの異なる '?u=...' URL でヒットします。認証は常に元の認証と一致します。これは、実行中のスクリプト内にある間は dbh を渡すことができないためです。

于 2013-12-17T00:37:27.857 に答える