当前位置:  开发笔记 > 编程语言 > 正文

如果我使用下拉列表,是否必须防止SQL注入?

如何解决《如果我使用下拉列表,是否必须防止SQL注入?》经验,为你挑选了9个好方法。

我知道你绝不应该信任表单中的用户输入,主要是因为SQL注入的可能性.

但是,这是否也适用于唯一输入来自下拉列表的表单(见下文)?

我将保存$_POST['size']到一个会话,然后在整个站点中使用该会话来查询各种数据库(使用mysqliSelect查询),任何SQL注入肯定会损害(可能会丢失)它们.

查询数据库的类型用户输入没有区域,只有下拉列表.

doppelgreene.. 194

是的,你需要防止这种情况发生.

让我告诉你为什么,使用Firefox的开发者控制台:

我已经将下拉列表中的一个值编辑为drop table语句

如果不清除此数据,则会破坏您的数据库.(这可能不是一个完全有效的SQL语句,但我希望我已经明确了我的观点.)

仅仅因为您限制了下拉列表可用的选项并不意味着您限制了我可以发送服务器的数据.

如果您尝试使用页面上的行为进一步限制此操作,我的选项包括禁用该行为,或者只是向服务器写入自定义HTTP请求,无论如何都会模仿此表单提交.有一个名为curl的工具正是用于此,我认为提交此SQL注入的命令看起来像这样:

curl --data "size=%27%29%3B%20DROP%20TABLE%20*%3B%20--"  http://www.example.com/profile/save

(这可能不是一个完全有效的curl命令,但是,我希望我已经明确了我的观点.)

所以,我会重申:

永远不要相信用户输入.总是保护自己.

不要假设任何用户输入是安全的.即使它通过表格之外的某些方式到达,它也可能是不安全的.没有任何一个值得信赖的放弃保护自己免受SQL注入.



1> doppelgreene..:

是的,你需要防止这种情况发生.

让我告诉你为什么,使用Firefox的开发者控制台:

我已经将下拉列表中的一个值编辑为drop table语句

如果不清除此数据,则会破坏您的数据库.(这可能不是一个完全有效的SQL语句,但我希望我已经明确了我的观点.)

仅仅因为您限制了下拉列表可用的选项并不意味着您限制了我可以发送服务器的数据.

如果您尝试使用页面上的行为进一步限制此操作,我的选项包括禁用该行为,或者只是向服务器写入自定义HTTP请求,无论如何都会模仿此表单提交.有一个名为curl的工具正是用于此,我认为提交此SQL注入的命令看起来像这样:

curl --data "size=%27%29%3B%20DROP%20TABLE%20*%3B%20--"  http://www.example.com/profile/save

(这可能不是一个完全有效的curl命令,但是,我希望我已经明确了我的观点.)

所以,我会重申:

永远不要相信用户输入.总是保护自己.

不要假设任何用户输入是安全的.即使它通过表格之外的某些方式到达,它也可能是不安全的.没有任何一个值得信赖的放弃保护自己免受SQL注入.


更不用说使用`curl`制作自定义有效负载了.***总是***消毒输入*服务器端*!
一张图片说的超过千言万语.
这应该是默认答案.还应该包括一些关于`curl`的东西.人们不明白你可以使用任何格式从任何地方向任何地方发送HTTP请求并传递任何值,由服务器决定请求在处理之前是否有效.
真可爱!这是小鲍比桌子!

2> Oliver Bayes..:

您可以执行与以下示例一样简单的操作,以确保发布的大小符合您的预期.

$possibleOptions = array('All', 'Large', 'Medium', 'Small');

if(in_array($_POST['size'], $possibleOptions)) {
    // Expected
} else {
    // Not Expected
}

然后使用mysqli_*如果你使用的是php> = 5.3.0的版本,你应该保存你的结果.如果使用正确,这将有助于sql注入.


但是,您必须使用Prepared Statements(推荐)或[`mysqli_real_escape_string`](http://php.net/mysqli_real_escape_string).在输出时也适当地转义值(例如在HTML文档中使用[htmlspecialchars()](http://php.net/htmlspecialchars).
我建议将`in_array`的第三个参数设置为'true`以进行严格比较.我不确定会出现什么问题,但是松散的比较非常古怪.

3> Your Common ..:

由于这个问题是用sql-injection标记的,所以这里有一个关于这种特殊攻击的答案:

正如您在评论中被告知的那样,您必须为涉及任何变量数据的每个查询使用预准备语句,没有例外.

无论任何HTML的东西!
必须了解SQL查询必须正确格式化,无论外部因素如何,无论是HTML输入还是其他任何因素.

虽然您可以使用其他答案中建议的白名单来进行输入验证,但它不应该影响任何与SQL相关的操作 - 无论您是否验证了HTML输入,它们都必须保持不变.这意味着在向查询中添加任何变量时,您仍然必须使用预准备语句.

在这里你可以找到一个彻底的解释,为什么准备好的陈述是必须的,如何正确使用它们以及它们不适用的地方以及在这种情况下该怎么做:Hitchhiker的SQL注入保护指南

此外,这个问题用mysqli标记.我猜想,大多是偶然的,但无论如何,我必须警告你,原始的mysqli 不能替代旧的mysq_*函数.仅仅因为如果使用旧样式,它将根本不添加任何安全性.虽然它对准备好的语句的支持是痛苦和麻烦的,但普通的PHP用户根本无法完成它们.因此,如果没有ORM或某种抽象库可供选择,那么PDO是您唯一的选择.


@YourCommonSense视线狭窄?对我来说"永远做X,我不会为它提供任何理由"是狭隘的.
i =随机(0,15); //使用i的一些查询 我还需要在这里准备好声明吗?
@Cruncher我想不出有什么理由不总是*总是*每次都使用准备好的陈述.你能告诉我一个吗?
@Cruncher我同意,看起来你似乎在扮演Devil的倡导者.答案中的规定也是*"涉及任何可变数据"*.有一些情况可能像PHP int casting,但似乎更好地使用预准备语句.告诉(没有经验的)人们认为轻微的表现"提升"比安全更重要.答案是"不完整",但它发出了一个强烈的信息,其他人都在忽略.我会休息一下.
什么是`random`的实现?
@Slicedpan如果你的随机不起作用,那么即使你的任何加密都是不安全的......在这种情况下,SQL注入不是你最大的问题.
@YourCommonSense还要提到这个答案非常不完整.你的预备陈述之神在这里还不够.他们仍然可能将值注入您的数据库,这可能会在以后出现问题.这是我的问题,人们只是说"总是做X".这使他们不考虑实际的安全问题.最好的方法是分析和确定必要的安全措施.
@Cruncher你听说过早优化的弊端吗?我无法想象这样一种场景,即请求加倍会成为性能的瓶颈.(除非你有5亿用户)
@WesleyMurch 0.001是一个GIANT假设.你告诉我找你一个案子.没有找到适合您没有告诉我的一些先前存在的情况的案例.当然,当人们获胜时,你会改变规则.如果您的应用程序在没有它的情况下是安全的,那么您什
@WesleyMurch AACK.在指导年轻程序员时,最好教他们为什么做这些事情.不只是告诉他们这样做.
@AnonymousPi不,没有丝毫想法.在这个问题变成"热"之后还是什么的 - 是的,这是可以理解的.但这是一个问题 - *它是如何实现的.它与其他数十万个未经注意的问题没有什么不同.

4> rm-vanda..:

是.

任何人都可以欺骗任何实际发送的值 -

因此,为了验证下拉菜单,您可以检查以确保您正在使用的值位于下拉列表中 - 这样的方式将是最好的(最明显的偏执)方式:

if(in_array($_POST['ddMenu'], $dropDownValues){

    $valueYouUseLaterInPDO = $dropDownValues[array_search("two", $arr)];

} else {

    die("effin h4x0rs! Keep off my LAMP!!"); 

}


@Slicedpan真的吗?这听起来就像你在不知道为什么的时候跳上了潮流......如果我在查询中有一些可能的输入,这样我就可以验证它们一切都好(我知道,因为我制作了它们),然后,您不会因使用预准备语句而产生额外的*安全*好处
这个答案是不完整的,另外你应该使用预准备语句,这样无论设置的值是什么,都不可能注入
除了强制使用预准备语句作为约定之外,您将来不会引入SQL注入漏洞.

5> Styphon..:

防止用户使用控制台更改下拉列表的一种方法是仅在其中使用整数值.然后,您可以验证POST值是否包含整数,并在需要时使用数组将其转换为文本.例如:

 'All', 1 => 'Large', 2 => 'Medium', 3 => 'Small');
$size = filter_input(INPUT_POST, "size", FILTER_VALIDATE_INT);

echo '';

然后,您可以$size在查询中使用它只包含的知识FALSE或整数.


@OliverBS什么是`filter_input`,如果没有在服务器端检查?没有人可以发布除整数之外的任何内容.

6> donquixote..:

其他答案已涵盖您需要了解的内容.但也许有助于澄清更多:

两件事情你需要做的:

1.验证表单数据.

正如Jonathan Hobbs的回答非常清楚地表明,为表单输入选择html元素并不能为您做任何可靠的过滤.

验证通常以不改变数据的方式进行,但是再次显示表单,标记为"请更正此"的字段.

大多数框架和CMS都有表单构建器,可以帮助您完成此任务.不仅如此,它们还有助于反对CSRF(或"XSRF"),这是另一种形式的攻击.

2. SQL语句中的清理/转义变量..

..或者让准备好的陈述为你完成这项工作.

如果使用用户提供或不提供的任何变量构建(My)SQL语句,则需要转义并引用这些变量.

通常,您插入MySQL语句的任何此类变量应该是字符串,或者PHP可以可靠地变成MySQL可以消化的字符串.如,数字.

对于字符串,您需要选择几种方法之一来转义字符串,这意味着,替换任何在MySQL中具有副作用的字符.

在老式的MySQL + PHP中,mysql_real_escape_string()完成了这项工作.问题是它太容易忘记了,所以你绝对应该使用预准备语句或查询构建器.

在MySQLi中,您可以使用预准备语句.

大多数框架和CMS提供了帮助您完成此任务的查询构建器.

如果您正在处理数字,则可以省略转义和引号(这就是准备好的语句允许指定类型的原因).

重要的是要指出您为SQL语句转义变量,而不是数据库本身.数据库将存储原始字符串,但该语句需要转义版本.

如果省略其中一个,会发生什么?

如果你不使用表单验证,但你确实清理了你的SQL输入,你可能会看到各种不好的事情发生,但你不会看到SQL注入!(*)

首先,它可以使您的应用程序进入您没有计划的状态.例如,如果您想计算所有用户的平均年龄,但是一个用户为该年龄提供了"aljkdfaqer",则您的计算将失败.

其次,您可能需要考虑各种其他注入攻击:例如,用户输入可能包含javascript或其他内容.

数据库仍然存在问题:例如,如果字段(数据库表列)限制为255个字符,并且字符串长于该字符串.或者,如果该字段仅接受数字,则您尝试保存非数字字符串.但这不是"注入",只是"使应用程序崩溃".

但是,即使您有一个自由文本字段,您允许任何输入完全没有验证,您仍然可以将其保存到数据库中,如果您在转到数据库语句时正确地将其保存.当你想在某个地方使用这个字符串时会出现问题.

(*)或者这将是非常奇特的东西.

如果你没有为SQL语句转义变量,但你确实验证了表单输入,那么你仍然可以看到发生了不好的事情.

首先,您冒着将数据保存到数据库并再次加载数据的风险,它将不再是相同的数据,"在翻译中丢失".

其次,它可能导致无效的SQL语句,从而导致应用程序崩溃.例如,如果任何变量包含引号或双引号字符,则根据您使用的引用类型,您将获得无效的MySQL语句.

第三,它仍然可以导致SQL注入.

如果表单中的用户输入已经过滤/验证,则有意 SQl注入可能会变得不太可能,如果您的输入被缩减为硬编码选项列表,或者仅限于数字.但是,如果没有正确地转义SQL语句中的变量,那么任何自由文本输入都可以用于SQL注入.

即使你根本没有表格输入,你仍然可以拥有来自各种来源的字符串:从文件系统中读取,从互联网上删除等等.没有人可以保证这些字符串是安全的.



7> Nameless One..:

您的网络浏览器"不知道"它正在从php接收页面,它看到的只是html.并且http层知道甚至更少.你需要能够处理几乎任何可以跨越http层的输入(幸运的是,大多数输入php都会给出错误).如果您试图阻止恶意请求弄乱您的数据库,那么您需要假设另一端的人知道他在做什么,并且他不仅限于您在正常情况下在浏览器中看到的内容(更不用说你可以摆弄浏览器的开发者工具了.所以是的,您需要满足下拉列表中的任何输入,但对于大多数输入,您可以给出错误.



8> Jason Higgin..:

您将用户限制为仅使用某个下拉列表中的值这一事实无关紧要.技术用户可以在离开网络之前捕获发送到服务器的http请求,使用本地代理服务器等工具对其进行更改,然后继续使用它.使用更改的请求,他们可以发送不是您在下拉列表中指定的参数值.开发人员必须具备客户端限制通常毫无意义的心态,因为客户端上的任何内容都可以被更改.客户端数据进入的每个点都需要服务器验证.在这方面,攻击者依赖于开发人员的天真.



9> Dan Smith..:

最好使用参数化查询以确保不会出现SQL注入.在这种情况下,查询的外观将是这样的:

SELECT * FROM table WHERE size = ?

当您提供如上所述的查询时,文本未经验证是为了完整性(输入未在服务器上验证)并且它包含SQL注入代码,它将被正确处理.换句话说,请求将导致在数据库层中发生这样的事情:

SELECT * FROM table WHERE size = 'DROP table;'

这将简单地选择返回0结果,这将使查询无效实际上对数据库造成损害而无需白名单,验证检查或其他技术.请注意,负责任的程序员将分层执行安全性,并且除了参数化查询之外,还经常进行验证.但是,从性能角度来看,没有理由不对查询进行参数化,并且通过这种做法添加的安全性是熟悉参数化查询的一个很好的理由.

推荐阅读
个性2402852463
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有