我从全新安装的 OpenBSD 6.0 开始,该服务器在其 httpd 服务器(不是 Apache)上有一个 chroot(/var/www)。我安装了 PHP 7.0,并使用二进制安装设置了 php-fpm。在 Web 根目录中存在 sendmail 和 femail 对象。我将网站移到位,php 运行良好,php 查询 postgresql 数据库(也是从二进制文件安装的),一切都运行良好 - 除了 mail()。
我在 /var/www/logs/php.mail.log 中设置了一个日志文件,它显示邮件被 php 识别,日志条目如下:
[09-Dec-2016 15:04:34 UTC] mail() on [/do_quick_mail_test.php:23]: To: [email protected] -- Headers: From: [email protected] (domain.com Robot)
/var/www/logs/error.log 和系统消息中没有发生任何错误。
系统邮件日志中没有电子邮件迹象。
当我从命令行运行该命令时,它可以正常工作并且邮件可以正常传送,没有任何问题:
echo 'Subject: test' | chroot /var/www /usr/sbin/sendmail -v [email protected]
我使用浏览器访问的 php 程序非常简单:
<?php
session_start();
header( "Content-Type: text/plain" );
echo( 'Configuration Tests:'."\n" );
echo('Testing DNS:'."\n" );
print_r( dns_get_record("trialtoaster.com") );
echo( 'localhost lookup: '.gethostbyname( "localhost" )."\n" );
echo('Testing DateTime:'."\n" );
print_r( getdate() );
echo('Sending test email:'."\n" );
if ( mail("[email protected]", "PHP Test mail", "PHP email - test message.", "From: [email protected] (domain.com Robot)") ) {
echo '- PHP thinks the email went normally.';
} else {
echo '- PHP thinks the email failed.';
}
?>
除了 mail() 终止之外,程序没有产生任何故障。DNS 测试返回所有记录(包括 MX 记录),并且日期准确。尽管在 php 邮件日志中记录正确。
显示时,phpinfo() 正确反映了配置:
sendmail_path: /usr/sbin/sendmail -t
SMTP: localhost
smtp_port: 25
当我检查数据包过滤器时,它允许 lo0 上的任何东西去任何地方,当我运行命令时,我可以在 pftop 上看到它,但是当我从浏览器运行 mail() 时什么也没有显示。
我已经在与 chrooted sendmail 相同的目录中安装了 sendmail.ini,但这没有任何区别。
OpenBSD chrooted httpd 安装似乎不完整,因为为了使用 php mail() 命令,有些东西完全缺失了,我担心这可能是 bash shell 和库的问题,因为从命令行发送邮件没问题。这对我来说似乎不合常理,因为 chroot 的目的是为了监禁黑客,而将 bash shell 和库提供给被监禁的系统似乎会为攻击提供很大的空间。
我只是觉得这不可能是问题所在,因为否则的话,你还不如放弃 chroot 并在没有 jail 的情况下运行它(看起来是这样)。
是否有人看到我遗漏了什么 - 如果没有,并且我复制了 shell 和库,那么最安全的方法是什么,以最少的暴露和不编写可能被攻击者重新包装的自定义包装器来做到这一点?
答案1
我相信可以通过以下两种方式之一解决这个问题:
(1) 您可以通过在 chroot 中安装可执行 shell 来解决这个问题,这样 sendmail 二进制文件就可以运行了。如果这样做,即使您将其安装在包装器中,也增加了攻击面,您可能还不如放弃 chroot。包装器可以重新包装,您只需执行重新启动,系统就会被破解。我建议不要这样做。
(2) 最好的选择是放弃邮件,直接通过套接字使用 SMTP - 这与 PHP 和 Web 服务器本身已经运行的方式非常相似。chroot 上没有 shell,您所做的只是安装更多 php 代码,并让该代码在本地主机上打开套接字到端口 25,您的 MTA 已经在该端口上监听并传递到外部世界,但不执行任何任意代码。
工作原理如下:
如果尚未安装 Pear,请安装它,然后安装邮件脚本。您可以像这样轻松完成此操作:
pkg_add install Pear
pear install Mail_smtp
pear install Net_SMTP
根据您的系统 - 第一个 pear install 可能会将第二个 pear install 作为依赖项为您执行。
从那里我在其自己的 php 程序中添加了一个 php 函数:
<?php
/**
* Sends an email using SMTP directly rather than using the sendmail binary (which requires
* a shell environment to run). This allows the chrooted server to run with less exposure.
*/
require_once "Mail.php";
function SMTP_mail($recipients, $subjectHeader, $message, $fromHeader)
{
$headers['From'] = $fromHeader;
$headers['Subject'] = $subjectHeader;
$smtpinfo["host"] = "localhost";
$smtpinfo["port"] = "25";
$smtpinfo["auth"] = false;
// Create the mail object using the Mail::factory method
$mail_object = Mail::factory("smtp", $smtpinfo);
$mail_object->send($recipients, $headers, $message);
}
剩下要做的就是检查我正在迁移的代码,并将邮件说明转换为使用此功能:
SMTP_mail($sendToEmailAddr, $subjectLine, $messageBody, 'From: [email protected] (Domain.com Robot)');
如果您还没有这样做,那么在 chroot 之外发送邮件的功能应该已经起作用了。这里对我们来说重要的是 /etc/mail/smtp.conf 文件中的内容:
listen on lo0
# Since we are only listening on the lo0 (local) we can safely use
# commands that are "accept from any" or bare "accept" commands.
# accept from any for domain "example.org" alias <aliases> deliver to mbox
accept for local alias <aliases> deliver to mbox
# accept from the lo0 (local) interface anything and relay it out
accept for any relay
# This was the original command - use it if you ever open up
# the external interface by doing a "listen on any" rather than
# the above command - that will keep us from being an open relay:
#accept from local for any relay
重新启动后它应该就可以正常工作了 - 假设您有与我的问题中相同的设置。PHP 将通过 chroot 中的本地主机打开到 chroot 之外的本地主机的 SMTP 连接,发送您编程发送的电子邮件,然后关闭连接。OpenBSD 的 mailer.conf 将确保“真正的”sendmail (smtpctl) 收到它并根据该电子邮件地址的邮件主机 DNS 中的 MX 条目将其路由到外部世界。您需要通过在 /etc/rc.conf.local 系统文件中设置 smtpd_flags 来确保 SMTP 正在运行。
全部由恶魔运行,并且和你的程序代码一样安全。希望这能有所帮助!