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.
这是我的方式,为每个页面请求新的php会话,它有自己的限制,没有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.
我为每个页面使用了新会话来防御CSRF和自动攻击。让我们说我们有论坛使用AJAX发布线程并由PHP SESSION验证。
add_answer.php?id=123
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
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?
一切正常,直到用户在另一个选项卡上打开page.php?id = 456,ajax在ajax.php上返回'invalid request'?id = 123这与我问的另一个问题有关。他们建议一直只使用一个会话哈希,直到他/她注销 - 然后才重新生成会话。如果令牌是相同的,则USER可以简单地绕过它并进行自动攻击。有什么想法吗?
Anyhow whats your way of preventing Automated AJAX attacks?
无论如何,你是如何防止自动AJAX攻击的?
PS:
PS:
- Dont torture users with captchas.
- 不要用验证码折磨用户。
- Google failed to show me something useful on this.
- 谷歌未能向我展示一些有用的东西。
- Take this as a challenge.
- 以此为挑战。
- Or at least vote the answers of the experts which you think is brilliant way of doing this
- 或者至少投票给专家的答案,你认为这是很好的做法
3 个解决方案
#1
2
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:
首先,我假设我们正在讨论专门针对您网站的攻击。 (如果我们谈论的是那些只是漫游并提交各种形式的机器人,这不仅会阻止它们,而且还有更好,更简单的方法。)如果是这样的话,那我就是针对我的网站,这是我的机器人会做的事情:
- Load form page.
- 加载表单页面。
- Read token on form page.
- 在表单页面上读取令牌。
- Submit automated request with that token.
- 使用该令牌提交自动请求。
- Go to step 1.
- 转到第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.)
(或者,如果我对你的系统进行了足够的调查,我会意识到,如果我在每个请求中包含“这是AJAX”标头,我可以永久保留一个令牌。或者我会意识到令牌是我的会话ID,并且发送我自己的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.
这种在每个页面加载时更改令牌的方法绝对不能阻止那些真正想要攻击你的人。因此,由于令牌对自动化没有影响,请关注其对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.
从阻止CSRF的角度来看,创建一个令牌并维护它直到用户关闭浏览器似乎可以实现所有目标。简单的CSRF攻击失败,用户可以打开多个选项卡。
TL;DR: Refreshing the token once on each request doesn't boost security. Go for usability and do one token per session.
TL; DR:每次请求刷新令牌一次不会提高安全性。寻求可用性并在每个会话中执行一个令牌。
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.
第一个令牌将保持不变,直到浏览器会话结束。此令牌用于防止CSRF攻击。此用户使用此令牌提交的任何内容都将被接受。
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.
这样,如果我打开表格A的标签和表格B的标签,每个人都有我的个人反CSRF令牌(CSRF照顾),以及我的一次性表格令牌(表格重新提交照顾)。解决这两个问题对用户体验没有任何不良影响。
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.
当然,你可能会认为实现这么简单的功能太过分了。无论如何,我认为它是。无论如何,如果您需要,都可以使用可靠的解决方案。
#2
1
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).
如果你试图阻止一个客户端DoS你,一个不常见但可行的策略是在请求中包含一个hashcash令牌(已经有PHP和JavaScript实现)。
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.
为了防止破坏选项卡式浏览和返回按钮,理想情况下,您希望hashcash令牌的挑战包含每会话防伪标记和为每个请求新生成的唯一性部分。如果您有一个很大的令牌成本,为了尽量减少对可用性的影响,一旦您花费了前一个令牌,就开始预先计算页面中的下一个令牌。
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.
这样做会限制客户端生成有效请求的速率,因为每个hashcash令牌只能使用一次(这意味着您需要保留一个附加到会话的有效,已经用完的hashcash令牌的缓存,以防止无限重用(单个令牌),它们不能在会话开始之前计算(因为随机防伪值),并且生成每个新的有效令牌需要花费大量的CPU时间,但只需要很少的时间验证一个。
While this doesn't prevent automation of your AJAX API per se, it does constrain high-volume hammering of the API.
虽然这并不妨碍您的AJAX API本身的自动化,但它确实限制了API的高容量锤击。
#3
1
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.
这可能以与常规请求相同的方式解决。每页加载一个令牌并停止新选项卡可能过度。当然,每个表单的时间敏感令牌可以在某种程度上缓解CSRF攻击。但除此之外,最好定义和实现提交策略引擎,而不是限制用户体验。
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.
冒着让所有人听起来浮夸或贬低的风险:通常网站使用基于积分的奖励系统,例如“业力”或“徽章”。这样的系统实际上增加了用户体验,因为提交然后成为用户的一种游戏。他们可能经常限制将提交仅发布给受信任的用户或在给定时间范围内发布最大数量的能力。看一下SO系统的好用例。
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.
- 如果用户在过去的y分钟内超过了x个帖子的数量,则拒绝数据库插入并显示“抱歉,自上次发布后很快”警告。这可以通过在允许新记录插入之前在给定的最近时间段内向DB查询用户的帖子数来实现。
- 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.
- 如果用户没有特定的业力阈值 - 例如,新用户或反复标记为垃圾邮件发送者的用户 - 拒绝DB写入并显示“抱歉,您没有在这里足够长时间”或“抱歉,您也是垃圾邮件”很多“警告。这可以通过在允许新记录插入之前向DB查询总共用户的“业力”来实现,该业务在单独的表或站点模块中管理。
- 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.
在关于“http header stuff”的注释中,标题仅用于最好的猜测,并且客户要求提供礼貌。它们与饼干一样难以伪造,锻造饼干只需点击鼠标即可。老实说,我个人不会有任何其他方式。
#1
2
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:
首先,我假设我们正在讨论专门针对您网站的攻击。 (如果我们谈论的是那些只是漫游并提交各种形式的机器人,这不仅会阻止它们,而且还有更好,更简单的方法。)如果是这样的话,那我就是针对我的网站,这是我的机器人会做的事情:
- Load form page.
- 加载表单页面。
- Read token on form page.
- 在表单页面上读取令牌。
- Submit automated request with that token.
- 使用该令牌提交自动请求。
- Go to step 1.
- 转到第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.)
(或者,如果我对你的系统进行了足够的调查,我会意识到,如果我在每个请求中包含“这是AJAX”标头,我可以永久保留一个令牌。或者我会意识到令牌是我的会话ID,并且发送我自己的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.
这种在每个页面加载时更改令牌的方法绝对不能阻止那些真正想要攻击你的人。因此,由于令牌对自动化没有影响,请关注其对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.
从阻止CSRF的角度来看,创建一个令牌并维护它直到用户关闭浏览器似乎可以实现所有目标。简单的CSRF攻击失败,用户可以打开多个选项卡。
TL;DR: Refreshing the token once on each request doesn't boost security. Go for usability and do one token per session.
TL; DR:每次请求刷新令牌一次不会提高安全性。寻求可用性并在每个会话中执行一个令牌。
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.
第一个令牌将保持不变,直到浏览器会话结束。此令牌用于防止CSRF攻击。此用户使用此令牌提交的任何内容都将被接受。
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.
这样,如果我打开表格A的标签和表格B的标签,每个人都有我的个人反CSRF令牌(CSRF照顾),以及我的一次性表格令牌(表格重新提交照顾)。解决这两个问题对用户体验没有任何不良影响。
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.
当然,你可能会认为实现这么简单的功能太过分了。无论如何,我认为它是。无论如何,如果您需要,都可以使用可靠的解决方案。
#2
1
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).
如果你试图阻止一个客户端DoS你,一个不常见但可行的策略是在请求中包含一个hashcash令牌(已经有PHP和JavaScript实现)。
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.
为了防止破坏选项卡式浏览和返回按钮,理想情况下,您希望hashcash令牌的挑战包含每会话防伪标记和为每个请求新生成的唯一性部分。如果您有一个很大的令牌成本,为了尽量减少对可用性的影响,一旦您花费了前一个令牌,就开始预先计算页面中的下一个令牌。
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.
这样做会限制客户端生成有效请求的速率,因为每个hashcash令牌只能使用一次(这意味着您需要保留一个附加到会话的有效,已经用完的hashcash令牌的缓存,以防止无限重用(单个令牌),它们不能在会话开始之前计算(因为随机防伪值),并且生成每个新的有效令牌需要花费大量的CPU时间,但只需要很少的时间验证一个。
While this doesn't prevent automation of your AJAX API per se, it does constrain high-volume hammering of the API.
虽然这并不妨碍您的AJAX API本身的自动化,但它确实限制了API的高容量锤击。
#3
1
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.
这可能以与常规请求相同的方式解决。每页加载一个令牌并停止新选项卡可能过度。当然,每个表单的时间敏感令牌可以在某种程度上缓解CSRF攻击。但除此之外,最好定义和实现提交策略引擎,而不是限制用户体验。
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.
冒着让所有人听起来浮夸或贬低的风险:通常网站使用基于积分的奖励系统,例如“业力”或“徽章”。这样的系统实际上增加了用户体验,因为提交然后成为用户的一种游戏。他们可能经常限制将提交仅发布给受信任的用户或在给定时间范围内发布最大数量的能力。看一下SO系统的好用例。
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.
- 如果用户在过去的y分钟内超过了x个帖子的数量,则拒绝数据库插入并显示“抱歉,自上次发布后很快”警告。这可以通过在允许新记录插入之前在给定的最近时间段内向DB查询用户的帖子数来实现。
- 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.
- 如果用户没有特定的业力阈值 - 例如,新用户或反复标记为垃圾邮件发送者的用户 - 拒绝DB写入并显示“抱歉,您没有在这里足够长时间”或“抱歉,您也是垃圾邮件”很多“警告。这可以通过在允许新记录插入之前向DB查询总共用户的“业力”来实现,该业务在单独的表或站点模块中管理。
- 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.
在关于“http header stuff”的注释中,标题仅用于最好的猜测,并且客户要求提供礼貌。它们与饼干一样难以伪造,锻造饼干只需点击鼠标即可。老实说,我个人不会有任何其他方式。