Fundraising/tech/Spikes/Fundraiser 2012 412
Contents |
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.