Wordfence Security – Firewall & Malware Scan - Version 3.0.5

Version Description

  • Fixed "The key used to start a scan has expired." error and added data to help diagnose future issues like this.
  • Removed HTTPHeaders from wfHits table which was using a lot of disk space and not used much.
  • Removed limiting wfHits table size because it was unreliable.
  • We're now limiting wfHits to 20,000 rows and the rows are much smaller. About 2 to 8 megs.
  • Fixed bug that could have caused install routine to run repeatedly.
  • Fixed typo bug in blocking code that didn't have any impact but was sloppy.
  • Changed wfscan.php message when accessed directly to be more helpful.
Download this release

Release Info

Developer mmaunder
Plugin Icon 128x128 Wordfence Security – Firewall & Malware Scan
Version 3.0.5
Comparing to
See all releases

Code changes from version 3.0.4 to 3.0.5

lib/IPTraf.php CHANGED
@@ -22,14 +22,6 @@
22
  <?php echo $v['loc']['countryName']; ?>
23
  </td></tr>
24
  <?php } ?>
25
- <tr><th>HTTP Headers:</th><td>
26
- <table border="0" class="HTTP">
27
- <?php foreach($v['HTTPHeaders'] as $key => $val){
28
- echo "<tr><th class=\"HTTP\">$key</th><td class=\"HTTP\">"."$val</td></tr>";
29
- }
30
- ?>
31
- </table>
32
- </td></tr>
33
  <tr><td colspan="2"><hr></td></tr>
34
  <?php } ?>
35
 
22
  <?php echo $v['loc']['countryName']; ?>
23
  </td></tr>
24
  <?php } ?>
 
 
 
 
 
 
 
 
25
  <tr><td colspan="2"><hr></td></tr>
26
  <?php } ?>
27
 
lib/menu_options.php CHANGED
@@ -62,7 +62,6 @@ var WFSLevels = <?php echo json_encode(wfConfig::$securityLevels); ?>;
62
  <tr><th>List of comma separated usernames to ignore:</th><td><input type="text" name="liveTraf_ignoreUsers" id="liveTraf_ignoreUsers" value="<?php echo $w->getHTML('liveTraf_ignoreUsers'); ?>" /></td></tr>
63
  <tr><th>List of comma separated IP addresses to ignore:</th><td><input type="text" name="liveTraf_ignoreIPs" id="liveTraf_ignoreIPs" value="<?php echo $w->getHTML('liveTraf_ignoreIPs'); ?>" /></td></tr>
64
  <tr><th>Browser user-agent to ignore:</th><td><input type="text" name="liveTraf_ignoreUA" id="liveTraf_ignoreUA" value="<?php echo $w->getHTML('liveTraf_ignoreUA'); ?>" /></td></tr>
65
- <tr><th>Limit size of hits table to</th><td><input type="text" name="liveTraf_hitsMaxSize" class="wfConfigElem" name="liveTraf_hitsMaxSize" value="<?php $w->f('liveTraf_hitsMaxSize'); ?>" size="6" />Megabytes</td></tr>
66
  <tr><td colspan="2"><h3 class="wfConfigHeading">Scans to include</h3></td></tr>
67
  <tr><th class="wfConfigEnable">Enable automatic scheduled scans</th><td><input type="checkbox" id="scheduledScansEnabled" class="wfConfigElem" name="scheduledScansEnabled" value="1" <?php $w->cb('scheduledScansEnabled'); ?> /></td></tr>
68
  <tr><th>Scan core files against repository versions for changes</th><td><input type="checkbox" id="scansEnabled_core" class="wfConfigElem" name="scansEnabled_core" value="1" <?php $w->cb('scansEnabled_core'); ?>/></td></tr>
62
  <tr><th>List of comma separated usernames to ignore:</th><td><input type="text" name="liveTraf_ignoreUsers" id="liveTraf_ignoreUsers" value="<?php echo $w->getHTML('liveTraf_ignoreUsers'); ?>" /></td></tr>
63
  <tr><th>List of comma separated IP addresses to ignore:</th><td><input type="text" name="liveTraf_ignoreIPs" id="liveTraf_ignoreIPs" value="<?php echo $w->getHTML('liveTraf_ignoreIPs'); ?>" /></td></tr>
64
  <tr><th>Browser user-agent to ignore:</th><td><input type="text" name="liveTraf_ignoreUA" id="liveTraf_ignoreUA" value="<?php echo $w->getHTML('liveTraf_ignoreUA'); ?>" /></td></tr>
 
65
  <tr><td colspan="2"><h3 class="wfConfigHeading">Scans to include</h3></td></tr>
66
  <tr><th class="wfConfigEnable">Enable automatic scheduled scans</th><td><input type="checkbox" id="scheduledScansEnabled" class="wfConfigElem" name="scheduledScansEnabled" value="1" <?php $w->cb('scheduledScansEnabled'); ?> /></td></tr>
67
  <tr><th>Scan core files against repository versions for changes</th><td><input type="checkbox" id="scansEnabled_core" class="wfConfigElem" name="scansEnabled_core" value="1" <?php $w->cb('scansEnabled_core'); ?>/></td></tr>
lib/wfConfig.php CHANGED
@@ -48,7 +48,6 @@ class wfConfig {
48
  "otherParams" => array(
49
  'securityLevel' => '0',
50
  "alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '',
51
- "liveTraf_hitsMaxSize" => 10,
52
  "neverBlockBG" => "neverBlockVerified",
53
  "loginSec_countFailMins" => "5",
54
  "loginSec_lockoutMins" => "5",
@@ -111,7 +110,6 @@ class wfConfig {
111
  "otherParams" => array(
112
  'securityLevel' => '1',
113
  "alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '',
114
- "liveTraf_hitsMaxSize" => 10,
115
  "neverBlockBG" => "neverBlockVerified",
116
  "loginSec_countFailMins" => "5",
117
  "loginSec_lockoutMins" => "5",
@@ -174,7 +172,6 @@ class wfConfig {
174
  "otherParams" => array(
175
  'securityLevel' => '2',
176
  "alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '',
177
- "liveTraf_hitsMaxSize" => 10,
178
  "neverBlockBG" => "neverBlockVerified",
179
  "loginSec_countFailMins" => "240",
180
  "loginSec_lockoutMins" => "240",
@@ -237,7 +234,6 @@ class wfConfig {
237
  "otherParams" => array(
238
  'securityLevel' => '3',
239
  "alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '',
240
- "liveTraf_hitsMaxSize" => 10,
241
  "neverBlockBG" => "neverBlockVerified",
242
  "loginSec_countFailMins" => "1440",
243
  "loginSec_lockoutMins" => "1440",
@@ -300,7 +296,6 @@ class wfConfig {
300
  "otherParams" => array(
301
  'securityLevel' => '4',
302
  "alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '',
303
- "liveTraf_hitsMaxSize" => 10,
304
  "neverBlockBG" => "neverBlockVerified",
305
  "loginSec_countFailMins" => "1440",
306
  "loginSec_lockoutMins" => "1440",
48
  "otherParams" => array(
49
  'securityLevel' => '0',
50
  "alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '',
 
51
  "neverBlockBG" => "neverBlockVerified",
52
  "loginSec_countFailMins" => "5",
53
  "loginSec_lockoutMins" => "5",
110
  "otherParams" => array(
111
  'securityLevel' => '1',
112
  "alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '',
 
113
  "neverBlockBG" => "neverBlockVerified",
114
  "loginSec_countFailMins" => "5",
115
  "loginSec_lockoutMins" => "5",
172
  "otherParams" => array(
173
  'securityLevel' => '2',
174
  "alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '',
 
175
  "neverBlockBG" => "neverBlockVerified",
176
  "loginSec_countFailMins" => "240",
177
  "loginSec_lockoutMins" => "240",
234
  "otherParams" => array(
235
  'securityLevel' => '3',
236
  "alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '',
 
237
  "neverBlockBG" => "neverBlockVerified",
238
  "loginSec_countFailMins" => "1440",
239
  "loginSec_lockoutMins" => "1440",
296
  "otherParams" => array(
297
  'securityLevel' => '4',
298
  "alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '',
 
299
  "neverBlockBG" => "neverBlockVerified",
300
  "loginSec_countFailMins" => "1440",
301
  "loginSec_lockoutMins" => "1440",
lib/wfDB.php CHANGED
@@ -155,6 +155,22 @@ class wfDB {
155
  error_log($msg);
156
  return;
157
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158
  public function createKeyIfNotExists($table, $col, $keyName){
159
  global $wpdb; $prefix = $wpdb->base_prefix;
160
  $table = $prefix . $table;
155
  error_log($msg);
156
  return;
157
  }
158
+ public function columnExists($table, $col){
159
+ global $wpdb; $prefix = $wpdb->base_prefix;
160
+ $table = $prefix . $table;
161
+ $q = $this->query("desc $table");
162
+ while($row = mysql_fetch_assoc($q)){
163
+ if($row['Field'] == $col){
164
+ return true;
165
+ }
166
+ }
167
+ return false;
168
+ }
169
+ public function dropColumn($table, $col){
170
+ global $wpdb; $prefix = $wpdb->base_prefix;
171
+ $table = $prefix . $table;
172
+ $this->query("alter table $table drop column $col");
173
+ }
174
  public function createKeyIfNotExists($table, $col, $keyName){
175
  global $wpdb; $prefix = $wpdb->base_prefix;
176
  $table = $prefix . $table;
lib/wfLog.php CHANGED
@@ -280,7 +280,7 @@ class wfLog {
280
  $headers[$matches[1]] = $v;
281
  }
282
  }
283
- $this->getDB()->query("insert into " . $this->hitsTable . " (ctime, is404, isGoogle, IP, userID, newVisit, URL, referer, UA, HTTPHeaders) values (%f, %d, %d, %s, %s, %d, '%s', '%s', '%s', '%s')",
284
  sprintf('%.6f', microtime(true)),
285
  (is_404() ? 1 : 0),
286
  (wfCrawl::isGoogleCrawler() ? 1 : 0),
@@ -289,8 +289,7 @@ class wfLog {
289
  (wordfence::$newVisit ? 1 : 0),
290
  wfUtils::getRequestedURL(),
291
  (isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ''),
292
- (isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : ''),
293
- serialize($headers)
294
  );
295
  return $this->getDB()->querySingle("select last_insert_id()");
296
  }
@@ -345,9 +344,6 @@ class wfLog {
345
  $browscap = new wfBrowscap();
346
  foreach($results as &$res){
347
  $res['type'] = $type;
348
- if(isset($res['HTTPHeaders'])){
349
- $res['HTTPHeaders'] = unserialize($res['HTTPHeaders']);
350
- }
351
  $res['timeAgo'] = wfUtils::makeTimeAgo($serverTime - $res['ctime']);
352
  $res['blocked'] = $this->getDB()->querySingle("select blockedTime from " . $this->blocksTable . " where IP=%s and blockedTime + %s > unix_timestamp()", $res['IP'], wfConfig::get('blockedTime'));
353
  $res['IP'] = wfUtils::inet_ntoa($res['IP']);
@@ -476,10 +472,8 @@ class wfLog {
476
  public function firewallBadIPs(){
477
  $IP = wfUtils::inet_aton(wfUtils::getIP());
478
  if($rec = $this->getDB()->querySingleRec("select (blockedTime + %s) - unix_timestamp() as secsToGo, reason from " . $this->blocksTable . " where IP=%s and (permanent=1 OR blockedTime + %s > unix_timestamp())", wfConfig::get('blockedTime'), $IP, wfConfig::get('blockedTime'))){
479
- $secsToGo = $rec['secsToGo'];
480
- $reason = $rec[1];
481
  $this->getDB()->query("update " . $this->blocksTable . " set lastAttempt=unix_timestamp(), blockedHits = blockedHits + 1 where IP=%s", $IP);
482
- $this->do503($secsToGo, $rec['reason']);
483
  }
484
  }
485
  private function takeBlockingAction($configVar, $reason){
280
  $headers[$matches[1]] = $v;
281
  }
282
  }
283
+ $this->getDB()->query("insert into " . $this->hitsTable . " (ctime, is404, isGoogle, IP, userID, newVisit, URL, referer, UA) values (%f, %d, %d, %s, %s, %d, '%s', '%s', '%s')",
284
  sprintf('%.6f', microtime(true)),
285
  (is_404() ? 1 : 0),
286
  (wfCrawl::isGoogleCrawler() ? 1 : 0),
289
  (wordfence::$newVisit ? 1 : 0),
290
  wfUtils::getRequestedURL(),
291
  (isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ''),
292
+ (isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '')
 
293
  );
294
  return $this->getDB()->querySingle("select last_insert_id()");
295
  }
344
  $browscap = new wfBrowscap();
345
  foreach($results as &$res){
346
  $res['type'] = $type;
 
 
 
347
  $res['timeAgo'] = wfUtils::makeTimeAgo($serverTime - $res['ctime']);
348
  $res['blocked'] = $this->getDB()->querySingle("select blockedTime from " . $this->blocksTable . " where IP=%s and blockedTime + %s > unix_timestamp()", $res['IP'], wfConfig::get('blockedTime'));
349
  $res['IP'] = wfUtils::inet_ntoa($res['IP']);
472
  public function firewallBadIPs(){
473
  $IP = wfUtils::inet_aton(wfUtils::getIP());
474
  if($rec = $this->getDB()->querySingleRec("select (blockedTime + %s) - unix_timestamp() as secsToGo, reason from " . $this->blocksTable . " where IP=%s and (permanent=1 OR blockedTime + %s > unix_timestamp())", wfConfig::get('blockedTime'), $IP, wfConfig::get('blockedTime'))){
 
 
475
  $this->getDB()->query("update " . $this->blocksTable . " set lastAttempt=unix_timestamp(), blockedHits = blockedHits + 1 where IP=%s", $IP);
476
+ $this->do503($rec['secsToGo'], $rec['reason']);
477
  }
478
  }
479
  private function takeBlockingAction($configVar, $reason){
lib/wfSchema.php CHANGED
@@ -52,7 +52,6 @@ class wfSchema {
52
  URL text,
53
  referer text,
54
  UA text,
55
- HTTPHeaders text,
56
  KEY k1(ctime),
57
  KEY k2(IP, ctime)
58
  ) default charset=latin1",
52
  URL text,
53
  referer text,
54
  UA text,
 
55
  KEY k1(ctime),
56
  KEY k2(IP, ctime)
57
  ) default charset=latin1",
lib/wordfenceClass.php CHANGED
@@ -116,25 +116,10 @@ class wordfence {
116
  $wfdb->query("delete from $p"."wfBlocks where blockedTime + %s < unix_timestamp() and permanent=0", wfConfig::get('blockedTime'));
117
  $wfdb->query("delete from $p"."wfCrawlers where lastUpdate < unix_timestamp() - (86400 * 7)");
118
 
119
- if(wfConfig::get('liveTraf_hitsMaxSize') && wfConfig::get('liveTraf_hitsMaxSize') > 0){
120
- $gotTableSize = false;
121
- $tableSizeQ = $wfdb->query("show table status like '$p"."wfHits'");
122
- if($tableSizeQ){
123
- $tableSizeRec = mysql_fetch_assoc($tableSizeQ);
124
- if($tableSizeRec && isset($tableSizeRec['Data_length']) && $tableSizeRec['Data_length'] > 0){
125
- $gotTableSize = true;
126
- if($tableSizeRec['Data_length'] > (wfConfig::get('liveTraf_hitsMaxSize') * 1024 * 1024) ){ //convert to bytes
127
- $count = $wfdb->querySingle("select count(*) as cnt from $p"."wfHits");
128
- $wfdb->query("delete from $p"."wfHits order by id asc limit %d", floor($count / 10)); //Delete 10% of rows. If we're still bigger than max, then next delete will reduce by further 10% and so on.
129
- }
130
- }
131
- } else {
132
- error_log("Wordfence could not get wfHits table data size for cleanup. Query returned false.");
133
- }
134
  }
135
-
136
-
137
-
138
  $maxRows = 1000; //affects stuff further down too
139
  foreach(array('wfLeechers', 'wfScanners') as $table){
140
  //This is time based per IP so shouldn't get too big
@@ -167,6 +152,7 @@ class wordfence {
167
 
168
  }
169
  public static function runInstall(){
 
170
  //EVERYTHING HERE MUST BE IDEMPOTENT
171
  $schema = new wfSchema();
172
  $schema->createAll(); //if not exists
@@ -192,6 +178,16 @@ class wordfence {
192
  wp_schedule_event(time(), 'hourly', 'wordfence_hourly_cron');
193
  $db = new wfDB();
194
 
 
 
 
 
 
 
 
 
 
 
195
  //Upgrading from 1.5.6 or earlier needs:
196
  $db->createKeyIfNotExists('wfStatus', 'level', 'k2');
197
  if(wfConfig::get('isPaid') == 'free'){
@@ -214,7 +210,6 @@ class wordfence {
214
  $db->queryIgnoreError("alter table $prefix"."wfStatus modify column msg varchar(1000) NOT NULL");
215
 
216
  //Must be the final line
217
- update_option('wordfence_version', WORDFENCE_VERSION);
218
  }
219
  public static function install_actions(){
220
  $versionInOptions = get_option('wordfence_version', false);
@@ -240,9 +235,7 @@ class wordfence {
240
  add_action('wp_logout','wordfence::logoutAction');
241
  add_action('profile_update', 'wordfence::profileUpdateAction', '99', 2);
242
  add_action('lostpassword_post', 'wordfence::lostPasswordPost', '1');
243
- /* For testing cron jobs
244
- add_filter('cron_schedules', 'wordfence::moreCronReccurences');
245
- */
246
  add_filter('pre_comment_approved', 'wordfence::preCommentApprovedFilter', '99', 2);
247
  add_filter('authenticate', 'wordfence::authenticateFilter', 99, 3);
248
  //html|xhtml|atom|rss2|rdf|comment|export
@@ -1342,10 +1335,10 @@ class wordfence {
1342
  }
1343
  return self::$debugOn;
1344
  }
1345
- /* For testing cron jobs
1346
  public static function moreCronReccurences(){
1347
  return array(
1348
- Feveryminute' => array('interval' => 60, 'display' => 'Once Every Minute'),
1349
  );
1350
  }
1351
  */
116
  $wfdb->query("delete from $p"."wfBlocks where blockedTime + %s < unix_timestamp() and permanent=0", wfConfig::get('blockedTime'));
117
  $wfdb->query("delete from $p"."wfCrawlers where lastUpdate < unix_timestamp() - (86400 * 7)");
118
 
119
+ $count = $wfdb->querySingle("select count(*) as cnt from $p"."wfHits");
120
+ if($count > 20000){
121
+ $wfdb->query("delete from $p"."wfHits order by id asc limit " . ($count - 20000));
 
 
 
 
 
 
 
 
 
 
 
 
122
  }
 
 
 
123
  $maxRows = 1000; //affects stuff further down too
124
  foreach(array('wfLeechers', 'wfScanners') as $table){
125
  //This is time based per IP so shouldn't get too big
152
 
153
  }
154
  public static function runInstall(){
155
+ update_option('wordfence_version', WORDFENCE_VERSION); //In case we have a fatal error we don't want to keep running install.
156
  //EVERYTHING HERE MUST BE IDEMPOTENT
157
  $schema = new wfSchema();
158
  $schema->createAll(); //if not exists
178
  wp_schedule_event(time(), 'hourly', 'wordfence_hourly_cron');
179
  $db = new wfDB();
180
 
181
+ if($db->columnExists('wfHits', 'HTTPHeaders')){ //Upgrade from 3.0.4
182
+ global $wpdb;
183
+ $prefix = $wpdb->base_prefix;
184
+ $count = $db->querySingle("select count(*) as cnt from $prefix"."wfHits");
185
+ if($count > 20000){
186
+ $db->query("delete from $prefix"."wfHits order by id asc limit " . ($count - 20000));
187
+ }
188
+ $db->dropColumn('wfHits', 'HTTPHeaders');
189
+ }
190
+
191
  //Upgrading from 1.5.6 or earlier needs:
192
  $db->createKeyIfNotExists('wfStatus', 'level', 'k2');
193
  if(wfConfig::get('isPaid') == 'free'){
210
  $db->queryIgnoreError("alter table $prefix"."wfStatus modify column msg varchar(1000) NOT NULL");
211
 
212
  //Must be the final line
 
213
  }
214
  public static function install_actions(){
215
  $versionInOptions = get_option('wordfence_version', false);
235
  add_action('wp_logout','wordfence::logoutAction');
236
  add_action('profile_update', 'wordfence::profileUpdateAction', '99', 2);
237
  add_action('lostpassword_post', 'wordfence::lostPasswordPost', '1');
238
+ //add_filter('cron_schedules', 'wordfence::moreCronReccurences');
 
 
239
  add_filter('pre_comment_approved', 'wordfence::preCommentApprovedFilter', '99', 2);
240
  add_filter('authenticate', 'wordfence::authenticateFilter', 99, 3);
241
  //html|xhtml|atom|rss2|rdf|comment|export
1335
  }
1336
  return self::$debugOn;
1337
  }
1338
+ /*
1339
  public static function moreCronReccurences(){
1340
  return array(
1341
+ 'everyminute' => array('interval' => 60, 'display' => 'Once Every Minute'),
1342
  );
1343
  }
1344
  */
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: mmaunder
3
  Tags: wordpress, security, wordpress security, security plugin, secure, anti-virus, malware, firewall, antivirus, virus, google safe browsing, phishing, scrapers, hacking, wordfence, securty, secrity, secure
4
  Requires at least: 3.3.1
5
  Tested up to: 3.4.1
6
- Stable tag: 3.0.4
7
 
8
  Wordfence Security is a free enterprise class security plugin that includes a firewall, virus scanning, real-time traffic with geolocation and more.
9
 
@@ -152,6 +152,15 @@ or a theme, because often these have been updated to fix a security hole.
152
  5. If you're technically minded, this is the under-the-hood view of Wordfence options where you can fine-tune your security settings.
153
 
154
  == Changelog ==
 
 
 
 
 
 
 
 
 
155
  = 3.0.4 =
156
  * Detects if the Wordfence app (not scanner) is short on memory and requests more
157
  * Fixes an issue where scan breaks if all scanning options are disabled
3
  Tags: wordpress, security, wordpress security, security plugin, secure, anti-virus, malware, firewall, antivirus, virus, google safe browsing, phishing, scrapers, hacking, wordfence, securty, secrity, secure
4
  Requires at least: 3.3.1
5
  Tested up to: 3.4.1
6
+ Stable tag: 3.0.5
7
 
8
  Wordfence Security is a free enterprise class security plugin that includes a firewall, virus scanning, real-time traffic with geolocation and more.
9
 
152
  5. If you're technically minded, this is the under-the-hood view of Wordfence options where you can fine-tune your security settings.
153
 
154
  == Changelog ==
155
+ = 3.0.5 =
156
+ * Fixed "The key used to start a scan has expired." error and added data to help diagnose future issues like this.
157
+ * Removed HTTPHeaders from wfHits table which was using a lot of disk space and not used much.
158
+ * Removed limiting wfHits table size because it was unreliable.
159
+ * We're now limiting wfHits to 20,000 rows and the rows are much smaller. About 2 to 8 megs.
160
+ * Fixed bug that could have caused install routine to run repeatedly.
161
+ * Fixed typo bug in blocking code that didn't have any impact but was sloppy.
162
+ * Changed wfscan.php message when accessed directly to be more helpful.
163
+
164
  = 3.0.4 =
165
  * Detects if the Wordfence app (not scanner) is short on memory and requests more
166
  * Fixes an issue where scan breaks if all scanning options are disabled
wfscan.php CHANGED
@@ -47,7 +47,9 @@ class wfScan {
47
  wordfence::status(4, 'info', "Scan engine received request.");
48
  wordfence::status(4, 'info', "Checking cronkey header");
49
  if(! $_SERVER['HTTP_X_WORDFENCE_CRONKEY']){
50
- self::errorExit("The Wordfence scanner did not receive the x_wordfence_cronkey secure header.");
 
 
51
  }
52
  wordfence::status(4, 'info', "Fetching stored cronkey for comparison.");
53
  $currentCronKey = wfConfig::get('currentCronKey', false);
@@ -57,8 +59,8 @@ class wfScan {
57
 
58
  wordfence::status(4, 'info', "Exploding stored cronkey");
59
  $savedKey = explode(',',$currentCronKey);
60
- if(time() - $savedKey[0] > 60){
61
- self::errorExit("The key used to start a scan has expired.");
62
  } //keys only last 60 seconds and are used within milliseconds of creation
63
  wordfence::status(4, 'info', "Checking saved cronkey against cronkey header");
64
  if($savedKey[1] != $_SERVER['HTTP_X_WORDFENCE_CRONKEY']){
47
  wordfence::status(4, 'info', "Scan engine received request.");
48
  wordfence::status(4, 'info', "Checking cronkey header");
49
  if(! $_SERVER['HTTP_X_WORDFENCE_CRONKEY']){
50
+ wordfence::status(2, 'error', "Wordfence wfscan.php accessed directly, or WF did not receive the secure HTTP header.");
51
+ echo "If you see this message it means Wordfence is working correctly. You should not access this URL directly. It is part of the Wordfence security plugin and is designed for internal use only.";
52
+ exit();
53
  }
54
  wordfence::status(4, 'info', "Fetching stored cronkey for comparison.");
55
  $currentCronKey = wfConfig::get('currentCronKey', false);
59
 
60
  wordfence::status(4, 'info', "Exploding stored cronkey");
61
  $savedKey = explode(',',$currentCronKey);
62
+ if(time() - $savedKey[0] > 86400){
63
+ self::errorExit("The key used to start a scan expired. The value is: " . $savedKey[0] . " and split is: " . $currentCronKey . " and time is: " . time());
64
  } //keys only last 60 seconds and are used within milliseconds of creation
65
  wordfence::status(4, 'info', "Checking saved cronkey against cronkey header");
66
  if($savedKey[1] != $_SERVER['HTTP_X_WORDFENCE_CRONKEY']){
wordfence.php CHANGED
@@ -4,10 +4,10 @@ Plugin Name: Wordfence Security
4
  Plugin URI: http://wordfence.com/
5
  Description: Wordfence Security - Anti-virus and Firewall security plugin for WordPress
6
  Author: Mark Maunder
7
- Version: 3.0.4
8
  Author URI: http://wordfence.com/
9
  */
10
- define('WORDFENCE_VERSION', '3.0.4');
11
  if(! defined('WORDFENCE_VERSIONONLY_MODE')){
12
  if((int) @ini_get('memory_limit') < 64){
13
  @ini_set('memory_limit', '64M'); //Some hosts have ini set at as little as 32 megs. 64 is the min sane amount of memory.
4
  Plugin URI: http://wordfence.com/
5
  Description: Wordfence Security - Anti-virus and Firewall security plugin for WordPress
6
  Author: Mark Maunder
7
+ Version: 3.0.5
8
  Author URI: http://wordfence.com/
9
  */
10
+ define('WORDFENCE_VERSION', '3.0.5');
11
  if(! defined('WORDFENCE_VERSIONONLY_MODE')){
12
  if((int) @ini_get('memory_limit') < 64){
13
  @ini_set('memory_limit', '64M'); //Some hosts have ini set at as little as 32 megs. 64 is the min sane amount of memory.