我已经为URL的安全性做了以下功能.我只是想知道我需要在下面的代码中重新考虑或改变.从各种来源阅读了一些关于安全性的文章后,我已经完成了这个功能.
这是功能:
// filters possible malacious stuff from URLs private function filter_url($url) { if (is_array($url)) { foreach($url as $key => $value) { // recurssion $url[$key] = filter_url($value); } return $url; } else { // Allow only one ? in URLs $total_question_marks = substr_count($url, '?'); if ($total_question_marks >= 2) { exit('You can not use 2 question marks (?) in URLs for security reasons!!'); } // decode URLs $url = rawurldecode($url); $url = urldecode($url); // remove bad stuff $url = str_replace('../', '', $url); $url = str_replace('..\\', '', $url); $url = str_replace('..%5C', '', $url); $url = str_replace('%00', '', $url); $url = str_ireplace('http', '', $url); $url = str_ireplace('https', '', $url); $url = str_ireplace('ftp', '', $url); $url = str_ireplace('smb', '', $url); $url = str_replace('://', '', $url); $url = str_replace(':\\\\', '', $url); $url = str_replace(array('<', '>'), array('<', '>'), $url); // Allow only a-zA-Z0-9_/.-?=& $url = preg_replace("/[^a-zA-Z0-9_\-\/\.\?=&]+/", "", $url); //print $url; return $url; } }
我可以像这样使用这个函数:
$_GET = filter_url($_GET);
或者甚至像这样:
$_SERVER['QUERY_STRING'] = filter_url($_SERVER['QUERY_STRING']);
Cheekysoft.. 5
尝试创建某种类似于此的全能过滤器的任何尝试都将失败,此外,由于您总是"破坏"数据,当您真正需要接受"已消除"的数据时,您将遇到麻烦"字符或字符序列.
您确实需要仔细阅读Web安全主题并充分了解常见攻击,例如(最少)跨站点脚本,跨站点请求伪造和SQL注入.
您需要采取双管齐下的方法以安全的方式使用用户提供的数据.这是为了
想想这样的过程:
在途中验证和拒绝数据.
在出路上编码数据
输入验证 检查每个输入以确保它只包含正确类型的数据并适合长度和范围边界 - 根据每个数据的含义 - - .即确保数字只包含数字.确保年份在合理的范围内,确保字符串不会过长或空白,确保文件名不会遍历目录,确保ID只包含合法字符.etc.etc.等等.这里最重要的是,尽可能说明允许的内容; 不要声明什么是丢弃的.测试允许的内容并拒绝其他所有内容称为白名单并且是一件好事,因为您知道您将获得干净的数据(或者尽可能接近它).寻找不良模式并拒绝它们被称为黑名单,这是一个不太安全的想法.要使黑名单成功,您需要确保黑名单完整,而且这通常是一项不可能完成的任务.在某些有限的环境中,黑名单方法可能是有用的,但只有当您尽可能确定时,该清单才是详尽无遗的.
存储数据 一旦只接受了干净的数据,请将其保存在变量或会话中.也许采用一种变量命名方法,表明这个数据现在是干净的.这里最重要的是,当我们保存这些数据时,我们还没有改变它.这意味着数据可以在任何上下文中使用,而不会让我们"扔掉任何东西"
输出编码 将数据发送到外部系统(例如文件名,cookie,网页,文件或保存在自己的数据库中)时,必须对数据进行编码,以确保不会破坏语言中使用的语言语法或文件格式.输出.在这里可以转换数据.
根据您使用数据的方式和位置,您需要对数据执行的转换将有所不同.转换用于windows文件名的字符串对于linux文件名是不同的,如果插入到PDF文档,网页或数据库等等,则会再次不同.但是,让我们更详细地看两个示例:
输出到HTML 在最常见的将字符串插入某些HTML的情况下,您需要确保不允许用户将任意内容注入页面,这不仅允许他们编辑其他用户可以看到的页面,但他们也可以以javascript的形式注入代码,可以做任何他们想做的事情.此脚本将以查看页面的用户身份运行,并可能允许攻击者窃取其信息和登录凭据.这称为跨站点脚本.HTML和Javascript的语法规则意味着您需要根据插入用户数据的HTML中的位置进行不同的编码.http://www.owasp.org/index.php/XSS_%28Cross_Site_Scripting%29_Prevention_Cheat_Sheet上有一个非常有价值的页面,它解释了如何转换6个不同类别的地方的数据,你可以在这些地方插入一个字符串到HTML页面.
输出到数据库 如果将用户数据保存到数据库,则实际上必须在SQL语句中包含该字符串.您必须确保不允许用户更改SQL语句的含义,并且只能更改数据值.如果它们可以更改语句的含义,则称为SQL注入.
这是一种特殊情况,因为虽然您可以使用输出编码来解决问题,但最好使用称为"绑定参数"的技术.这可确保您的数据始终用作数据,而不是与数据库通信时的代码.PHP支持许多db库中的绑定参数,包括"PDO"(跨数据库)和"Mysqli"(MySQL).应该注意,"Mysql"库不支持绑定参数.
整个网络和StackOverflow中有关于跨站点脚本(XSS)和SQL注入(SQLi)的更多信息,非常值得阅读这个主题.当然还有许多其他类型的攻击,但如果您按照上述过程进行操作,则应尽量减少风险.数据验证和编码例程构成安全Web应用程序的重要部分并非不合理.但是,您必须将安全方法纳入标准工作流程.将其作为事后补充添加起来要困难得多.有时候会回顾一下特定函数的验证代码,并考虑是否可以添加更多规则.总会有你第一次错过的东西.
尝试创建某种类似于此的全能过滤器的任何尝试都将失败,此外,由于您总是"破坏"数据,当您真正需要接受"已消除"的数据时,您将遇到麻烦"字符或字符序列.
您确实需要仔细阅读Web安全主题并充分了解常见攻击,例如(最少)跨站点脚本,跨站点请求伪造和SQL注入.
您需要采取双管齐下的方法以安全的方式使用用户提供的数据.这是为了
想想这样的过程:
在途中验证和拒绝数据.
在出路上编码数据
输入验证 检查每个输入以确保它只包含正确类型的数据并适合长度和范围边界 - 根据每个数据的含义 - - .即确保数字只包含数字.确保年份在合理的范围内,确保字符串不会过长或空白,确保文件名不会遍历目录,确保ID只包含合法字符.etc.etc.等等.这里最重要的是,尽可能说明允许的内容; 不要声明什么是丢弃的.测试允许的内容并拒绝其他所有内容称为白名单并且是一件好事,因为您知道您将获得干净的数据(或者尽可能接近它).寻找不良模式并拒绝它们被称为黑名单,这是一个不太安全的想法.要使黑名单成功,您需要确保黑名单完整,而且这通常是一项不可能完成的任务.在某些有限的环境中,黑名单方法可能是有用的,但只有当您尽可能确定时,该清单才是详尽无遗的.
存储数据 一旦只接受了干净的数据,请将其保存在变量或会话中.也许采用一种变量命名方法,表明这个数据现在是干净的.这里最重要的是,当我们保存这些数据时,我们还没有改变它.这意味着数据可以在任何上下文中使用,而不会让我们"扔掉任何东西"
输出编码 将数据发送到外部系统(例如文件名,cookie,网页,文件或保存在自己的数据库中)时,必须对数据进行编码,以确保不会破坏语言中使用的语言语法或文件格式.输出.在这里可以转换数据.
根据您使用数据的方式和位置,您需要对数据执行的转换将有所不同.转换用于windows文件名的字符串对于linux文件名是不同的,如果插入到PDF文档,网页或数据库等等,则会再次不同.但是,让我们更详细地看两个示例:
输出到HTML 在最常见的将字符串插入某些HTML的情况下,您需要确保不允许用户将任意内容注入页面,这不仅允许他们编辑其他用户可以看到的页面,但他们也可以以javascript的形式注入代码,可以做任何他们想做的事情.此脚本将以查看页面的用户身份运行,并可能允许攻击者窃取其信息和登录凭据.这称为跨站点脚本.HTML和Javascript的语法规则意味着您需要根据插入用户数据的HTML中的位置进行不同的编码.http://www.owasp.org/index.php/XSS_%28Cross_Site_Scripting%29_Prevention_Cheat_Sheet上有一个非常有价值的页面,它解释了如何转换6个不同类别的地方的数据,你可以在这些地方插入一个字符串到HTML页面.
输出到数据库 如果将用户数据保存到数据库,则实际上必须在SQL语句中包含该字符串.您必须确保不允许用户更改SQL语句的含义,并且只能更改数据值.如果它们可以更改语句的含义,则称为SQL注入.
这是一种特殊情况,因为虽然您可以使用输出编码来解决问题,但最好使用称为"绑定参数"的技术.这可确保您的数据始终用作数据,而不是与数据库通信时的代码.PHP支持许多db库中的绑定参数,包括"PDO"(跨数据库)和"Mysqli"(MySQL).应该注意,"Mysql"库不支持绑定参数.
整个网络和StackOverflow中有关于跨站点脚本(XSS)和SQL注入(SQLi)的更多信息,非常值得阅读这个主题.当然还有许多其他类型的攻击,但如果您按照上述过程进行操作,则应尽量减少风险.数据验证和编码例程构成安全Web应用程序的重要部分并非不合理.但是,您必须将安全方法纳入标准工作流程.将其作为事后补充添加起来要困难得多.有时候会回顾一下特定函数的验证代码,并考虑是否可以添加更多规则.总会有你第一次错过的东西.