【问题标题】:What is the risk of whitelisting IP addresses in PHP scripts used for Cronjobs before running them在运行 Cronjobs 之前将用于 Cronjobs 的 PHP 脚本中的 IP 地址列入白名单的风险是什么
【发布时间】:2020-05-08 14:31:00
【问题描述】:

我的服务器上有一些 PHP 脚本,用于定期 cron 作业(例如,用于日常交流和更新排行榜)。

为了防止外人手动运行这些脚本(例如通过在浏览器中运行http://url/script.php),我包含以下代码以在运行实际脚本之前检查 IP 地址。其中XX.XX.XX.XX代表我自己网络的IP地址。

    $remote = isset($_SERVER["REMOTE_ADDR"]) ? $_SERVER["REMOTE_ADDR"] : '127.0.0.1';
    $whitelist = array('XX.XX.XX.XX', '127.0.0.1');

    if (!in_array($remote, $whitelist))
    {
        exit;
    } 

所以现在我有以下问题:

  • 这有多安全?
  • 有什么风险?
  • 我怎样才能使它更安全?
  • 还有其他(更好的)解决方案吗?

附言。我之前的问题已关闭,因为有人认为这个问题与PHP IP Address Whitelist with Wildcards 重复。但我不是这样的!这个问题是关于在白名单中使用通配符,而这个问题是关于此解决方案的安全性和风险。

【问题讨论】:

  • 你为什么要把php文件放在公共空间? cron 制作的文件更是如此。在服务器崩溃的情况下,它们可以显示为 txt。如果 IP 是共享的,您的安全性就会很弱。
  • 这两个问题都与服务器类型无关。 PHP 用作预处理器,这意味着如果 www 服务器网关不起作用,则 php 页面以 mime-type html/txt 发送。 (例如,您丢失了 MySQL 密码)。在 public_html 中应该只有一个指向应用程序主文件的符号链接,或者如果您不能放置符号链接脚本,其中包含来自 public_html 外部的应用程序文件和静态文件。然后,如果发生故障,则不会披露或披露不相关的信息。
  • 是的。 Cron 脚本运行 php-cli,因此它们没有理由拥有公共访问权限。所有活动文件都应该在公共目录之外。尤其是带有密码等的 .inc 文件。
  • 既然脚本不能通过www访问,为什么还要检查其中的IP地址呢?在不了解所有细节的情况下很难谈论应用程序设计。我宁愿使用 iptables 或 htaccess 或 htpasswd 来管理对敏感数据的访问。
  • 谢谢。我写了答案。

标签: php server cron


【解决方案1】:

所提出的方法并不完全安全。

PHP 充当文本预处理器,这意味着在 Web 服务器网关错误的情况下,可以使用 mime 类型的 text/html 发送脚本内容,这存在泄露敏感数据的风险,例如作为 SQL 数据库或 (s)ftp 帐户的密码。

如果脚本中控制的 IP 地址是共享(或动态传输)地址,则公开发布的管理脚本也存在未经授权执行的风险。 Cron 脚本是使用 php-cli 执行的,因此任何事情都不需要 Web 服务器网关,如果脚本在公共目录之外,则不需要在脚本中进行 IP 分析。

使用例如远程执行curl 可能是将管理脚本放置在 www 服务器的公共空间中的唯一原因。这通常是一个弱解决方案,因为脚本会使用其他设置执行 php 解释器(而不是 php-cli),通常执行时间非常有限。但是,如果出于某种原因有必要,它应该位于单独的目录中,使用 .htaccess(和/或 .iptables)将访问限制为特定 IP 地址,并使用 htpasswd(基本身份验证)分配用户名和密码。

理想的情况是www服务器的public目录(以下简称public)只包含静态内容(img、css、js...文件)和位于父目录的应用触发器。 示例结构为:

/home/username/domainname/(apps,crons,public,tmp)

apps 目录应包含所有应用程序文件和目录。公共目录应仅包含静态内容(用于某些子目录中的订单)和指向应用程序主文件的符号链接,可以使用以下命令获取:

ln -s ../apps/app.php index.php

某些服务器配置不允许使用符号链接。然后你可以使用 index.php 文件包含:

<?php
include('/home/username/domainname/apps/app.php');

这个解决方案有点糟糕,因为在网关发生故障的情况下,目录结构会暴露出来。但是,敏感数据仍然是安全的,因为 Web 服务器无法显示不存在的文件的内容。

假设 php 文件本身位于公共 Web 服务器之外,所呈现的 IP 分析可用于显示授权地址的部分内容。但是,如果这些是整个网站,我更愿意使用 iptables 或 .htaccess 来管理对它们的访问。

【讨论】:

  • 感谢您的明确答复!您不仅让我清楚地了解了资源的存储位置,而且还为我希望某些用户可以访问的应用程序部分提供了更好的解决方案(通过使用 .htacces 和/或 htpasswd)。
  • 很高兴听到。祝您实施顺利。
【解决方案2】:

这有多安全?

实际上,只要您可以控制地址(127.0.0.1 可以,XXX.XXX.XXX.XXX 可能不行),它就非常安全。 相当安全我的意思是有人可能滥用这个系统的可能性很小并且没有更大的机会滥用网络应用程序的其余部分

有什么风险?

如果有人以某种方式假设 IP 地址 XXX.XXX.XXX.XXX,或者欺骗系统相信他们有,那么他们可能会从外部调用您的脚本。

我怎样才能使它更安全?

您可以在原始调用中包含一个 secret,并对照同一 secret 的 hash 检查它。即使有人能看懂剧本,也不会泄露秘密。

if (!array_key_exists('key', $_GET)) {
    die('Access denied');
}
if (sha1($_GET['key']) !== '713dca7cf928f23a2347cae828d98879629e1e80') {
    die('Access denied');
}

您还可以将脚本置于网络根目录之外,并通过require 语句调用它。这样,要么 PHP 子系统工作,脚本无法读取,要么它不工作,显示的只是一个不可访问目录的名称。您甚至可以合并这两种方法:

if (sha1($_GET['key']) !== '713dca7cf928f23a2347cae828d98879629e1e80') {
    die('Access denied');
}
$realScript = $_GET['key'];
require $realScript;

现在,可以包含的唯一脚本是其名称具有特定 SHA1 哈希值的脚本,没有其他脚本(冲突的风险实际上可以忽略不计:您需要与有效的文件名,以及创建这样一个文件名的方法)。所以您知道脚本是有效的,但除非在调用中提供名称,否则整个构造将无法工作,甚至不会告诉攻击者为什么

curl http://yoursite.internal.address/cron/cron.php?key=../scripts7ab9ceef/mycron.php

还有其他(更好的)解决方案吗?

是和不是。使用命令行界面调用脚本同样安全,并且不需要工作的网络服务器。如果需要,它还允许以不同的用户身份运行。

另一方面,它需要安装命令行界面,这可能会产生其他安全问题,即使使用相同的用户和主目录,这两个界面的行为仍可能略有不同(或者不是这样)巧妙地:你可能有一个 PHP7.3 web 模块和一个 PHP5.2 CLI 安装,反之亦然,这将使脚本具有短数组语法(或像 if(empty(some_function($_GET['x'])) 这样的结构)甚至没有加载在一个或另一个界面中。

总而言之,对 curllynx 的 crontab 调用可能更易于维护和使用,即使它无疑效率较低。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-01
    • 2012-10-07
    • 1970-01-01
    • 2018-11-01
    • 2012-10-29
    相关资源
    最近更新 更多