清理来自用户的输入的首选方法是什么?
谢谢你!
只要可行, WL 就是针对 BL 的最佳实践。
原因很简单:您无法合理安全地枚举不允许的内容,攻击者总能找到您没有想到的方法。如果可以的话,肯定地说什么是允许的,它更简单,更安全!
最好的方法是使用存储过程或参数化查询。白名单是一种附加技术,可以在任何注入到达服务器之前阻止它们,但不应用作您的主要防御措施。黑名单通常不是一个好主意,因为通常不可能过滤掉所有恶意输入。
顺便说一句,这个答案考虑到你的意思是像防止 sql 注入一样进行消毒。
让我用更多的问答来解释你的问题。
黑名单 VS 白名单限制
一世。黑名单 XSS 和 SQL 注入处理根据负面输入列表验证所需的输入。基本上,人们会编制一份所有负面或不良条件的列表,并验证接收到的输入不是不良或负面条件之一。
ii. 白名单 XSS 和 SQL 注入处理根据可能的正确输入列表验证所需的输入。为此,将编制一份所有良好/积极输入值/条件的列表,并验证接收到的输入是否是正确条件之一。
哪个更好?
一世。攻击者将使用任何可能的手段来访问您的应用程序。这包括尝试各种负面或不良条件、各种编码方法以及将恶意输入数据附加到有效数据中。你认为你能想到所有可能发生的坏排列吗?
ii. 白名单是验证输入的最佳方式。您将确切知道需要什么,并且不接受任何错误类型。通常,创建白名单的最佳方法是使用正则表达式。使用正则表达式是抽象白名单的好方法,而不是手动列出每个可能的正确值。
建立一个好的正则表达式。仅仅因为您使用的是正则表达式并不意味着不接受错误的输入。确保您测试您的正则表达式,并且您的正则表达式不能接受无效输入。
我认为白名单是理想的方法,但是我从未遇到过真正的白名单 HTML 表单验证。例如,这里是一个带有文档验证的 symfony 1.x 表单:
class ContactForm extends sfForm
{
protected static $subjects = array('Subject A', 'Subject B', 'Subject C');
public function configure()
{
$this->setWidgets(array(
'name' => new sfWidgetFormInput(),
'email' => new sfWidgetFormInput(),
'subject' => new sfWidgetFormSelect(array('choices' => self::$subjects)),
'message' => new sfWidgetFormTextarea(),
));
$this->widgetSchema->setNameFormat('contact[%s]');
$this->setValidators(array(
'name' => new sfValidatorString(array('required' => false)),
'email' => new sfValidatorEmail(),
'subject' => new sfValidatorChoice(array('choices' => array_keys(self::$subjects))),
'message' => new sfValidatorString(array('min_length' => 4)),
));
}
}
您看不到的是,它在没有验证设置的情况下接受新输入,并且不检查未在表单中注册的输入是否存在。所以这是一个黑名单输入验证。通过白名单,您将首先定义一个输入验证器,然后才将一个输入字段绑定到该验证器。通过像这样的黑名单方法,很容易忘记向输入添加验证器,没有它它可以完美地工作,所以你不会注意到漏洞,只有当为时已晚......
假设的白名单方法如下所示:
class ContactController {
/**
* @input("name", type = "string", singleLine = true, required = false)
* @input("email", type = "email")
* @input("subject", type = "string", alternatives = ['Subject A', 'Subject B', 'Subject C'])
* @input("message", type = "string", range = [4,])
*/
public function post(Inputs $inputs){
//automatically validates inputs
//throws error when an input is not on the list
//throws error when an input has invalid value
}
}
/**
* @controller(ContactController)
* @method(post)
*/
class ContactForm extends sfFormX {
public function configure(InputsMeta $inputs)
{
//automatically binds the form to the input list of the @controller.@method
//throws error when the @controller.@method.@input is not defined for a widget
$this->addWidgets(
new sfWidgetFormInput($inputs->name),
new sfWidgetFormInput($inputs->email),
new sfWidgetFormSelect($inputs->subject),
new sfWidgetFormTextarea($inputs->message)
);
$this->widgetSchema->setNameFormat('contact[%s]');
}
}
就个人而言,我会衡量允许或不允许字符的数量,然后从那里开始。如果允许的字符多于不允许的字符,则将其列入黑名单。否则白名单。我不相信有任何“标准”说你应该以一种或另一种方式去做。
顺便说一句,这个答案假设您想限制输入表单字段,例如电话号码或姓名:) @posterBelow
作为一般规则,最好使用白名单验证,因为它更容易只接受你知道应该去那里的字符,例如,如果你有一个用户输入他/她的电话号码的字段,你可以只做一个正则表达式并检查值收到的只是数字,删除其他所有内容并存储数字。请注意,您还应该继续验证结果数字。黑名单验证较弱,因为熟练的攻击者可以规避您的验证功能或发送您的功能未预料到的值,来自 OWASP“使用黑名单进行清理”:
消除或翻译字符(例如 HTML 实体或删除引号)以使输入“安全”。像黑名单一样,这种方法需要维护并且通常是不完整的。由于大多数领域都有特定的语法,因此简单地验证单个正确的正面测试比尝试为所有当前和未来的攻击包含复杂且缓慢的清理例程更简单、更快、更安全。
意识到这种验证只是抵御攻击的第一道防线。对于 XSS,你应该总是“转义”你的输出,这样你就可以打印任何需要的字符,但是它们被转义意味着它们被更改为它们的 HTML 实体,因此浏览器知道它是数据而不是解析器应该解释的东西,从而有效地关闭所有XSS 攻击。对于 SQL 注入在存储之前转义所有数据,尽量不要使用动态查询,因为它们是最容易利用的查询类型。尝试使用参数化存储过程。还要记住使用与连接必须执行的操作相关的连接。如果连接只需要读取数据,请创建一个只有“读取”权限的数据库帐户,这主要取决于用户的角色。
答案通常是,这取决于。
对于具有明确定义的参数的输入(例如相当于下拉菜单),我会将选项列入白名单并忽略不属于其中之一的任何内容。
对于自由文本输入,这要困难得多。我赞同这一学派,您应该尽可能地过滤它,使其尽可能安全(转义 HTML 等)。其他一些建议是明确禁止任何无效输入 - 然而,虽然这可能会防止攻击,但它也可能会影响真正用户的可用性。
我认为这只是找到适合你的混合物的一个例子。我想不出任何一种适用于所有可能性的解决方案。主要取决于您的用户群。