2

我有一个 PHP 应用程序需要输出一个 python 脚本,更具体地说是一堆变量赋值语句,例如。

subject_prefix = 'This String From User Input'
msg_footer = """This one too."""

需要编写subject_prefix等内容以接受用户输入;因此,我需要转义字符串的内容。编写如下内容不会减少它;一旦有人使用引号或换行符或我不知道可能有危险的任何其他内容,我们就会被塞满:

echo "subject_prefix = '".$subject_prefix."'\n";

所以。有任何想法吗?

(由于时间限制,无法用 Python 重写应用程序。:P)

多年后编辑:

这是为了在 web 应用程序(用 PHP 编写)和 Mailman(用 Python 编写)之间进行集成。我无法修改后者的安装,所以我需要想出一种方法来用它的语言来管理它的配置。

这也是一个非常糟糕的主意。

4

5 回答 5

2

不要尝试在 PHP 中编写此函数。您将不可避免地出错,您的应用程序将不可避免地具有任意远程执行漏洞。

首先,考虑您实际解决的是什么问题。我想你只是想从 PHP 到 Python 获取数据。您可能会尝试编写 .ini 文件而不是 .py 文件。Python 有一个出色的 ini 语法解析器ConfigParser。您可以在 PHP 中编写明显且可能不正确的引用函数,如果(阅读:何时)您弄错了,不会发生任何严重的事情。

您还可以编写一个 XML 文件。PHP 和 Python 的 XML 解析器和发射器太多了,我什至无法在此处列出。

如果我真的不能让你相信这是一个糟糕的、糟糕的想法,那么你至少可以使用 Python 已有的功能来做这样的事情:repr().

这是一个方便的 PHP 函数,它将运行 Python 脚本为您执行此操作:

<?php

function py_escape($input) {
    $descriptorspec = array(
        0 => array("pipe", "r"),
        1 => array("pipe", "w")
        );
    $process = proc_open(
        "python -c 'import sys; sys.stdout.write(repr(sys.stdin.read()))'",
        $descriptorspec, $pipes);
    fwrite($pipes[0], $input);
    fclose($pipes[0]);
    $chunk_size = 8192;
    $escaped = fread($pipes[1], $chunk_size);
    if (strlen($escaped) == $chunk_size) {
        // This is important for security.
        die("That string's too big.\n");
    }
    proc_close($process);
    return $escaped;
}

// Example usage:
$x = "string \rfull \nof\t crappy stuff";
print py_escape($x);

chunk_size检查旨在防止攻击导致您的输入最终成为两个非常长的字符串,它们分别看起来像("hello " + ("." * chunk_size))'; os.system("do bad stuff")。现在,这种天真的攻击不会完全起作用,因为 Python 不会让单引号字符串在行的中间结束,并且system()调用中的那些引号本身也会被引用,但是如果攻击者设法得到一行延续(“\”)到正确的位置并使用类似的东西,os.system(map(chr, ...))然后他们可以注入一些将运行的代码。

我选择简单地读取一个块,如果有更多的输出就放弃,而不是继续读取和累积,因为 Python 源文件行长度也有限制;据我所知,这可能是另一个攻击媒介。Python 并非旨在防止任意人在您的系统上编写任意源代码,因此该领域不太可能被审计。

我不得不为这个简单的例子考虑所有这些,这只是另一个例子,说明为什么不应该使用 python 源代码作为数据交换格式。

于 2008-10-14T07:58:38.000 回答
0

我将从标准化我在 python 中使用的字符串类型开始,以使用三引号字符串 (""")。这应该可以减少输入中的杂散引号引起的问题事件。您仍然需要将其转义为当然,但它应该减少令人担忧的问题的数量。

我为逃避字符串所做的工作在一定程度上取决于我担心被滑入的内容,以及它们再次被打印出来的上下文。如果你只是担心引起问题的引号,你可以简单地检查和出现“””并转义它们。另一方面,如果我担心输入本身是恶意的(而且它是用户输入,所以你可能应该),然后我会查看诸如 strip_tags() 或其他类似函数之类的选项。

于 2008-10-13T05:34:47.090 回答
0

另一种选择可能是将数据导出为数组或对象为 JSON 字符串,并稍微修改 python 代码以处理新输入。虽然通过 JSON 转义不是 100% 防弹的,但它仍然比自己的转义例程更好。

如果 JSON 字符串格式错误,您将能够处理错误。

有一个 Python 包可以对 JSON 进行编码和解码:python-json 3.4

于 2008-10-13T07:57:21.467 回答
0

我需要对此进行编码以转义“ntriples”格式的字符串,该格式使用python escaping

以下函数采用 utf-8 字符串并将其转义为 python(或 ntriples 格式)返回。如果给出非法的 utf-8 数据,它可能会做一些奇怪的事情。它不了解 xFFFF 之后的 Unicode 字符。它(当前)不将字符串用双引号括起来。

uniord 函数来自 php.net 上的评论。

function python_string_escape( $string ) {
    $string = preg_replace( "/\\\\/", "\\\\", $string ); # \\ (first to avoid string re-escaping)
    $string = preg_replace( "/\n/", "\\n", $string ); # \n
    $string = preg_replace( "/\r/", "\\r", $string ); # \r 
    $string = preg_replace( "/\t/", "\\t", $string ); # \t 
    $string = preg_replace( "/\"/", "\\\"", $string ); # \"
    $string = preg_replace( "/([\x{00}-\x{1F}]|[\x{7F}-\x{FFFF}])/ue",
                            "sprintf(\"\\u%04X\",uniord(\"$1\"))",
                            $string );
    return $string;
}

function uniord($c) {
    $h = ord($c{0});
    if ($h <= 0x7F) {
        return $h;
    } else if ($h < 0xC2) {
        return false;
    } else if ($h <= 0xDF) {
        return ($h & 0x1F) << 6 | (ord($c{1}) & 0x3F);
    } else if ($h <= 0xEF) {
        return ($h & 0x0F) << 12 | (ord($c{1}) & 0x3F) << 6 | (ord($c{2}) & 0x3F);
    } else if ($h <= 0xF4) {
        return ($h & 0x0F) << 18 | (ord($c{1}) & 0x3F) << 12 | (ord($c{2}) & 0x3F) << 6 | (ord($c{3}) & 0x3F);
    } else {
        return false;
    }
}
于 2009-11-28T18:47:35.033 回答
-2

我建议编写一个带有两个参数的函数:要转义的文本和字符串所在的引号类型。然后,例如,如果引号的类型是单引号,则该函数将转义字符串中的单引号以及任何其他需要转义的字符(反斜杠?)。

function escape_string($text, $type) {
    // Escape backslashes for all types of strings?
    $text = str_replace('\\', '\\\\', $text);

    switch($type) {
        case 'single':
            $text = str_replace("'", "\\'", $text);
            break;
        case 'double':
            $text = str_replace('"', '\\"', $text);
            break;
        // etc...
    }

    return $text;
}

我假设对于单引号字符串,您想要转义单引号,而对于双引号字符串,您想要转义双引号......

于 2008-10-13T05:30:00.610 回答