在PHP中转义Python字符串的最佳方法是什么?
我有一个用PHP写的应用程序,它需要输出一个Python脚本,具体来说,就是一堆变量赋值的语句,比如:
subject_prefix = 'This String From User Input'
msg_footer = """This one too."""
这些变量的内容需要根据用户输入来写,所以我需要对字符串的内容进行转义。像下面这样写是行不通的;一旦有人使用了引号、换行符或者其他我不知道的可能会出问题的字符,我们就麻烦了:
echo "subject_prefix = '".$subject_prefix."'\n";
那么,有什么好主意吗?
(因为时间有限,重写成Python是不可能的。:P )
编辑,几年后:
这是为了一个用PHP写的网页应用和一个用Python写的Mailman之间的集成。我不能修改后者的安装,所以我需要想办法用它的语言来管理它的配置。
这也是一个非常糟糕的主意。
5 个回答
我会先把在Python中使用的字符串类型标准化,改成三重引号字符串(""")。这样可以减少输入中出现多余引号的问题。当然,你还是需要对引号进行转义,但这样可以减少很多麻烦。
我用来转义字符串的方法会根据我担心的内容和它们被打印出来的上下文而有所不同。如果你只是担心引号会引起问题,可以简单地检查一下是否有""",然后对它们进行转义。另一方面,如果我担心输入本身可能有恶意内容(而且这是用户输入,所以你可能应该担心),那么我会考虑使用像strip_tags()这样的函数或者其他类似的选项。
另一个选择是把数据导出为数组或对象的JSON字符串,然后稍微修改一下Python代码来处理这种新输入。虽然通过JSON进行转义并不是百分之百安全,但总的来说比自己写的转义方法要好。
这样一来,如果JSON字符串格式不正确,你也能处理错误。
Python有一个包可以用来编码和解码JSON:python-json 3.4
不要尝试在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源代码当作数据交换格式。