1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2025-02-22 19:49:02 +01:00
phorge-phorge/src/applications/system/action/PhabricatorSystemAction.php
epriestley 847b7977c1 Add semi-generic rate limiting infrastructure
Summary:
This adds a system which basically keeps a record of recent actions, who took them, and how many "points" they were worth, like:

  epriestley email.add 1 1233989813
  epriestley email.add 1 1234298239
  epriestley email.add 1 1238293981

We can use this to rate-limit actions by examining how many actions the user has taken in the past hour (i.e., their total score) and comparing that to an allowed limit.

One major thing I want to use this for is to limit the amount of error email we'll send to an email address. A big concern I have with sending more error email is that we'll end up in loops. We have some protections against this in headers already, but hard-limiting the system so it won't send more than a few errors to a particular address per hour should provide a reasonable secondary layer of protection.

This use case (where the "actor" needs to be an email address) is why the table uses strings + hashes instead of PHIDs. For external users, it might be appropriate to rate limit by cookies or IPs, too.

To prove it works, I rate limited adding email addresses. This is a very, very low-risk security thing where a user with an account can enumerate addresses (by checking if they get an error) and sort of spam/annoy people (by adding their address over and over again). Limiting them to 6 actions / hour should satisfy all real users while preventing these behaviors.

Test Plan:
This dialog is uggos but I'll fix that in a sec:

{F137406}

Reviewers: btrahan

Reviewed By: btrahan

Subscribers: epriestley

Differential Revision: https://secure.phabricator.com/D8683
2014-04-03 11:22:38 -07:00

40 lines
978 B
PHP

<?php
abstract class PhabricatorSystemAction {
abstract public function getActionConstant();
abstract public function getScoreThreshold();
public function shouldBlockActor($actor, $score) {
return ($score > $this->getScoreThreshold());
}
public function getLimitExplanation() {
return pht('You are performing too many actions too quickly.');
}
public function getRateExplanation($score) {
return pht(
'The maximum allowed rate for this action is %s. You are taking '.
'actions at a rate of %s.',
$this->formatRate($this->getScoreThreshold()),
$this->formatRate($score));
}
protected function formatRate($rate) {
if ($rate > 10) {
$str = pht('%d / second', $rate);
} else {
$rate *= 60;
if ($rate > 10) {
$str = pht('%d / minute', $rate);
} else {
$rate *= 60;
$str = pht('%d / hour', $rate);
}
}
return phutil_tag('strong', array(), $str);
}
}