在PHP中逃避Python字符串的最佳方法是什么?

时间:2008-10-13 05:20:57

标签: php python user-input

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

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编写)之间的集成。我无法修改后者的安装,所以我需要想出一种方法来用它的语言来管理它的配置。

这也是真的坏主意。

5 个答案:

答案 0 :(得分: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源代码作为数据交换格式的另一个例子。

答案 1 :(得分:0)

我首先标准化我在python中使用的字符串类型,使用三引号字符串(“”“)。这应该减少输入中杂散引号引起的问题。你仍然需要当然要逃避它,但它应该减少一些问题的数量。

我为逃避弦乐而做的事情在某种程度上取决于我担心的内容,以及他们再次打印出来的背景。如果你只是担心引起问题的引用,你可以简单地检查和发生“”“并逃避它们。另一方面,如果我担心输入本身是恶意的(并且它是用户输入,所以你可能应该),然后我会看看像strip_tags()或其他类似函数的选项。

答案 2 :(得分:0)

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

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

Python有一个用于编码和解码JSON的包:python-json 3.4

答案 3 :(得分: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;
    }
}

答案 4 :(得分:-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;
}

我假设对于单引号字符串,你想要转义单引号,并且使用双引号字符串,你想要转义双引号......