一般来说,我会用之类的东西去掉所有非英语字符
$file = filter_var($file, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH );
然而,我厌倦了不支持来自其他语言的用户输入,这些语言可能是上传文件(文件名可能是西里尔文、中文或阿拉伯语等)或表单字段,甚至是所见即所得的内容。
与此相关的清除数据的示例有两种形式之一
- 那些去掉所有非英语字符的字符
- 那些将所有非英语字符转换为英语字母替代品的字符
这种做法的问题是,你最终会得到一个破碎的框架,它假装支持多种语言,但实际上除了用他们的语言向他们显示标签或内容之外。
有许多攻击利用了unicode/utf-8/utf-16/etc对传递空字节等的支持,因此很明显,不清除数据不是一种选择。
是否有任何方法可以在维护这些其他语言的完整字母表/字符的同时,从任意命令中清除变量,但(以通用的方式)去除所有可能的不可打印字符、作为字符一部分的带有null的字符以及其他此类漏洞,同时保持用户输入的实际字符的完整性?上面的命令是完美的,可以完全按照它应该做的来做任何事情,但是如果有一种方法可以扩展它以支持所有语言,那将是非常酷的。
Null字节不是(!)UTF-8,所以假设您在内部使用UTF-8,您所需要做的就是验证传递的变量是UTF-8。例如,不需要支持UTF-16,因为您作为API或表单的作者定义了正确的编码,并且您可以将自己限制为UTF-8。此外,"unicode"也不是您需要支持的编码,因为它不是一种编码。相反,Unicode是一种标准,UTF编码是其中的一部分
现在,回到PHP,您要查找的函数是mb_check_encoding()。错误处理很简单,如果任何参数都没有通过测试,您将以"坏请求"响应进行回复。无需尝试猜测用户可能想要什么。
虽然这个问题并没有特别提出这个问题,但这里有一些例子以及应该如何处理输入:
- 非UTF-8字节:以400拒绝("错误请求")
- 包含路径元素的字符串(如
../
):Accept - filename(不是文件路径)包含路径元素(如
../
):用400拒绝 - 文件名
شعار.jpg
、标志.png
或логотип.png
:接受 - filename
foo <0> bar.jpg
:接受 - number
abc
:以400拒绝 - number
1234
:接受
以下是如何针对不同的输出处理它们:
- 非UTF-8字节:不可能,它们以前被拒绝过
- filename包含路径元素:不可能发生,它们以前被拒绝过
- HTML中的文件名
شعار.jpg
、标志.png
或логотип.png
:如果HTML编码为UTF-8,则逐字使用,使用默认ISO8859-1时替换为HTML实体 - Bash中的文件名
شعار.jpg
、标志.png
或логотип.png
:逐字使用,假设文件系统的编码为UTF-8 - SQL中的文件名
شعار.jpg
、标志.png
或логотип.png
:可能只是引号,取决于驱动程序、数据库、表等。请参阅手册 - HTML中的文件名
foo <0> bar.jpg
:转义为"foo<0>bar.jpeg"。可能使用" "作为空格 - Bash中的filename
foo <0> bar.jpg
:引号或带反斜杠的转义符"、"<"answers">" - SQL中的filename
foo <0> bar.jpg
:仅引用一句 - 数字
abc
:不可能,他们以前被拒绝过 - HTML中的数字
1234
:逐字使用 - Bash中的数字
1234
:逐字使用(不确定) - SQL中的数字
1234
:逐字使用
一般程序应为:
- 定义您的内部类型(字符串、文件名、数字),并拒绝任何不匹配的内容。这些类型创建约束(文件名不包括路径元素)并提供保证(文件名可以附加到目录中以在该目录中形成文件名)
- 使用HTML的模板库(脑海中浮现出"胡子")
- 为SQL使用DB包装库(PDO、Propel、Doctrine)
- 转义shell参数。我不知道该走哪条路,但我相信你会找到合适的路的
逃跑不是一个明确的程序,而是一系列程序。实际使用的转义算法取决于目标上下文。除了你写的("逃避也会把名字搞砸"),实际情况应该相反!基本上,它确保在XML中包含小于号的字符串保持为包含小于号,并且不会变成格式错误的XML片段。为了实现这一点,转义转换字符串,以防止任何通常不被解释为文本的字符得到正常的解释,比如shell中的空格字符。