在 Web 开发过程中,我将花费多少时间用于用户输入验证?

发布于 2024-07-05 08:27:53 字数 90 浏览 7 评论 0原文

我是网络开发方面的新手。 到目前为止,我花了很多时间(50% 左右)来尝试阻止坏人将 sql 注入之类的东西放入我的输入表单中并在服务器端验证它。 这是正常的吗?

I'm new to developing things on the web. So far, I'm spending a lot of time (50% or so) to try and prevent bad people from putting things like sql injection into my input forms and validating it server side. Is this normal?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

小梨窩很甜 2024-07-12 08:27:53

@Jeremy - 一些 PHP 细节

当涉及到数据库查询时,总是尝试使用准备好的参数化查询。 mysqliPDO 库支持这一点。 这比使用 mysql_real_escape_string 等转义函数安全得多。

是的,mysql_real_escape_string 实际上只是一个字符串转义函数。 它不是灵丹妙药。 它所做的就是转义危险字符,以便它们可以安全地在单个查询字符串中使用。 但是,如果您不事先清理您的输入,那么您将很容易受到某些攻击媒介的攻击。

想象一下以下 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 注入向量。

虽然这些功能很有用,但必须小心使用。 您需要确保所有网络输入都在某种程度上得到验证。 在这种情况下,我们发现我们可以被利用,因为我们没有检查我们用作数字的变量实际上是数字。 在 PHP 中,您应该广泛使用一组函数来检查输入是否为整数、浮点数、字母数字等。但是当涉及 SQL 时,请最注意准备语句的值。 如果上面的代码是准备好的语句,那么它是安全的,因为数据库函数会知道 1 OR 1=1 不是有效的文字。

至于htmlspecialchars()。 这本身就是一个雷区。

PHP 中存在一个真正的问题,因为它有一系列不同的 html 相关转义函数,并且没有明确说明哪些函数具体做什么。

首先,如果您位于 HTML 标记内,那么您就有麻烦了。 看看

echo '<img src= "' . htmlspecialchars($_GET['imagesrc']) . '" />';

我们已经在 HTML 标签内了,所以我们不需要 << 或> 去做任何危险的事情。 我们的攻击向量可能只是 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 备忘单,了解向量的多样性的示例

,即使您使用 htmlspecialchars($ string)在 HTML 标签之外,您仍然容易受到多字节字符集攻击向量的攻击。

最有效的方法是使用 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 使用率下降。

@Jeremy - some PHP specifics

When it comes to database queries, always try and use prepared parameterised queries. The mysqli and PDO libraries support this. This is infinitely safer than using escaping functions such as mysql_real_escape_string.

Yes, mysql_real_escape_string is effectively just a string escaping function. It is not a magic bullet. All it will do is escape dangerous characters in order that they can be safe to use in a single query string. However, if you do not sanitise your inputs beforehand, then you will be vulnerable to certain attack vectors.

Imagine the following SQL:

$result = "SELECT fields FROM table WHERE id = ".mysql_real_escape_string($_POST['id']);

You should be able to see that this is vulnerable to exploit.
Imagine the id parameter contained the common attack vector:

1 OR 1=1

There's no risky chars in their to encode, so it will pass straight through the escaping filter. Leaving us:

SELECT fields FROM table WHERE id = 1 OR 1=1

Which is a lovely SQL injection vector.

Whilst these functions are useful, they must be used with care. You need to ensure that all web inputs are validated to some degree. In this case, we see that we can be exploited because we didn't check that a variable we were using as a number, was actually numeric. In PHP you should widely use a set of functions to check that inputs are integers, floats, alphanumeric etc. But when it comes to SQL, heed most the value of the prepared statement. The above code would have been secure if it was a prepared statement as the database functions would have known that 1 OR 1=1 is not a valid literal.

As for htmlspecialchars(). That's a minefield of its own.

There's a real problem in PHP in that it has a whole selection of different html-related escaping functions, and no clear guidance on exactly which functions do what.

Firstly, if you are inside an HTML tag, you are in real trouble. Look at

echo '<img src= "' . htmlspecialchars($_GET['imagesrc']) . '" />';

We're already inside an HTML tag, so we don't need < or > to do anything dangerous. Our attack vector could just be javascript:alert(document.cookie)

Now resultant HTML looks like

<img src= "javascript:alert(document.cookie)" />

The attack gets straight through.

It gets worse. Why? because htmlspecialchars only encodes double quotes and not single. So if we had

echo "<img src= '" . htmlspecialchars($_GET['imagesrc']) . ". />";

Our evil attacker can now inject whole new parameters

pic.png' onclick='location.href=xxx' onmouseover='...

gives us

<img src='pic.png' onclick='location.href=xxx' onmouseover='...' />

In these cases, there is no magic bullet, you just have to santise the input yourself. If you try and filter out bad characters you will surely fail. Take a whitelist approach and only let through the chars which are good. Look at the XSS cheat sheet for examples on how diverse vectors can be

Even if you use htmlspecialchars($string) outside of HTML tags, you are still vulnerable to multi-byte charset attack vectors.

The most effective you can be is to use the a combination of mb_convert_encoding and htmlentities as follows.

$str = mb_convert_encoding($str, ‘UTF-8′, ‘UTF-8′);
$str = htmlentities($str, ENT_QUOTES, ‘UTF-8′);

Even this leaves IE6 vulnerable, because of the way it handles UTF. However, you could fall back to a more limited encoding, such as ISO-8859-1, until IE6 usage drops off.

听不够的曲调 2024-07-12 08:27:53

为了防止 SQL 注入攻击,只需使用准备好的语句进行查询(具体方式取决于您的平台)。 一旦你这样做了,你就再也不用为这个特定的方面而烦恼了。 您只需在任何地方使用它即可。

至于一般的输入验证,最好依靠一个公共基础来测试所需的字段、数字等。例如,ASP.Net 的验证器非常易于使用。 您应该遵循的一条经验法则是不要相信客户端(javascript)会为您执行此操作,因为很容易绕过它。 始终首先在服务器端进行。

需要注意的一个特殊情况是,当您允许引入可能包含 html/javascript 的丰富内容时。 这可能允许恶意用户在您的数据中注入 JavaScript,从而在渲染数据时触发您无法控制的代码。 不要不要尝试使用自己的验证代码。 在网络上搜索免费的、经过测试的、维护的代码,可以为您做到这一点。 杰夫在一个播客中就这方面提出了一些建议。

一旦您自动化输入验证代码,执行此操作所花费的时间应该与业务规则的复杂性直接相关。 所以作为一般规则:保持简单。

To prevent sql injection attacks just do your queries with prepared statements (the exact way will depend on your platform). Once you do that, you'll never have to bother with this particular aspect again. You just need to use this everywhere.

As for general input validation, it's always good to rely on a common base to test for required fields, numbers, etc. ASP.Net's validators are very easy to use for example. One rule of thumb you should follow is not to trust client-side (javascript) to do this for you, since it's easy to go around it. Always do it server-side first.

A special case to keep under your radar is when you allow rich content to be introduced that may contain html/javascript. This can allow a malicious user to inject javascript in your data that will trigger code you don't control when you render it. Do not try to roll your own validation code. Search the web for free, tested, mantained code that will do it for you. Jeff had a few pointers in that regard in one of the podcasts.

Once you automate your input validation code, the time spent doing it should be directly related to the complexity of your business rules. So as a general rule: keep them simple.

远山浅 2024-07-12 08:27:53

不,这不正常。 也许您需要:

  • 使用权限组件来避免 SQL 注入(Java 中的 PreparedStatements)
  • 创建一个“过滤”来自用户的消息的组件(Java 中的 servlet Filter)。

任何现代语言都支持这两件事。

亲切的问候

No. It is not normal. Maybe you need to:

  • Use the rights components to avoid SQL Injection (PreparedStatements in Java)
  • Create a component that "filters" messages coming from user (a servlet Filter in Java).

Any modern language has support for both things.

Kind Regards

黯淡〆 2024-07-12 08:27:53

我很高兴你能注意保护自己。 太多人没有。

然而,正如其他人所说,更好的架构选择将使您的问题消失。 使用准备好的语句(大多数语言应该支持它)将使 SQL 注入攻击消失。 再加上许多数据库,它们将带来显着更好的性能。 处理跨站点脚本攻击更加棘手。 但基本策略必须是决定如何转义用户输入,决定在哪里转义它,并且始终在同一个地方进行。 不要陷入“越多越好”的陷阱! 在一个地方始终以一种方式执行此操作就足够了,并且可以避免您必须找出多个转义级别中的哪一个导致了特定的错误。

或者学习如何创建和维护健全的架构的课程需要经验。 此外,它需要反思你的糟糕经历。 因此,请注意您当前的痛点(看起来您确实是痛点),并思考您可以采取哪些不同的措施来避免它们。 如果您有导师,请与您的导师交谈。 这并不总是对你的这个项目有很大帮助,但对下一个项目会有帮助。

I'm glad you're taking care to protect yourself. Too many don't.

However as others have said, a better choice of architecture will make your problems go away. Using prepared statements (most languages should have support for that) will make SQL injection attacks go away. Plus with many databases they will result in significantly better performance. Handling cross-site scripting attacks is more tricky. But the basic strategy has to be to decide how you will escape user input, decide where you will escape it, and always do it in the same place. Don't fall into the trap of thinking that more is better! Consistently doing it in one way in one place will suffice, and will avoid your having to figure out which of the multiple levels of escaping are causing a specific bug.

Or course learning how to create and maintain a sane architecture takes experience. And moreover, it takes reflecting on your bad experiences. So pay attention to your current pain points (it looks like you are), and think about what you could have done differently to avoid them. If you have a mentor, talk with your mentor. That won't always help you so much with this project, but it will with the next.

一城柳絮吹成雪 2024-07-12 08:27:53

您面临的问题只能通过概括来解决。

尝试识别常见的输入验证类型,您需要

  • 数字/字符串值/正则表达式验证
  • 范围/长度
  • 转义特殊字符
  • 检查您在特定上下文中不期望的常见关键字(“script”、“select”、“drop”)。 ..)针对黑名单

并在处理数据之前系统地调用它们。

所有数据库访问都必须使用准备好的语句完成,而不是连接查询字符串。

所有输出都必须进行转义,因为您不想将转义的所有内容存储在数据库中。

一个好的带外/社交方法是:尽可能地识别您的用户。 被识别的机会越高,他们欺骗系统的可能性就越小。 获取他们的手机号码以发送代码、检查他们的信用卡等。

You're facing a problem that only can be solved by generalizing.

Try to identify common types of input-validation you need

  • numeric / string values / regex validation
  • range / length
  • escaping special characters
  • check for common keywords you don't expect in a particular context ('script', 'select', 'drop'...) against a blacklist

and call them systematically before processing the data.

All database access must be done with prepared statements and not concatenating a query string.

All output must be escaped, since you d'ont want to store everything escaped in your database.

A good out of band/social approach is: identify your users the best you can. The higher the chance to get identified, the lesser they will fool with the system. Get their mobile phone number to send a code, check their credit-card etc.

鹤舞 2024-07-12 08:27:53

我看到你的问题了。 看起来您的保护逻辑散布在整个代码库中。并且每次编写有潜在危险的代码时,您都必须小心地包含所有保护。 每次出现新的威胁时,您都必须仔细检查所有这些声明并验证它们是否安全。

你不能用这种方式实现真正的安全性。

你应该有一些包装器,这将使生成不安全的代码变得困难,如果不是不可能的话。 例如,准备好的语句。 但是您可能想要使用 ORM,例如 Ruby on Rails 的 ActiveRecord,或者框架中的某些等效项。

对于输出和 XSS 保护,请确保输出默认情况下是 HTML 转义的。然后,如果您确实需要将生成的 HTML 输出给用户,您将显式执行此操作,并且更容易验证。

对于 CSRF 保护,也尝试找到一个通用的解决方案。 一般来说,它应该自动履行其职责,而不需要您显式创建验证令牌,并手动验证它、丢弃它或拒绝请求。

I see your problem. It looks like you have the protection logic sprinkled all over the codebase. And each time you write potentially dangerous code you have to be careful to include all protections. And each time a new threat is out, you have to go through all these statements and verify that they're secure.

You can't do real security this way.

You should have some wrappers, that would make producing insecure code hard, if not impossible. For example, prepared statements. But you may want to use an ORM, like Ruby on Rails' ActiveRecord, or some equivalent in your framework.

For output and XSS protection, make sure that output is HTML-escaped by default. Then if you really need to output generated HTML to user, you'll do this explicitly, and it will be easier to verify.

For CSRF protection try to also find a generic solution. Generally it should do its duty automatically, without the need for you to explicitly create a verification token, and manually verify it, discard it, or deny the request.

蛮可爱 2024-07-12 08:27:53

只是关于准备好的陈述的注释。 首先,如果可以的话,您应该尝试使用存储过程......在大多数情况下它们可能是更好的解决方案。

其次,只有当您不使用动态 SQL(即编写更多 SQL 然后执行它的 SQL)时,它们才能保护您免受 SQL 注入。 在这种情况下,它们将无效——存储过程也是如此。

关于您花费的时间百分比:验证非常重要,即使不需要花一些时间,也确实需要一些思考。 但百分比取决于您的应用程序有多大,不是吗? 在一个非常小的应用程序中,例如,只有新闻通讯注册,验证很可能会占用您很大一部分时间。

在较大的应用程序中,即有大量非表示代码的情况下,这是不正常的。

Just a note on prepared statements. First of all, you should try to use stored procedures if you can... they are probably a better solution in most cases.

Secondly, they both protect you from SQL injection only as long as you don't use dynamic SQL, that is, SQL that writes more SQL and then executes it. In this case they will be ineffective -- and so will be stored procedures.

Regarding the percentage of time you spend: validation is very important and it does take some thought, if not some time. But the percentage depends on how large your application is, no? In a very small application, say, only a newsletter registration, it's quite possible that validation takes a huge percentage of your time.

In larger applications, i.e. where you have a lot of non-presentation code, it is not normal.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文