Obsolete:Fundraising/tech/Spikes/Fundraiser 2012 412
Fundraising 2012 spike #412
See the spike #412 in mingle.
We have need of an IPA velocity filter for DonationInterface.
The AbuseFilter extension handles IP ranges; however, the tool they are using is Mediawiki's IP class.
As it turns it may not need very mush special code as this will just be doing a count from a database to obtain a rate from a time interval.
Requirements
- define a limit of transactions per time interval for repeat IPAs
- it would be helpful if a risk score was saved with each record
- it might need the contribution tracking id
- whitelist, blacklist and rate editable in LocalSettings
- DO NOT VIOLATE PCI COMPLIANCE with storing to much information :)
Schema changes
This would require a table that would have the following fields:
- `id` INTEGER
- `ipa` INTEGER 4 bytes
- `risk_score` DOUBLE
- `contribution_tracking_id`
- `created` DATETIME
It might be helpful to have built in garbage collection that deletes data after a specified lifetime.
This would prevent the table from growing to large over the course of a campaign.
Example as a filter function
This is an example of how to run an IP velocity filter as a custom filter function.
/**
* This custom filter function checks the global variable:
*
* IpaMap
*
* How the score is tabulated:
* - If a IPA is blacklisted, a score of 100 will be generated. No further checks.
* - If a IPA is whitelisted, a score of zero will be generated. No further checks.
* - If a limit is defined, then count the occurences and generate a score.
* - Returns an integer: 0 <= $score <= 100
*
* @see GatewayAdapter::$debugarray
* @see GatewayAdapter::log()
*
* @see $wgDonationInterfaceCustomFiltersFunctions
* @see $wgDonationInterfaceIpaMap
*
* @return integer
*/
public function getScoreIpaMap() {
// The score to return
$score = 0;
// Perform a check to generate a score
$check = true;
$ipa = wfGetIP();
$ipaMap = $this->getGlobal( 'IpaMap' );
$msg = self::getGatewayName() . ': IPA map: '
. print_r( $ipaMap, true );
$this->log( $msg, LOG_DEBUG );
// Lookup blacklist
if ( $check && isset( $ipaMap['blacklist'] ) ) {
if ( in_array( $ipa, $ipaMap['blacklist'] ) ) {
$score = 100;
$check = false;
}
}
// Lookup whitelist
if ( $check && isset( $ipaMap['whitelist'] ) ) {
if ( in_array( $ipa, $ipaMap['whitelist'] ) ) {
$score = 0;
$check = false;
}
}
// Lookup the IPA in the database and calculate the score.
if ( $check ) {
$score = $this->getIpaCountScore( $ipa, $ipaMap );
}
// Save the IPA in the database
$this->recordIpa( $ipa );
// @see $wgDonationInterfaceDisplayDebug
$this->debugarray[] = 'custom filters function: get ipa [ '
. $ipa . ' ] map score = ' . $score;
return $score;
}
Filtering by cidr notation
It might be helpful to whitelist or blacklist countries by cidr notation using the IP class
IP::isInRange( $ipa, '192.0.2.0/24')
Implementing this as a firewall
It is also possible to put this higher up in the stack to prevent a form from being displayed due to repeat attacks by the same IPA.