转义,是个程序员应该都知道。 就是能让用户输入的字符安全使用的一种处理措施。最常见的需要转义的地方有两种:输出到浏览器、写入到数据库。
所谓有因有果,就是当你要输出内容给用户的浏览器的时候,用户要求你确保他不会受到xss攻击这是因,所以你就转义你的输出为果。所谓有因有果,就是当你写数据到数据库中时,数据库要求你转义确保不会导致注入这是因,所以你才转义了数据这为果。
怎么转义用户的输入输出到浏览器才安全呢?那么,你需要了解HTML、PHP与HTML的关系(真的有好多人不知道,当然是菜鸟级别的人)。HTML是一种客户端标记语言。PHP是一种服务器端脚本语言。PHP负责处理文本(HTML)输出到客户端的浏览器中。而如何安全的显示HTML就是PHP要做的。在处理文本的时候,确保HTML是准确的,无误的。而HTML如果想准确无误的显示用户的输入,就必须针对用户输入的内容进行HTML转义。HTML的敏感词列表:<>‘&”(小于号,大于号,单引号,与操作符,双引号)。转义了这些,那么你的输出便可安全显示了。当然,这只是针对非富文本,如果说我的编辑器是富文本编辑器呢?那该怎么办呢?我尝试使用黑名单方式过滤但总有新的xss出现,该怎么防御呢?答案就是采用白名单方式过滤(参考这篇)。可完美解决富文本问题。
再说说怎么转义用户的输入插入到数据库中的问题。很多人,在插入数据库的时候进行HTML转义,认为这是正确的做法。因为在显示的时候就可以直接显示了。认为数据库中的数据应该是安全的,可被信任的。殊不知,这种做法大错特错了。当我们在自己的产品中处理数据输出给用户的时候,我们会对数据库中的数据直接放行,对用户从浏览器提交过来的数据进行转义回显给用户。这可以说没什么问题,除了数据转义处理时机不统一外,没啥不好之处。再考虑,当我们的产品数据供其他产品调用的情况。我们把数据库中的数据直接提供给其他产品,因为这是我们信任的数据,告知他们,也应该信任。结果,对方就直接接收了数据,直接显示给了用户。设想,我们的产品某天被大牛xss了,然后,其他产品可想而知。可见,所有的外部数据都应该是不被信任的。所以,产品(就算是同一个公司,就算是同一个团队做的两个产品)之间的数据传递应该是原始数据。这样,对方就可以在正确的时机做正确的转义,而不用担心数据被乱转义的问题。怎么转义插入到数据库中的数据呢?这针对不同的数据库可能处理的方式也不同。拿最常见的mysql来说,使用最原始的mysql_函数的话,需要拼接SQL字符串。注入就发生在这里。PHP拼接好的SQL发送给MYSQL,MYSQL处理此SQL。拼接步骤如果不转义,就会产生注入漏洞。SQL中的敏感词有(null,回车,换行,反斜杠,单引号,双引号,SUB)。可以通过一段小程序测试一下:
<?php for ($i=0; $i < 256; $i++) { if (chr($i) !== mysql_escape_string(chr($i))) { echo $i,'"',chr($i),'" => ', mysql_escape_string(chr($i)), PHP_EOL;//实际入库不要使用此函数 } }
需要注意的是,MYSQL有字符集的概念,它在处理SQL字符串的时候,会根据你设定的字符集处理。这就存在宽字符被当作两个字符处理的问题。所以,要正确设置字符集。提交的SQL字符串编码与MYSQL连接编码要保持一致。使用MYSQL的转义函数也要为mysql_real_escape_string并同时指定字符集。
如果你真的懂了转义是什么意思,那么你就应该知道应该在什么时候转义你的代码了。
附图一张: