Perl - DBI 和 .pgpass

7

我可以使用以下方法成功地创建到Postgres数据库的连接:

my $settings = {
    host => 'myhost',
    db => 'mydb',
    user => 'myuser',
    passwd => 'mypasswd'
};

my $connection = DBI->connect(
    'DBI:Pg:dbname=' . $settings->{'db'} . ';host=' . $settings->{'host'},
    $settings->{'user'},
    $settings->{'passwd'},
    {
        RaiseError => 1,
        ShowErrorStatement => 0,
        AutoCommit => 0
    }
) or die DBI->errstr;

然而,我的Perl模块中暴露了有价值的登录凭据(是的,我已经更改了它们)。目前,我使用psql进行交互式查询。为了节省记住用户名/密码的麻烦,我将凭据放在了一个文件(~/.pgpass)中,并设置了600的权限。文件看起来像这样:

# host:port:database:user:passwd
myhost:5432:mydb:myuser:mypasswd

如何安全地使用此文件("$ENV{HOME}/.pgpass")以及DBI模块来隐藏我的凭据?这可行吗?最佳实践是什么?

3个回答

12

是的!有更好的方法。

轻松切换测试和生产服务器。

  • 将密码保存在~/.pgpass中(用于psqlpg_dump
  • 其他配置信息保存在~/.pg_service.conf(或/etc/pg_service.conf)中

例如:

#!/usr/bin/perl -T
use strict;
use warnings;
use DBI;

my $dbh = DBI->connect
(
    #"dbi:Pg:service=live",
    "dbi:Pg:service=test",
    undef,
    undef,
    {
        AutoCommit => 0,
        RaiseError => 1,
        PrintError => 0
    }
) or die DBI->errstr;

~/.pg_service.conf:

# http://www.postgresql.org/docs/9.2/static/libpq-pgservice.html
# /usr/local/share/postgresql/pg_service.conf.sample
# http://search.cpan.org/dist/DBD-Pg/Pg.pm
#

[test]
dbname=hotapp_test
user=hotusr_test
# localhost, no TCP nonsense needed:
host=/tmp

[live]
dbname=hotapp_live
user=hotusr_live
host=pgsql-server.example.org

~/.pgpass:

# http://www.postgresql.org/docs/9.2/static/libpq-pgpass.html
# hostname:port:database:username:password
localhost:5432:hotapp_test:hotusr_test:kq[O2Px7=g1
pgsql-server.example.org:5432:hotapp_live:hotusr_live:Unm£a7D(H

甚至可以通过 shell 环境变量 export PGSERVICE=test 连接到 my $dbh = DBI->connect("dbi:Pg:", undef, undef); - Craig R. Skinner
很棒的答案。我一直期待着有更好的方法来执行连接,而不是将大量的连接信息硬编码到perl中。我已经创建了一个包含相关字段的~/.pg_service.conf文件,但是我收到了错误消息:ERROR: service file "/etc/sysconfig/pgsql/pg_service.conf" not found。有没有办法强制连接查看~/.pg_service.conf呢? - Steve
实际上,我自己找到了答案。我所需要做的就是设置:$ENV{'PGSYSCONFDIR'}。谢谢! - Steve

2
  1. 根据上面的问题,在名为~/.pgpass的文件中放置您的登录凭证。

  2. 要打开连接,您需要在主机、数据库和用户名中进行硬编码。但这没关系,因为至少您不需要在密码字段中编码。此字段保持隐藏在您的~/.pgpass文件中。

  3. 确保将连接实例的密码字段设置为undef

以下是对我有效的内容:

my $settings = {
    host => 'myhost',
    db => 'mydb',
    user => 'myuser'
};

my $connection = DBI->connect(
    'DBI:Pg:dbname=' . $settings->{'db'} . ';host=' . $settings->{'host'},
    $settings->{'user'},
    undef,
    {
        RaiseError => 1,
        ShowErrorStatement => 0,
        AutoCommit => 0
    }
) or die DBI->errstr;

连接成功建立是因为某种原因,至少对我来说是未知的,实例在尝试连接时会搜索~/.pgpass文件。我知道这个文件有一些神奇的地方,只是不确定该怎么处理它。文档链接:http://search.cpan.org/dist/DBI/DBI.pm#data_string_diff。请注意,该页面上搜索“pgpass”并没有返回结果。我拒绝阅读所有内容,也许有一天会读完。

1
~/.pgpasslibpq 的一个特性,它是 postgres C 客户端库。DBI 建立在 libpq 之上,因此它只是继承了它的特性。这就是为什么它可以与 DBI 一起使用,也是为什么在 DBI 文档中没有提到它的原因。 - Daniel Vérité
2
这是针对PostgreSQL的,因此不应在DBI的文档中提及。另一方面,在DBD::Pg中应该提到它,尽管实际上并没有。然而,后者确实提到了环境变量和不同的配置文件格式! - ikegami

1
open(my $fh, '<', "$ENV{HOME}/.pgpass") or die $!;

my $settings;
while (<>) {
   chomp;
   next if /^\s*(?:#.*)?\z/s;
   @{$settings}{qw( host port database user passwd )} = split /:/;
}

die "No settings" if !$settings;

任何能够运行该脚本的用户仍然可以看到凭据。

是的,但肯定有更好的方法吧?我开始觉得可能没有了。 - Steve
将凭证简单地传递给 $connection 实例,而无需声明它们或打开文件。 - Steve
这毫无意义。将参数传递到函数与您提到的两件事情没有任何关系。因此,我再次问,更好的方式是做什么,确切地?随后的问题显然会是,按什么标准更好? - ikegami
非常抱歉我之前的解释不够清晰。但是,我们最后的评论帮助找到了解决方案。如果您对解决方案感兴趣,请查看我的答案。再次感谢您的帮助。 - Steve
抱歉,ikegami,希望你不介意,但我认为Craig的回答最安全,而且得分最少。再次感谢。 - Steve
1
虽然这个答案避免了硬编码密码,将其作为命令行参数或环境变量发送是一个实现方式的例子,如果您使用非libpq PostgreSQL连接,则与使用来自libpq的.pgpass文件一样安全,但它重新发明了轮子,因为DBD::Pg基于libpq。让libpq处理它的.pgpass似乎是DBD::Pg更好的做法。 - jla

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接