Postgresql SET会话授权多用户mod-perl2连接缓存的安全设计
我有一个mod_perl2.0.4/Apache2.2 web应用程序,运行在CentOS 6.4和PostgreSQL 9.0上 直到最近,我还为所有连接缓存了:Apache::DBI和DBI->connect\u,这开始导致Postgresql SET会话授权多用户mod-perl2连接缓存的安全设计,postgresql,database-connection,dbi,mod-perl2,apache-dbi,Postgresql,Database Connection,Dbi,Mod Perl2,Apache Dbi,我有一个mod_perl2.0.4/Apache2.2 web应用程序,运行在CentOS 6.4和PostgreSQL 9.0上 直到最近,我还为所有连接缓存了:Apache::DBI和DBI->connect\u,这开始导致致命的问题:抱歉,即使在我唯一的用户所在的开发区域,已经有太多的客户机了 为了调试它,我删除了对Apache::DBI的所有引用,升级到最新的DBI,并用普通DBI->connect替换了所有出现的connect_缓存。在我看来,现在的连接少了一些,然后就离开了。然而,我
致命的问题:抱歉,即使在我唯一的用户所在的开发区域,已经有太多的客户机了
为了调试它,我删除了对Apache::DBI的所有引用,升级到最新的DBI,并用普通DBI->connect替换了所有出现的connect_缓存。在我看来,现在的连接少了一些,然后就离开了
。然而,我意识到我并没有在所有语句句柄上调用disconnect(),因为在Apache::DBI中它听起来像是没有什么区别的
“我的连接”当前以同一用户的身份连接所有用户,然后通过设置会话授权降低其权限(基于该用户)。我这样做是因为其他一些使用数据库的应用程序允许密码登录,可以将凭据直接传递到数据库,但这个特定的web应用程序使用荣誉系统登录屏幕,您只需单击自己的姓名即可登录。因此,它为未来的安全性做好了准备,但目前已经实现了便利性。此外,历史记录等的数据库触发器依赖于会话用户被正确设置以跟踪谁做了什么
因为我担心数据库句柄被错误的会话用户重用,所以我将{private\u user\u login=>$login\u role\u name,PrintError=>0,RaiseError=>1,AutoCommit=>1}
传递给连接缓存,以按用户区分每个连接。但由于我总是在连接后立即设置会话授权,我假设所有的private\u user\u login
hash都是这样做的:对于给定的Apache进程,可能创建的DB连接和空闲的DB连接数至少与用户数相同,如果最终每个用户都能随机使用给定的Apache进程。同时,因为我没有断开任何手柄,它们最终会被用完
我的问题是,是否可以安全地使用<代码> PrimeTyAuthErthLogy< /Cord>使所有的连接句柄看起来相同,以减少打开的连接的数量,或者是否有可能在一个脚本的中间重新使用连接句柄(在设置会话用户之后)由不同的用户使用,从而创造了一种竞赛条件?另外,尽管Apache::DBI的文档说我不需要删除
disconnect()
调用,但我是否应该在每一个脚本的末尾都有这样一个调用,以便Apache::DBI可以决定是否断开连接
换句话说,在没有我的私有连接变量的情况下,当下一个Apache::DBI->connect()重用现有连接时,SET SESSION AUTHORIZATION的效果会持续吗?如果是这样,当一个请求正在执行但当前未使用数据库句柄时,是否有可能另一个请求重新使用连接?如果可以的话,我建议使用稍微不同的策略
在Apache中保持简单。使用每个用户的私有会话,如果这是最容易做到安全可靠的
然后在PostgreSQL服务器和Apache实例之间放置一个PgBouncer。将其设置为事务池模式。它将很高兴地多路复用您的连接,并且它将负责在用户之间切换连接时调用DISCARD ALL
我认为您仍然可以对通过PgBouncer建立的连接使用设置会话授权 如果可以的话,我推荐一种稍微不同的方法
在Apache中保持简单。使用每个用户的私有会话,如果这是最容易做到安全可靠的
然后在PostgreSQL服务器和Apache实例之间放置一个PgBouncer。将其设置为事务池模式。它将很高兴地多路复用您的连接,并且它将负责在用户之间切换连接时调用DISCARD ALL
我认为您仍然可以对通过PgBouncer建立的连接使用设置会话授权 如果可以的话,我推荐一种稍微不同的方法
在Apache中保持简单。使用每个用户的私有会话,如果这是最容易做到安全可靠的
然后在PostgreSQL服务器和Apache实例之间放置一个PgBouncer。将其设置为事务池模式。它将很高兴地多路复用您的连接,并且它将负责在用户之间切换连接时调用DISCARD ALL
我认为您仍然可以对通过PgBouncer建立的连接使用设置会话授权 如果可以的话,我推荐一种稍微不同的方法
在Apache中保持简单。使用每个用户的私有会话,如果这是最容易做到安全可靠的
然后在PostgreSQL服务器和Apache实例之间放置一个PgBouncer。将其设置为事务池模式。它将很高兴地多路复用您的连接,并且它将负责在用户之间切换连接时调用DISCARD ALL
我认为您仍然可以对通过PgBouncer建立的连接使用设置会话授权 看起来很安全。要“验证”,您可以创建如下人工比赛条件:
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";
}
使用Apache2::RequestUtil;
使用Apache2::RequestRec;
my$r=Apache2::RequestUtil->request;
$r->headers\u out->add('Cache-control'=>“必须重新验证,没有缓存,没有存储”);
需要Apache2::请求;
my$req=Apache2::Request->new($r);
$r->content_type(“text/html”);
我的$login\u role\u name=$req->param('u');
$r->打印($u);
$r->打印('
'.$$);
使用DBI;
my$dbh=DBI->connect_cached(“DBI:Pg:dbname=…,{RaiseError=>1,AutoCommit=>1});
$dbh->do(“设置会话授权?;”,未定义,$login\u role\u name);
{
使用非致命警告=>“全部”;
my$rows=$dbh->selectall_arrayref('selectpg_backend_pid(),current_user::text');
警告“pg${$$rows[0]}[0]mp$$auth:${$$rows[0]}[1]原始auth:$login\u role\u name”;
睡眠10;
$rows=$dbh->selectall\u arrayref('select p