我很擅长在网上开发东西。到目前为止,我花了很多时间(50%左右)来尝试阻止坏人将sql注入等内容放入我的输入表单并验证服务器端。这是正常的吗?
答案 0 :(得分:9)
@Jeremy - 一些PHP细节
说到数据库查询,请始终尝试使用准备好的参数化查询。 mysqli
和PDO
库支持此功能。这比使用mysql_real_escape_string等转义函数更安全。
是的,mysql_real_escape_string实际上只是一个字符串转义函数。它不是一个神奇的子弹。它所做的只是逃避危险的字符,以便在单个查询字符串中使用它们是安全的。但是,如果您事先没有对输入进行消毒,那么您将容易受到某些攻击媒介的攻击。</ p>
想象一下以下SQL:
$result = "SELECT fields FROM table WHERE id = ".mysql_real_escape_string($_POST['id']);
你应该能够看到这很容易受到攻击
想象一下id
参数包含常见的攻击向量:
1 OR 1=1
编码时没有冒险的字符,所以它会直接通过转义过滤器。离开我们:
SELECT fields FROM table WHERE id = 1 OR 1=1
这是一个可爱的SQL注入向量。
虽然这些功能很有用,但必须小心使用。您需要确保在某种程度上验证所有Web输入。在这种情况下,我们看到我们可以被利用,因为我们没有检查我们用作数字的变量,实际上是数字。在PHP中,您应该广泛使用一组函数来检查输入是整数,浮点数,字母数字等。但是当涉及到SQL时,请注意准备语句的大部分值。如果它是一个准备好的语句,上面的代码就是安全的,因为数据库函数已经知道1 OR 1=1
不是有效的文字。
至于htmlspecialchars()。那是一个独立的雷区。
PHP中存在一个真正的问题,即它具有一系列与html相关的不同转义函数,并且没有明确指导哪些函数可以做什么。
首先,如果你在HTML标签内,那你就遇到了麻烦。看看
echo '<img src= "' . htmlspecialchars($_GET['imagesrc']) . '" />';
我们已经在HTML标记内,因此我们不需要&lt;或者&gt;做任何危险的事情。我们的攻击向量可能只是javascript:alert(document.cookie)
现在生成的HTML看起来像
<img src= "javascript:alert(document.cookie)" />
攻击直截了当。
情况变得更糟。为什么?因为htmlspecialchars只编码双引号而不是单引号。所以,如果我们有
echo "<img src= '" . htmlspecialchars($_GET['imagesrc']) . ". />";
我们的邪恶攻击者现在可以注入全新的参数
pic.png' onclick='location.href=xxx' onmouseover='...
给我们
<img src='pic.png' onclick='location.href=xxx' onmouseover='...' />
在这些情况下,没有灵丹妙药,你只需要自己调整输入。如果你试图过滤掉坏的角色,你肯定会失败。采取白名单的方法,只让通过好的字符。请查看XSS cheat sheet有关不同向量的示例
即使您在HTML标记之外使用htmlspecialchars($ string),您仍然容易受到多字节字符集攻击媒介的攻击。</ p>
最有效的方法是使用mb_convert_encoding和htmlentities的组合,如下所示。
$str = mb_convert_encoding($str, ‘UTF-8′, ‘UTF-8′);
$str = htmlentities($str, ENT_QUOTES, ‘UTF-8′);
即使这样,IE6仍然容易受到攻击,因为它处理UTF的方式。但是,您可以回退到更有限的编码,例如ISO-8859-1,直到IE6使用率下降。
答案 1 :(得分:8)
要防止sql注入攻击,只需使用预准备语句进行查询(具体方法取决于您的平台)。一旦你这样做,你将再也不必为这个特殊方面而烦恼。你只需要在任何地方使用 。
对于一般的输入验证,依靠公共基础来测试必需的字段,数字等总是好的。例如,ASP.Net的验证器非常容易使用。你应该遵循的一条经验法则是不要相信客户端(javascript)为你做这件事,因为它很容易解决它。始终先在服务器端进行。
当您允许引入可能包含html / javascript的丰富内容时,您需要关注的特殊情况。这可能允许恶意用户在您的数据中注入javascript,这将触发您在呈现时无法控制的代码。 不尝试滚动您自己的验证码。在网上搜索可以为您完成的免费,经过测试和修改的代码。杰夫在其中一个播客中有这方面的一些指示。
自动化输入验证代码后,执行此操作所花费的时间应与业务规则的复杂性直接相关。因此,作为一般规则:保持简单。
答案 2 :(得分:2)
没有。这不正常。也许你需要:
任何现代语言都支持这两种情况。
亲切的问候
答案 3 :(得分:2)
我很高兴你注意保护自己。太多没有。
然而正如其他人所说,更好的架构选择会让你的问题消失。使用预准备语句(大多数语言应该支持)将使SQL注入攻击消失。加上许多数据库,它们将带来明显更好的性能。处理跨站点脚本攻击更加棘手。但基本的策略必须是决定如何逃避用户输入,决定你将逃脱它的位置,并始终在同一个地方进行。不要陷入认为越多越好的陷阱!一直在一个地方以一种方式完成它就足够了,并且可以避免你必须弄清楚多个转义级别中的哪一个导致特定的错误。
或者学习如何创建和维护理智的架构的课程需要经验。而且,它需要反映你的糟糕经历。所以要注意你当前的痛点(它看起来像你),并考虑你可以做些什么来避免它们。如果您有导师,请与您的导师交谈。对于这个项目来说,这并不会对你有太多的帮助,但它会与下一个项目有所帮助。
答案 4 :(得分:2)
我看到了你的问题。看起来你已经在整个代码库中散布了保护逻辑。每次编写有潜在危险的代码时,都必须小心包含所有保护措施。每当出现新威胁时,您必须完成所有这些陈述并验证它们是否安全。
你无法以这种方式做到真正的安全。
你应该有一些包装器,如果不是不可能的话,难以生成不安全的代码。例如,准备好的陈述。但是你可能想要使用ORM,比如Ruby on Rails的ActiveRecord,或者你的框架中的等价物。
对于输出和XSS保护,请确保默认情况下输出 HTML转义。然后,如果您确实需要将生成的HTML输出到用户,您将明确地执行此操作,它将是更容易验证。
对于CSRF保护,尝试找到通用解决方案。通常它应该自动执行其职责,而无需您明确创建验证令牌,并手动验证,丢弃或拒绝请求。
答案 5 :(得分:1)
关于预备陈述的说明。首先,如果可以的话,你应该尝试使用存储过程......在大多数情况下,它们可能是更好的解决方案。
其次,只要您不使用动态SQL,即只编写更多SQL然后执行它的SQL,它们都会保护您免受SQL注入。在这种情况下,它们将无效 - 存储过程也是如此。
关于您花费的时间百分比:验证非常重要,如果不是一段时间,它确实需要一些思考。但百分比取决于你的申请量有多大,不是吗?例如,在一个非常小的应用程序中,只有一个简报注册,验证很可能占用了你很大一部分时间。
在较大的应用程序中,即你有很多非表示代码的地方,这是不正常的。
答案 6 :(得分:1)
你面临的问题只能通过概括来解决。
尝试识别您需要的常见输入验证类型
在处理数据之前系统地调用它们。
所有数据库访问必须使用预准备语句完成,而不是连接查询字符串。
所有输出必须进行转义,因为您想要存储数据库中转义的所有内容。
良好的带外/社交方法是:尽可能地识别您的用户。获得识别的机会越高,他们就越不会愚弄系统。获取手机号码发送密码,查看信用卡等。