如何防止自动 AJAX 攻击

发布于 2024-10-14 10:20:04 字数 1013 浏览 1 评论 0原文

如何防止用户自动发帖/垃圾邮件?

这是我的做法,每个页面请求都有新的 php 会话,它有其自身的局限性,没有多选项卡。

我为每个页面使用了新会话来防御 CSRF 和自动攻击。假设我们有一个使用 AJAX 发布线程的论坛,并通过 PHP SESSION 进行验证。

add_answer.php?id=123

<?php
if(!is_ajax()){// function that determines whether the request is from ajax (http header stuff)
$_SESSION['token'] = md5(rand());
}
//some ajax request to ajax.php?id=123
?>

ajax.php?id=123

<?php
if($_SESSION['token'] == $_GET['token']){
echo 'MYSQL INSERT stuff';
}else{
echo 'Invalid Request';
}
?>

一切正常,直到用户在另一个选项卡上打开 page.php?id=456,ajax 在 ajax.php?id=123 这与我问的另一个问题相关。他们建议始终只使用一个会话哈希,直到他/她注销 - 然后才会重新生成会话。如果令牌是同一个用户,则可以简单地绕过它并进行自动攻击。对此有什么想法吗?

无论如何,您的方法如何防止自动 AJAX 攻击?

PS:

  1. 不要用验证码折磨用户。
  2. 谷歌未能向我展示对此有用的东西。
  3. 将此视为一个挑战。
  4. 或者至少对专家的答案进行投票,您认为这是做到这一点的绝妙方法

How to prevent USER from doing automated posts/spam?

Here is my way of doing it, new php session for each page request, which has its own limitations, no multitabing.

I used new session for each page as defense against both CSRF and automated attacks. Lets say we have forum that uses AJAX to post threads and its validated by PHP SESSION.

add_answer.php?id=123

<?php
if(!is_ajax()){// function that determines whether the request is from ajax (http header stuff)
$_SESSION['token'] = md5(rand());
}
//some ajax request to ajax.php?id=123
?>

ajax.php?id=123

<?php
if($_SESSION['token'] == $_GET['token']){
echo 'MYSQL INSERT stuff';
}else{
echo 'Invalid Request';
}
?>

Every thing works fine until the user opens page.php?id=456 on another tab, the ajax returns 'invalid request' on ajax.php?id=123 This is related to another question I asked. They suggested to use only one session hash all the time, until he/she logs out - only then the session is regenerated. If the token is the same USER could simply bypass it and do the automated attacks. Any ideas on that?

Anyhow whats your way of preventing Automated AJAX attacks?

PS:

  1. Dont torture users with captchas.
  2. Google failed to show me something useful on this.
  3. Take this as a challenge.
  4. Or at least vote the answers of the experts which you think is brilliant way of doing this

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

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

发布评论

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

评论(3

烟沫凡尘 2024-10-21 10:20:05

听起来您反对只要浏览器打开就让会话保持打开状态是自动攻击的问题。不幸的是,在每个页面加载时刷新令牌只能阻止最业余的攻击者。

首先,我假设我们正在讨论专门针对您的网站的攻击。 (如果我们谈论的是那些只是四处游荡并提交各种表格的机器人,这不仅不会阻止他们,而且还有更好、更简单的方法来做到这一点。)如果是这样的话,我的目标是我的网站,这就是我的机器人会做的事情:

  1. 加载表单页面。
  2. 读取表单页面上的令牌。
  3. 使用该令牌提交自动请求。
  4. 转到步骤 1。

(或者,如果我对您的系统进行了足够的调查,我会意识到,如果我在每个请求中包含“这是 AJAX”标头,我可以永远保留一个令牌。或者我会意识到该令牌是我的会话 ID,并发送我自己的 PHPSESSID cookie。)

这种在每次页面加载时更改令牌的方法绝对无法阻止那些真正想要攻击你们所有人的人太糟糕了。因此,由于代币对自动化没有影响,所以重点关注它对 CSRF 的影响。

从阻止 CSRF 的角度来看,创建一个令牌并维护它直到用户关闭浏览器似乎就完成了所有目标。简单的 CSRF 攻击被击败,用户能够打开多个选项卡。

TL;DR:在每个请求上刷新一次令牌并不会提高安全性。追求可用性并在每个会话中执行一个令牌。


但是!如果您非常担心重复的表单提交(无论是意外还是其他原因),这个问题仍然可以轻松解决。答案很简单:将两个令牌用于两个不同的工作。

第一个令牌将保持不变,直到浏览器会话结束。该令牌的存在是为了防止 CSRF 攻击。该用户使用此令牌提交的任何内容都将被接受。

第二个令牌将为加载的每个表单唯一生成,并将存储在打开表单令牌的用户会话数据的列表中。该Token具有唯一性,一旦使用即失效。该用户使用此令牌提交的内容将被接受一次且仅一次。

这样,如果我打开表单 A 的选项卡和表单 B 的选项卡,每个选项卡都会有我个人的反 CSRF 令牌(已处理 CSRF)和我的一次性表单令牌(已处理表单重新提交)。这两个问题均得到解决,且不会对用户体验产生任何不良影响。

当然,您可能会认为对于这样一个简单的功能来说,实现起来太多了。无论如何,我认为是这样。无论如何,如果你想要的话,就存在一个可靠的解决方案。

It sounds like your objection to letting the session stay open as long as the browser is open is the issue of automated attacks. Unfortunately, refreshing the token on each page load only deters the most amateur attackers.

First, I assume we're talking about attacks specifically targeted at your site. (If we're talking about the bots that just roam around and submit various forms, not only would this not stop them, but there are far better and easier ways to do so.) If that's the case, and I'm targeting my site, here's what my bot would do:

  1. Load form page.
  2. Read token on form page.
  3. Submit automated request with that token.
  4. Go to step 1.

(Or, if I investigated your system enough, I'd realize that if I included the "this is AJAX" header on each request, I could keep one token forever. Or I'd realize that the token is my session ID, and send my own PHPSESSID cookie.)

This method of changing the token on each page load would do absolutely nothing to stop someone who actually wanted to attack you all that badly. Therefore, since the token has no effect on automation, focus on its effects on CSRF.

From the perspective of blocking CSRF, creating one token and maintaining it until the user closes the browser seems to accomplish all goals. Simple CSRF attacks are defeated, and the user is able to open multiple tabs.

TL;DR: Refreshing the token once on each request doesn't boost security. Go for usability and do one token per session.


However! If you're extremely concerned about duplicate form submissions, accidental or otherwise, this issue can still easily be resolved. The answer is simple: use two tokens for two different jobs.

The first token will stay the same until the browser session ends. This token exists to prevent CSRF attacks. Any submission from this user with this token will be accepted.

The second token will be uniquely generated for each form loaded, and will be stored in a list in the user's session data of open form tokens. This token is unique and is invalidated once it is used. Submissions from this user with this token will be accepted once and only once.

This way, if I open a tab to Form A and a tab to Form B, each one has my personal anti-CSRF token (CSRF taken care of), and my one-time form token (form resubmission taken care of). Both issues are resolved without any ill effect on the user experience.

Of course, you may decide that that's too much to implement for such a simple feature. I think it is, anyway. Regardless, a solid solution exists if you want it.

踏雪无痕 2024-10-21 10:20:05

如果您试图阻止某个客户端对您进行 DoS,一种不常见但可行的策略是包含 hashcash请求中的令牌(已经有 PHP 和 JavaScript 实现)。

为了防止破坏选项卡式浏览和后退按钮,理想情况下,您希望 hashcash 令牌的质询包含每个会话的防伪令牌和为每个请求新生成的唯一性部分。如果您的令牌成本较高,为了尽量减少对可用性的影响,请在消耗完前一个令牌后立即开始预先计算页面中的下一个令牌。

这样做会限制客户端生成有效请求的速率,因为每个 hashcash 令牌只能使用一次(这意味着您需要保留附加到会话的有效的、已用过的 hashcash 令牌的缓存,以防止无休止的重用单个令牌的数量),它们无法在会话开始之前计算(因为随机的防伪值),并且生成每个新的有效令牌需要花费大量的 CPU 时间,但只需要很少的时间来验证一个。

虽然这并不妨碍 AJAX API 本身的自动化,但它确实限制了 API 的大量使用。

If you're trying to prevent having one client DoS you, an uncommon but workable strategy would be to include a hashcash token in the request (there are already PHP and JavaScript implementations).

In order to prevent breaking tabbed browsing and back buttoning, ideally you'd want the hashcash token's challenge to contain both a per-session anti-forgery token and a uniqueness portion newly generated for each request. In order to minimize the impact on usability if you have a large token cost, start precomputing the next token in your page as soon as you've expended the previous one.

Doing this limits the rate at which a client can produce valid requests, because each hashcash token can only be used once (which means you'll need to keep a cache of valid, already-spent hashcash tokens attached to the session to prevent endless reuse of a single token), they can't be computed in advance of the session start (because of the random anti-forgery value), and it costs nontrivial amounts of CPU time to generate each new valid token but only a trivial amount of time to validate one.

While this doesn't prevent automation of your AJAX API per se, it does constrain high-volume hammering of the API.

梅窗月明清似水 2024-10-21 10:20:05

如何防止用户自动发布帖子/垃圾邮件?

这可能可以通过与常规请求相同的方式解决。每页加载一个令牌并停止新选项卡可能有点矫枉过正。当然,每个表单的时间敏感令牌可以在一定程度上减轻 CSRF 攻击。但除此之外,最好定义并实现提交策略引擎,而不是限制用户体验。

冒着对每个人来说听起来浮夸或贬低的风险:网站通常使用基于积分的奖励系统,例如“业力”或“徽章”。这样的系统实际上增加了用户体验,因为提交内容变成了用户的一种游戏。他们通常可能会限制仅向受信任的用户发布提交内容的能力,或者限制在给定时间范围内的最大数量。查看 SO 的系统以获得良好的用例。

一个非常基本的答案,只是演示一些常见的站点策略:

  • 如果用户在过去 y 分钟内的帖子数量超过了 x 数量,则拒绝数据库插入并显示“抱歉,自上次帖子以来太早了”警告。这可以通过在允许插入新记录之前查询数据库在给定的最近时间段内的用户帖子计数来实现。
  • 如果用户没有一定的业力阈值 - 例如,新用户或反复被标记为垃圾邮件发送者的用户 - 拒绝数据库写入并显示“抱歉,你在这里呆的时间不够长”或“抱歉,你也发垃圾邮件”很多”警告。这可以通过在允许插入新记录之前在数据库中查询用户的“业力”总数来实现,该“业力”在单独的表或站点模块中进行管理。
  • 如果网站很小且易于管理,仅可由一两个用户管理,请首先审查和批准所有新用户请求和帖子。这可以通过在移动到实时表之前在单独的表中保存新条目以供审查,或者通过在主表上设置“已批准”标志列来实现。

此外,可以对每个用户保留策略违规计数,如果在给定时间段内超过特定点,您可以选择在特定时间段内自动禁止他们。如果您愿意,可以通过拒绝与该用户相关的所有数据库写入来实施该禁令。

关于“http header stuff”的注释,标头仅用于对客户端请求的内容进行最佳猜测和礼貌。它们与伪造饼干一样困难,而伪造饼干只需要点击鼠标即可。老实说,我个人不会有任何其他方式。

How to prevent USER from doing automated posts/spam?

This could likely be solved in the same manner as regular requests. A token per page load and stopping new tabs may be overkill. Certainly a time-sensitive token per form may mitigate CSRF attacks to some degree. But otherwise, instead of restricting the user experience, it may be best to define and implement a submission policy engine.

At the risk of sounding pompous or demeaning to everyone: Often sites use a points-based reward system, such as "karma" or "badges". Such systems actually add to the user experience as submissions then become a sort of game for users. They may often restrict the ability to post submissions to only trusted users or by a max number during a given time-frame. Take a look at SO's system for a good use case.

A very basic answer just demonstrating some common site policies:

  • If the user exceeded a count of x number of posts in the past y minutes, deny DB insert and display a "Sorry, too soon since your last post" warning. This can be achieved by querying the DB for a count of users's posts over a given recent time period before allowing the new record insert.
  • If the user doesn't have a certain karma threshold - for example, new users or those repeatedly marked as spammers - deny DB write and display a "Sorry, you haven't been here long enough" or a "Sorry, you spam too much" warning. This can be achieved by querying the DB for a total of users's "karma", which is managed in a separate table or site module, before allowing the new record insert.
  • If the site is small and manageable enough to be moderated by just one or two users, have all new user requests and posts reviewed and approved first. This can be achieved by holding new entries in a separate table for review before moving to the live table, or by having an "approved" flag column on the main table.

Furthermore, a count of policy violations can be kept on each user, and if it exceeds a certain point over a given time period, you may opt to have them automatically banned for a certain time period. The ban can be put into effect by denying all db writes related to that user if you wish.

On the note about "http header stuff", headers are for only working off a best guess and courtesy at what the client is requesting. They are only as difficult to forge as cookies, and forging cookies only takes a click of the mouse. And honestly, I personally wouldn't have it any other way.

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