Wordfence Security – Firewall & Malware Scan - Version 2.0.6

Version Description

  • Added IP whitelisting including ability to whitelist ranges that are excluded from firewall and login security measures.
  • RFC1918 private networks and loopback address is automatically whitelisted to prevent firewall or login security blocking internal routers and proxy servers, internal firewalls and internal users.
  • Added WORDFENCE_VERSION constant to improve version lookup performance.
  • Fixed issue that caused security scans to not start and humans to not be logged in live traffic. Wordfence makes security scan script and visitors script executable on install or upgrade now.
  • Fixed bug that caused disk space scanning to still show an issue found in security scan summary even when user chooses to ignore the security issue.
  • Made disk space thresholds 1 and 1.5% space remaining because many hosts have very large disks where 1% is gigabytes.
  • Made wordfence database handle cache deal with concurrent connections to different databases.
  • Improved Wordfence database library's error reporting.
  • Improved performance when Wordfence looks up it's own version during security scans and other operations.
  • Removed three rules in base wordfence htaccess that could cause 500 errors on servers that don't allow these options to be overridden. Does not affect htaccess security because we inherit the base htaccess and still protect our lib/ directory with our own htaccess.
Download this release

Release Info

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

Code changes from version 2.0.5 to 2.0.6

.htaccess CHANGED
@@ -26,6 +26,4 @@ Deny From All
26
  Order Allow,Deny
27
  Deny From All
28
  </Files>
29
- DirectoryIndex index.html
30
- IndexIgnore *
31
- Options -Indexes
26
  Order Allow,Deny
27
  Deny From All
28
  </Files>
29
+
 
 
lib/IPTraf.php CHANGED
@@ -2,7 +2,7 @@
2
  <html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" lang="en-US">
3
  <head>
4
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
5
- <link rel='stylesheet' id='wordfence-main-style-css' href='<?php echo wfUtils::getBaseURL(); ?>/css/iptraf.css?ver=<?php echo wfUtils::myVersion(); ?>' type='text/css' media='all' />
6
  <body>
7
  <h1>Wordfence: All recent hits for IP address <?php echo $IP; if($reverseLookup){ echo '[' . $reverseLookup . ']'; } ?></h1>
8
  <table border="0" cellpadding="2" cellspacing="0" style="width: 900px;">
2
  <html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" lang="en-US">
3
  <head>
4
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
5
+ <link rel='stylesheet' id='wordfence-main-style-css' href='<?php echo wfUtils::getBaseURL(); ?>/css/iptraf.css?ver=<?php echo WORDFENCE_VERSION; ?>' type='text/css' media='all' />
6
  <body>
7
  <h1>Wordfence: All recent hits for IP address <?php echo $IP; if($reverseLookup){ echo '[' . $reverseLookup . ']'; } ?></h1>
8
  <table border="0" cellpadding="2" cellspacing="0" style="width: 900px;">
lib/diffResult.php CHANGED
@@ -2,7 +2,7 @@
2
  <html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" lang="en-US">
3
  <head>
4
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
5
- <link rel='stylesheet' id='wordfence-main-style-css' href='<?php echo wfUtils::getBaseURL(); ?>/css/diff.css?ver=<?php echo wfUtils::myVersion(); ?>' type='text/css' media='all' />
6
  <body>
7
  <h1>Wordfence: Viewing File Differences</h1>
8
  <p style="width: 800px; font-size: 16px; font-family: Verdana;">
2
  <html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" lang="en-US">
3
  <head>
4
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
5
+ <link rel='stylesheet' id='wordfence-main-style-css' href='<?php echo wfUtils::getBaseURL(); ?>/css/diff.css?ver=<?php echo WORDFENCE_VERSION; ?>' type='text/css' media='all' />
6
  <body>
7
  <h1>Wordfence: Viewing File Differences</h1>
8
  <p style="width: 800px; font-size: 16px; font-family: Verdana;">
lib/menu_options.php CHANGED
@@ -198,6 +198,8 @@ var WFSLevels = <?php echo json_encode(wfConfig::$securityLevels); ?>;
198
  <tr><th>Immediately lock out invalid usernames</th><td><input type="checkbox" id="loginSec_lockInvalidUsers" class="wfConfigElem" name="loginSec_lockInvalidUsers" <?php $w->cb('loginSec_lockInvalidUsers'); ?> /></td></tr>
199
  <tr><th>Don't let WordPress reveal valid users in login errors</th><td><input type="checkbox" id="loginSec_maskLoginErrors" class="wfConfigElem" name="loginSec_maskLoginErrors" <?php $w->cb('loginSec_maskLoginErrors'); ?> /></td></tr>
200
  <tr><td colspan="2"><h3 class="wfConfigHeading">Other Options</h3></td></tr>
 
 
201
  <tr><th>Hide WordPress version</th><td><input type="checkbox" id="other_hideWPVersion" class="wfConfigElem" name="other_hideWPVersion" value="1" <?php $w->cb('other_hideWPVersion'); ?> /></td></tr>
202
  <tr><th>Hold anonymous comments using member emails for moderation</th><td><input type="checkbox" id="other_noAnonMemberComments" class="wfConfigElem" name="other_noAnonMemberComments" value="1" <?php $w->cb('other_noAnonMemberComments'); ?> /></td></tr>
203
  <tr><th>Scan comments for malware and phishing URL's</th><td><input type="checkbox" id="other_scanComments" class="wfConfigElem" name="other_scanComments" value="1" <?php $w->cb('other_scanComments'); ?> /></td></tr>
198
  <tr><th>Immediately lock out invalid usernames</th><td><input type="checkbox" id="loginSec_lockInvalidUsers" class="wfConfigElem" name="loginSec_lockInvalidUsers" <?php $w->cb('loginSec_lockInvalidUsers'); ?> /></td></tr>
199
  <tr><th>Don't let WordPress reveal valid users in login errors</th><td><input type="checkbox" id="loginSec_maskLoginErrors" class="wfConfigElem" name="loginSec_maskLoginErrors" <?php $w->cb('loginSec_maskLoginErrors'); ?> /></td></tr>
200
  <tr><td colspan="2"><h3 class="wfConfigHeading">Other Options</h3></td></tr>
201
+ <tr><th>Whitelisted IP addresses that bypass all rules:</th><td><input type="text" name="whitelisted" id="whitelisted" value="<?php echo $w->getHTML('whitelisted'); ?>" size="40" /></td></tr>
202
+ <tr><th colspan="2" style="color: #999;">Whitelisted IP's must be separated by commas. You can specify ranges using the following format: 123.23.34.[1-50]<br />Wordfence automatically whitelists <a href="http://en.wikipedia.org/wiki/Private_network" target="_blank">private networks</a> because these are not routable on the public Internet.<br /><br /></th></tr>
203
  <tr><th>Hide WordPress version</th><td><input type="checkbox" id="other_hideWPVersion" class="wfConfigElem" name="other_hideWPVersion" value="1" <?php $w->cb('other_hideWPVersion'); ?> /></td></tr>
204
  <tr><th>Hold anonymous comments using member emails for moderation</th><td><input type="checkbox" id="other_noAnonMemberComments" class="wfConfigElem" name="other_noAnonMemberComments" value="1" <?php $w->cb('other_noAnonMemberComments'); ?> /></td></tr>
205
  <tr><th>Scan comments for malware and phishing URL's</th><td><input type="checkbox" id="other_scanComments" class="wfConfigElem" name="other_scanComments" value="1" <?php $w->cb('other_scanComments'); ?> /></td></tr>
lib/sysinfo.php CHANGED
@@ -3,7 +3,7 @@
3
  <head>
4
  <title>Wordfence System Info</title>
5
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
6
- <link rel='stylesheet' id='wordfence-main-style-css' href='<?php echo wfUtils::getBaseURL(); ?>/css/phpinfo.css?ver=<?php echo wfUtils::myVersion(); ?>' type='text/css' media='all' />
7
  <body>
8
  <?php
9
  ob_start();
3
  <head>
4
  <title>Wordfence System Info</title>
5
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
6
+ <link rel='stylesheet' id='wordfence-main-style-css' href='<?php echo wfUtils::getBaseURL(); ?>/css/phpinfo.css?ver=<?php echo WORDFENCE_VERSION; ?>' type='text/css' media='all' />
7
  <body>
8
  <?php
9
  ob_start();
lib/viewFullActivityLog.php CHANGED
@@ -2,7 +2,7 @@
2
  <html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" lang="en-US">
3
  <head>
4
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
5
- <link rel='stylesheet' id='wordfence-main-style-css' href='<?php echo wfUtils::getBaseURL(); ?>/css/fullLog.css?ver=<?php echo wfUtils::myVersion(); ?>' type='text/css' media='all' />
6
  <style type="text/css">
7
 
8
  </style>
2
  <html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" lang="en-US">
3
  <head>
4
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
5
+ <link rel='stylesheet' id='wordfence-main-style-css' href='<?php echo wfUtils::getBaseURL(); ?>/css/fullLog.css?ver=<?php echo WORDFENCE_VERSION; ?>' type='text/css' media='all' />
6
  <style type="text/css">
7
 
8
  </style>
lib/wfAPI.php CHANGED
@@ -16,7 +16,7 @@ class wfAPI {
16
  }
17
  public function call($action, $getParams = array(), $postParams = array()){
18
  $this->errorMsg = false;
19
- $json = $this->getURL(WORDFENCE_API_URL . '/v' . WORDFENCE_VERSION . '/?' . $this->makeAPIQueryString() . '&' . http_build_query(
20
  array_merge(
21
  array('action' => $action),
22
  $getParams
@@ -88,7 +88,7 @@ class wfAPI {
88
  }
89
  public function binCall($func, $postData){
90
  $this->errorMsg = false;
91
- $url = WORDFENCE_API_URL . '/v' . WORDFENCE_VERSION . '/?' . $this->makeAPIQueryString() . '&action=' . $func;
92
  $curl = curl_init($url);
93
  curl_setopt ($curl, CURLOPT_TIMEOUT, 300);
94
  //curl_setopt($curl, CURLOPT_VERBOSE, true);
16
  }
17
  public function call($action, $getParams = array(), $postParams = array()){
18
  $this->errorMsg = false;
19
+ $json = $this->getURL(WORDFENCE_API_URL . '/v' . WORDFENCE_API_VERSION . '/?' . $this->makeAPIQueryString() . '&' . http_build_query(
20
  array_merge(
21
  array('action' => $action),
22
  $getParams
88
  }
89
  public function binCall($func, $postData){
90
  $this->errorMsg = false;
91
+ $url = WORDFENCE_API_URL . '/v' . WORDFENCE_API_VERSION . '/?' . $this->makeAPIQueryString() . '&action=' . $func;
92
  $curl = curl_init($url);
93
  curl_setopt ($curl, CURLOPT_TIMEOUT, 300);
94
  //curl_setopt($curl, CURLOPT_VERBOSE, true);
lib/wfConfig.php CHANGED
@@ -44,7 +44,7 @@ class wfConfig {
44
  ),
45
  "otherParams" => array(
46
  'securityLevel' => '0',
47
- "alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256',
48
  "liveTraf_hitsMaxSize" => 10,
49
  "neverBlockBG" => "neverBlockVerified",
50
  "loginSec_countFailMins" => "5",
@@ -106,7 +106,7 @@ class wfConfig {
106
  ),
107
  "otherParams" => array(
108
  'securityLevel' => '1',
109
- "alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256',
110
  "liveTraf_hitsMaxSize" => 10,
111
  "neverBlockBG" => "neverBlockVerified",
112
  "loginSec_countFailMins" => "5",
@@ -168,7 +168,7 @@ class wfConfig {
168
  ),
169
  "otherParams" => array(
170
  'securityLevel' => '2',
171
- "alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256',
172
  "liveTraf_hitsMaxSize" => 10,
173
  "neverBlockBG" => "neverBlockVerified",
174
  "loginSec_countFailMins" => "240",
@@ -230,7 +230,7 @@ class wfConfig {
230
  ),
231
  "otherParams" => array(
232
  'securityLevel' => '3',
233
- "alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256',
234
  "liveTraf_hitsMaxSize" => 10,
235
  "neverBlockBG" => "neverBlockVerified",
236
  "loginSec_countFailMins" => "1440",
@@ -292,7 +292,7 @@ class wfConfig {
292
  ),
293
  "otherParams" => array(
294
  'securityLevel' => '4',
295
- "alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256',
296
  "liveTraf_hitsMaxSize" => 10,
297
  "neverBlockBG" => "neverBlockVerified",
298
  "loginSec_countFailMins" => "1440",
44
  ),
45
  "otherParams" => array(
46
  'securityLevel' => '0',
47
+ "alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '',
48
  "liveTraf_hitsMaxSize" => 10,
49
  "neverBlockBG" => "neverBlockVerified",
50
  "loginSec_countFailMins" => "5",
106
  ),
107
  "otherParams" => array(
108
  'securityLevel' => '1',
109
+ "alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '',
110
  "liveTraf_hitsMaxSize" => 10,
111
  "neverBlockBG" => "neverBlockVerified",
112
  "loginSec_countFailMins" => "5",
168
  ),
169
  "otherParams" => array(
170
  'securityLevel' => '2',
171
+ "alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '',
172
  "liveTraf_hitsMaxSize" => 10,
173
  "neverBlockBG" => "neverBlockVerified",
174
  "loginSec_countFailMins" => "240",
230
  ),
231
  "otherParams" => array(
232
  'securityLevel' => '3',
233
+ "alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '',
234
  "liveTraf_hitsMaxSize" => 10,
235
  "neverBlockBG" => "neverBlockVerified",
236
  "loginSec_countFailMins" => "1440",
292
  ),
293
  "otherParams" => array(
294
  'securityLevel' => '4',
295
+ "alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '',
296
  "liveTraf_hitsMaxSize" => 10,
297
  "neverBlockBG" => "neverBlockVerified",
298
  "loginSec_countFailMins" => "1440",
lib/wfDB.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  class wfDB {
3
  private $dbh = false;
4
- private static $dbhCache = false;
5
  private $dbhost = false;
6
  private $dbpassword = false;
7
  private $dbname = false;
@@ -38,8 +38,9 @@ class wfDB {
38
  mysql_select_db($this->dbname, $dbh);
39
  $this->dbh = $dbh;
40
  } else {
41
- if(self::$dbhCache){
42
- $this->dbh = self::$dbhCache;
 
43
  } else {
44
  $dbh = mysql_connect( $this->dbhost, $this->dbuser, $this->dbpassword, true );
45
  if($dbh === false){
@@ -48,12 +49,13 @@ class wfDB {
48
  }
49
 
50
  mysql_select_db($this->dbname, $dbh);
51
- self::$dbhCache = $dbh;
52
- $this->dbh = self::$dbhCache;
53
  }
54
  }
55
  }
56
  public function querySingleRec(){
 
57
  $args = func_get_args();
58
  if(sizeof($args) == 1){
59
  $query = $args[0];
@@ -65,11 +67,13 @@ class wfDB {
65
  $res = mysql_query($query, $this->dbh);
66
  $err = mysql_error();
67
  if($err){
 
68
  $trace=debug_backtrace(); $caller=array_shift($trace); error_log("Wordfence DB error in " . $caller['file'] . " line " . $caller['line'] . ": $err");
69
  }
70
  return mysql_fetch_assoc($res); //returns false if no rows found
71
  }
72
  public function querySingle(){
 
73
  $args = func_get_args();
74
  if(sizeof($args) == 1){
75
  $query = $args[0];
@@ -84,6 +88,7 @@ class wfDB {
84
  $res = mysql_query($query, $this->dbh);
85
  $err = mysql_error();
86
  if($err){
 
87
  $trace=debug_backtrace(); $caller=array_shift($trace); error_log("Wordfence DB error in " . $caller['file'] . " line " . $caller['line'] . ": $err");
88
  }
89
  if(! $res){
@@ -94,6 +99,7 @@ class wfDB {
94
  return $row[0];
95
  }
96
  public function query(){ //sprintfString, arguments
 
97
  $args = func_get_args();
98
  if(sizeof($args) == 1){
99
  $query = $args[0];
@@ -108,6 +114,7 @@ class wfDB {
108
  $res = mysql_query($query, $this->dbh);
109
  $err = mysql_error();
110
  if($err){
 
111
  $trace=debug_backtrace(); $caller=array_shift($trace); error_log("Wordfence DB error in " . $caller['file'] . " line " . $caller['line'] . ": $err");
112
  }
113
  return $res;
1
  <?php
2
  class wfDB {
3
  private $dbh = false;
4
+ private static $dbhCache = array();
5
  private $dbhost = false;
6
  private $dbpassword = false;
7
  private $dbname = false;
38
  mysql_select_db($this->dbname, $dbh);
39
  $this->dbh = $dbh;
40
  } else {
41
+ $handleKey = md5($dbhost . $dbuser . $dbpassword . $dbname);
42
+ if(isset(self::$dbhCache[$handleKey])){
43
+ $this->dbh = self::$dbhCache[$handleKey];
44
  } else {
45
  $dbh = mysql_connect( $this->dbhost, $this->dbuser, $this->dbpassword, true );
46
  if($dbh === false){
49
  }
50
 
51
  mysql_select_db($this->dbname, $dbh);
52
+ self::$dbhCache[$handleKey] = $dbh;
53
+ $this->dbh = self::$dbhCache[$handleKey];
54
  }
55
  }
56
  }
57
  public function querySingleRec(){
58
+ $this->errorMsg = false;
59
  $args = func_get_args();
60
  if(sizeof($args) == 1){
61
  $query = $args[0];
67
  $res = mysql_query($query, $this->dbh);
68
  $err = mysql_error();
69
  if($err){
70
+ $this->errorMsg = $err;
71
  $trace=debug_backtrace(); $caller=array_shift($trace); error_log("Wordfence DB error in " . $caller['file'] . " line " . $caller['line'] . ": $err");
72
  }
73
  return mysql_fetch_assoc($res); //returns false if no rows found
74
  }
75
  public function querySingle(){
76
+ $this->errorMsg = false;
77
  $args = func_get_args();
78
  if(sizeof($args) == 1){
79
  $query = $args[0];
88
  $res = mysql_query($query, $this->dbh);
89
  $err = mysql_error();
90
  if($err){
91
+ $this->errorMsg = $err;
92
  $trace=debug_backtrace(); $caller=array_shift($trace); error_log("Wordfence DB error in " . $caller['file'] . " line " . $caller['line'] . ": $err");
93
  }
94
  if(! $res){
99
  return $row[0];
100
  }
101
  public function query(){ //sprintfString, arguments
102
+ $this->errorMsg = false;
103
  $args = func_get_args();
104
  if(sizeof($args) == 1){
105
  $query = $args[0];
114
  $res = mysql_query($query, $this->dbh);
115
  $err = mysql_error();
116
  if($err){
117
+ $this->errorMsg = $err;
118
  $trace=debug_backtrace(); $caller=array_shift($trace); error_log("Wordfence DB error in " . $caller['file'] . " line " . $caller['line'] . ": $err");
119
  }
120
  return $res;
lib/wfLog.php CHANGED
@@ -111,6 +111,45 @@ class wfLog {
111
  }
112
  }
113
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
  public function unblockAllIPs(){
115
  $this->getDB()->query("delete from " . $this->blocksTable);
116
  }
@@ -121,6 +160,7 @@ class wfLog {
121
  $this->getDB()->query("delete from " . $this->blocksTable . " where IP=%s", wfUtils::inet_aton($IP));
122
  }
123
  public function blockIP($IP, $reason, $wfsn = false){
 
124
  $wfsn = $wfsn ? 1 : 0;
125
  $this->getDB()->query("insert into " . $this->blocksTable . " (IP, blockedTime, reason, wfsn) values (%s, unix_timestamp(), '%s', %d) ON DUPLICATE KEY update blockedTime=unix_timestamp(), reason='%s', wfsn=%d",
126
  wfUtils::inet_aton($IP),
@@ -129,13 +169,16 @@ class wfLog {
129
  $reason,
130
  $wfsn
131
  );
 
132
  }
133
  public function lockOutIP($IP, $reason){
 
134
  $this->getDB()->query("insert into " . $this->lockOutTable . " (IP, blockedTime, reason) values(%s, unix_timestamp(), '%s') ON DUPLICATE KEY update blockedTime=unix_timestamp(), reason='%s'",
135
  wfUtils::inet_aton($IP),
136
  $reason,
137
  $reason
138
  );
 
139
  }
140
  public function unlockOutIP($IP){
141
  $this->getDB()->query("delete from " . $this->lockOutTable . " where IP=%s", wfUtils::inet_aton($IP));
111
  }
112
  }
113
  }
114
+ public function isWhitelisted($IP){
115
+ //We now whitelist all RFC1918 IP addresses and loopback
116
+ if(strpos($IP, '127.') === 0 || strpos($IP, '10.') === 0 || strpos($IP, '192.168.') === 0 || strpos($IP, '172.') === 0){
117
+ if(strpos($IP, '172.') === 0){
118
+ $parts = explode('.', $IP);
119
+ if($parts[1] >= 16 && $parts[1] <= 31){
120
+ return true;
121
+ }
122
+ } else {
123
+ return true;
124
+ }
125
+ }
126
+ $list = wfConfig::get('whitelisted');
127
+ if(! $list){ return false; }
128
+ $list = explode(',', $list);
129
+ if(sizeof($list) < 1){ return false; }
130
+ foreach($list as $whiteIP){
131
+ if(preg_match('/\[\d+\-\d+\]/', $whiteIP)){
132
+ $IPparts = explode('.', $IP);
133
+ $whiteParts = explode('.', $whiteIP);
134
+ $mismatch = false;
135
+ for($i = 0; $i <= 3; $i++){
136
+ if(preg_match('/^\[(\d+)\-(\d+)\]$/', $whiteParts[$i], $m)){
137
+ if($IPparts[$i] < $m[1] || $IPparts[$i] > $m[2]){
138
+ $mismatch = true;
139
+ }
140
+ } else if($whiteParts[$i] != $IPparts[$i]){
141
+ $mismatch = true;
142
+ }
143
+ }
144
+ if($mismatch === false){
145
+ return true; //Is whitelisted because we did not get a mismatch
146
+ }
147
+ } else if($whiteIP == $IP){
148
+ return true;
149
+ }
150
+ }
151
+ return false;
152
+ }
153
  public function unblockAllIPs(){
154
  $this->getDB()->query("delete from " . $this->blocksTable);
155
  }
160
  $this->getDB()->query("delete from " . $this->blocksTable . " where IP=%s", wfUtils::inet_aton($IP));
161
  }
162
  public function blockIP($IP, $reason, $wfsn = false){
163
+ if($this->isWhitelisted($IP)){ return false; }
164
  $wfsn = $wfsn ? 1 : 0;
165
  $this->getDB()->query("insert into " . $this->blocksTable . " (IP, blockedTime, reason, wfsn) values (%s, unix_timestamp(), '%s', %d) ON DUPLICATE KEY update blockedTime=unix_timestamp(), reason='%s', wfsn=%d",
166
  wfUtils::inet_aton($IP),
169
  $reason,
170
  $wfsn
171
  );
172
+ return true;
173
  }
174
  public function lockOutIP($IP, $reason){
175
+ if($this->isWhitelisted($IP)){ return false; }
176
  $this->getDB()->query("insert into " . $this->lockOutTable . " (IP, blockedTime, reason) values(%s, unix_timestamp(), '%s') ON DUPLICATE KEY update blockedTime=unix_timestamp(), reason='%s'",
177
  wfUtils::inet_aton($IP),
178
  $reason,
179
  $reason
180
  );
181
+ return true;
182
  }
183
  public function unlockOutIP($IP){
184
  $this->getDB()->query("delete from " . $this->lockOutTable . " where IP=%s", wfUtils::inet_aton($IP));
lib/wfScanEngine.php CHANGED
@@ -582,9 +582,9 @@ class wfScanEngine {
582
  $level = false;
583
  $spaceLeft = sprintf('%.2f', ($free / $total * 100));
584
  $this->status(2, 'info', "The disk has $spaceLeft percent space available");
585
- if($spaceLeft < 3){
586
  $level = 1;
587
- } else if($spaceLeft < 5){
588
  $level = 2;
589
  } else {
590
  wordfence::statusEnd($statusIDX, false);
@@ -594,7 +594,7 @@ class wfScanEngine {
594
  'spaceLeft' => $spaceLeft ))){
595
  wordfence::statusEnd($statusIDX, true);
596
  } else {
597
- wordfence::statusEnd($statusIDX, true);
598
  }
599
  }
600
  private function scanDNSChanges(){
582
  $level = false;
583
  $spaceLeft = sprintf('%.2f', ($free / $total * 100));
584
  $this->status(2, 'info', "The disk has $spaceLeft percent space available");
585
+ if($spaceLeft < 1){
586
  $level = 1;
587
+ } else if($spaceLeft < 1.5){
588
  $level = 2;
589
  } else {
590
  wordfence::statusEnd($statusIDX, false);
594
  'spaceLeft' => $spaceLeft ))){
595
  wordfence::statusEnd($statusIDX, true);
596
  } else {
597
+ wordfence::statusEnd($statusIDX, false);
598
  }
599
  }
600
  private function scanDNSChanges(){
lib/wfUtils.php CHANGED
@@ -1,7 +1,6 @@
1
  <?php
2
  class wfUtils {
3
  private static $reverseLookupCache = array();
4
- private static $myVersion = false;
5
  public static function makeTimeAgo($secs, $noSeconds = false) {
6
  if($secs < 1){
7
  return "a moment";
@@ -153,24 +152,6 @@ class wfUtils {
153
  public static function getSiteBaseURL(){
154
  return rtrim(site_url(), '/') . '/';
155
  }
156
- public static function myVersion(){
157
- if(! self::$myVersion){
158
- if(! function_exists( 'get_plugin_data')){
159
- require_once ABSPATH . '/wp-admin/includes/plugin.php';
160
- }
161
- $file = dirname(__FILE__) . '/../wordfence.php';
162
- if(is_file($file)){
163
- $dat = get_plugin_data($file);
164
- if(is_array($dat)){
165
- self::$myVersion = $dat['Version'];
166
- }
167
- }
168
- if(! self::$myVersion){
169
- self::$myVersion = 'unknown';
170
- }
171
- }
172
- return self::$myVersion;
173
- }
174
  public static function longestLine($data){
175
  $lines = preg_split('/[\r\n]+/', $data);
176
  $max = 0;
1
  <?php
2
  class wfUtils {
3
  private static $reverseLookupCache = array();
 
4
  public static function makeTimeAgo($secs, $noSeconds = false) {
5
  if($secs < 1){
6
  return "a moment";
152
  public static function getSiteBaseURL(){
153
  return rtrim(site_url(), '/') . '/';
154
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
155
  public static function longestLine($data){
156
  $lines = preg_split('/[\r\n]+/', $data);
157
  $max = 0;
lib/wfViewResult.php CHANGED
@@ -2,7 +2,7 @@
2
  <html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" lang="en-US">
3
  <head>
4
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
5
- <link rel='stylesheet' id='wordfence-main-style-css' href='<?php echo wfUtils::getBaseURL(); ?>/css/diff.css?ver=<?php echo wfUtils::myVersion(); ?>' type='text/css' media='all' />
6
  <body>
7
  <h1>Wordfence: File Viewer</h1>
8
  <table border="0" style="margin: 0 0 20px 0;" class="summary">
2
  <html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" lang="en-US">
3
  <head>
4
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
5
+ <link rel='stylesheet' id='wordfence-main-style-css' href='<?php echo wfUtils::getBaseURL(); ?>/css/diff.css?ver=<?php echo WORDFENCE_VERSION; ?>' type='text/css' media='all' />
6
  <body>
7
  <h1>Wordfence: File Viewer</h1>
8
  <table border="0" style="margin: 0 0 20px 0;" class="summary">
lib/wordfenceClass.php CHANGED
@@ -23,40 +23,12 @@ class wordfence {
23
  private static $hitID = 0;
24
  private static $statusStartMsgs = array();
25
  public static function installPlugin(){
26
- $schema = new wfSchema();
27
- $schema->createAll(); //if not exists
28
- wfConfig::setDefaults(); //If not set
29
-
30
- $api = new wfAPI('', wfUtils::getWPVersion());
31
- $keyData = $api->call('get_anon_api_key');
32
- if($api->errorMsg){
33
- die("Error fetching free API key from Wordfence: " . $api->errorMsg);
34
- }
35
- if($keyData['ok'] && $keyData['apiKey']){
36
- wfConfig::set('apiKey', $keyData['apiKey']);
37
- } else {
38
- die("Could not understand the response we received from the Wordfence servers when applying for a free API key.");
39
- }
40
-
41
-
42
- if( !wp_next_scheduled( 'wordfence_daily_cron' )){
43
- wp_schedule_event(time(), 'daily', 'wordfence_daily_cron');
44
- }
45
- if( !wp_next_scheduled( 'wordfence_hourly_cron' )){
46
- wp_schedule_event(time(), 'hourly', 'wordfence_daily_cron');
47
- }
48
  update_option('wordfenceActivated', 1);
49
- $db = new wfDB();
50
-
51
- //Upgrading from 1.5.6 or earlier needs:
52
- $db->createKeyIfNotExists($prefix . 'wfStatus', 'level', 'k2');
53
-
54
- if(wfConfig::get('isPaid') == 'free'){
55
- wfConfig::set('isPaid', '');
56
- }
57
- wfConfig::set('alertEmailMsgCount', 0);
58
  }
59
  public static function uninstallPlugin(){
 
60
  update_option('wordfenceActivated', 0);
61
  }
62
  public static function hourlyCron(){
@@ -164,7 +136,58 @@ class wordfence {
164
  }
165
 
166
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
167
  public static function install_actions(){
 
 
 
 
 
168
  if(defined('MULTISITE') && MULTISITE === true){
169
  global $blog_id;
170
  if($blog_id == 1 && get_option('wordfenceActivated') != 1){ return; } //Because the plugin is active once installed, even before it's network activated, for site 1 (WordPress team, why?!)
@@ -457,7 +480,7 @@ class wordfence {
457
  }
458
  }
459
  public static function ajax_sendActivityLog_callback(){
460
- $content = "SITE: " . site_url() . "\nPLUGIN VERSION: " . wfUtils::myVersion() . "\nWP VERSION: " . wfUtils::getWPVersion() . "\nAPI KEY: " . wfConfig::get('apiKey') . "\nADMIN EMAIL: " . get_option('admin_email') . "\nLOG:\n\n";
461
  $wfdb = new wfDB();
462
  global $wpdb;
463
  $p = $wpdb->base_prefix;
@@ -498,6 +521,29 @@ class wordfence {
498
  if(sizeof($badEmails) > 0){
499
  return array('errorMsg' => "The following emails are invalid: " . implode(', ', $badEmails));
500
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
501
  }
502
  $opts['apiKey'] = trim($opts['apiKey']);
503
  if(! preg_match('/^[a-fA-F0-9]+$/', $opts['apiKey'])){
@@ -621,6 +667,9 @@ class wordfence {
621
  if($IP == wfUtils::getIP()){
622
  return array('err' => 1, 'errorMsg' => "You can't block your own IP address.");
623
  }
 
 
 
624
  if(wfConfig::get('neverBlockBG') != 'treatAsOtherCrawlers'){ //Either neverBlockVerified or neverBlockUA is selected which means the user doesn't want to block google
625
  if(wfCrawl::verifyCrawlerPTR('/googlebot\.com$/i', $IP)){
626
  return array('err' => 1, 'errorMsg' => "The IP address you're trying to block belongs to Google. Your options are currently set to not block these crawlers. Change this in Wordfence options if you want to manually block Google.");
@@ -1048,16 +1097,16 @@ class wordfence {
1048
  foreach(array('activate', 'scan', 'sendActivityLog', 'restoreFile', 'deleteFile', 'removeExclusion', 'activityLogUpdate', 'ticker', 'loadIssues', 'updateIssueStatus', 'deleteIssue', 'updateAllIssues', 'reverseLookup', 'unlockOutIP', 'unblockIP', 'blockIP', 'loadStaticPanel', 'saveConfig', 'clearAllBlocked') as $func){
1049
  add_action('wp_ajax_wordfence_' . $func, 'wordfence::ajaxReceiver');
1050
  }
1051
- wp_enqueue_style('wordfence-main-style', WP_PLUGIN_URL . '/wordfence/css/main.css', '', wfUtils::myVersion());
1052
- wp_enqueue_style('wordfence-colorbox-style', WP_PLUGIN_URL . '/wordfence/css/colorbox.css', '', wfUtils::myVersion());
1053
- wp_enqueue_style('wordfence-dttable-style', WP_PLUGIN_URL . '/wordfence/css/dt_table.css', '', wfUtils::myVersion());
1054
 
1055
  wp_enqueue_script('json2');
1056
- wp_enqueue_script('jquery.tmpl', wfUtils::getBaseURL() . 'js/jquery.tmpl.min.js', array('jquery'), wfUtils::myVersion());
1057
- wp_enqueue_script('jquery.colorbox', wfUtils::getBaseURL() . 'js/jquery.colorbox-min.js', array('jquery'), wfUtils::myVersion());
1058
- wp_enqueue_script('jquery.dataTables', wfUtils::getBaseURL() . 'js/jquery.dataTables.min.js', array('jquery'), wfUtils::myVersion());
1059
  //wp_enqueue_script('jquery.tools', wfUtils::getBaseURL() . 'js/jquery.tools.min.js', array('jquery'));
1060
- wp_enqueue_script('wordfenceAdminjs', wfUtils::getBaseURL() . 'js/admin.js', array('jquery'), wfUtils::myVersion());
1061
  wp_localize_script('wordfenceAdminjs', 'WordfenceAdminVars', array(
1062
  'ajaxURL' => admin_url('admin-ajax.php'),
1063
  'firstNonce' => wp_create_nonce('wp-ajax'),
23
  private static $hitID = 0;
24
  private static $statusStartMsgs = array();
25
  public static function installPlugin(){
26
+ self::runInstall();
27
+ //Used by MU code below
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  update_option('wordfenceActivated', 1);
 
 
 
 
 
 
 
 
 
29
  }
30
  public static function uninstallPlugin(){
31
+ //Used by MU code below
32
  update_option('wordfenceActivated', 0);
33
  }
34
  public static function hourlyCron(){
136
  }
137
 
138
  }
139
+ public static function runInstall(){
140
+ //EVERYTHING HERE MUST BE IDEMPOTENT
141
+
142
+ $schema = new wfSchema();
143
+ $schema->createAll(); //if not exists
144
+ wfConfig::setDefaults(); //If not set
145
+
146
+ if(! wfConfig::get('apiKey')){
147
+ $api = new wfAPI('', wfUtils::getWPVersion());
148
+ $keyData = $api->call('get_anon_api_key');
149
+ if($api->errorMsg){
150
+ die("Error fetching free API key from Wordfence: " . $api->errorMsg);
151
+ }
152
+ if($keyData['ok'] && $keyData['apiKey']){
153
+ wfConfig::set('apiKey', $keyData['apiKey']);
154
+ } else {
155
+ die("Could not understand the response we received from the Wordfence servers when applying for a free API key.");
156
+ }
157
+ }
158
+
159
+
160
+ if( !wp_next_scheduled( 'wordfence_daily_cron' )){
161
+ wp_schedule_event(time(), 'daily', 'wordfence_daily_cron');
162
+ }
163
+ if( !wp_next_scheduled( 'wordfence_hourly_cron' )){
164
+ wp_schedule_event(time(), 'hourly', 'wordfence_daily_cron');
165
+ }
166
+ $db = new wfDB();
167
+ //Upgrading from 1.5.6 or earlier needs:
168
+ $db->createKeyIfNotExists($prefix . 'wfStatus', 'level', 'k2');
169
+ if(wfConfig::get('isPaid') == 'free'){
170
+ wfConfig::set('isPaid', '');
171
+ }
172
+ //End upgrade from 1.5.6
173
+
174
+ //Show an alert that user needs to enter an email address if user has not seen it before
175
+ if(! wfConfig::get('alertEmailMsgCount')){
176
+ wfConfig::set('alertEmailMsgCount', 0);
177
+ }
178
+
179
+ @chmod(dirname(__FILE__) . '/../wfscan.php', 0755);
180
+ @chmod(dirname(__FILE__) . '/../visitor.php', 0755);
181
+
182
+ //Must be the final line
183
+ update_option('wordfence_version', WORDFENCE_VERSION);
184
+ }
185
  public static function install_actions(){
186
+ $versionInOptions = get_option('wordfence_version', false);
187
+ if( (! $versionInOptions) || version_compare(WORDFENCE_VERSION, $versionInOptions, '>')){
188
+ //Either there is no version in options or the version in options is greater and we need to run the upgrade
189
+ self::runInstall();
190
+ }
191
  if(defined('MULTISITE') && MULTISITE === true){
192
  global $blog_id;
193
  if($blog_id == 1 && get_option('wordfenceActivated') != 1){ return; } //Because the plugin is active once installed, even before it's network activated, for site 1 (WordPress team, why?!)
480
  }
481
  }
482
  public static function ajax_sendActivityLog_callback(){
483
+ $content = "SITE: " . site_url() . "\nPLUGIN VERSION: " . WORDFENCE_VERSION . "\nWP VERSION: " . wfUtils::getWPVersion() . "\nAPI KEY: " . wfConfig::get('apiKey') . "\nADMIN EMAIL: " . get_option('admin_email') . "\nLOG:\n\n";
484
  $wfdb = new wfDB();
485
  global $wpdb;
486
  $p = $wpdb->base_prefix;
521
  if(sizeof($badEmails) > 0){
522
  return array('errorMsg' => "The following emails are invalid: " . implode(', ', $badEmails));
523
  }
524
+ $opts['alertEmails'] = implode(',', $emails);
525
+ } else {
526
+ $opts['alertEmails'] = '';
527
+ }
528
+ $whiteIPs = array();
529
+ foreach(explode(',', preg_replace('/[\r\n\s\t]+/', '', $opts['whitelisted'])) as $whiteIP){
530
+ if(strlen($whiteIP) > 0){
531
+ array_push($whiteIPs, $whiteIP);
532
+ }
533
+ }
534
+ if(sizeof($whiteIPs) > 0){
535
+ $badWhiteIPs = array();
536
+ foreach($whiteIPs as $whiteIP){
537
+ if(! preg_match('/^[\[\]\-\d]+\.[\[\]\-\d]+\.[\[\]\-\d]+\.[\[\]\-\d]+$/', $whiteIP)){
538
+ array_push($badWhiteIPs, $whiteIP);
539
+ }
540
+ }
541
+ if(sizeof($badWhiteIPs) > 0){
542
+ return array('errorMsg' => "Please make sure you separate your IP addresses with commas. The following whitelisted IP addresses are invalid: " . implode(', ', $badWhiteIPs));
543
+ }
544
+ $opts['whitelisted'] = implode(',', $whiteIPs);
545
+ } else {
546
+ $opts['whitelisted'] = '';
547
  }
548
  $opts['apiKey'] = trim($opts['apiKey']);
549
  if(! preg_match('/^[a-fA-F0-9]+$/', $opts['apiKey'])){
667
  if($IP == wfUtils::getIP()){
668
  return array('err' => 1, 'errorMsg' => "You can't block your own IP address.");
669
  }
670
+ if(self::getLog()->isWhitelisted($IP)){
671
+ return array('err' => 1, 'errorMsg' => "The IP address $IP is whitelisted and can't be blocked or it is in a range of internal IP addresses that Wordfence does not block. You can remove this IP from the whitelist on the Wordfence options page.");
672
+ }
673
  if(wfConfig::get('neverBlockBG') != 'treatAsOtherCrawlers'){ //Either neverBlockVerified or neverBlockUA is selected which means the user doesn't want to block google
674
  if(wfCrawl::verifyCrawlerPTR('/googlebot\.com$/i', $IP)){
675
  return array('err' => 1, 'errorMsg' => "The IP address you're trying to block belongs to Google. Your options are currently set to not block these crawlers. Change this in Wordfence options if you want to manually block Google.");
1097
  foreach(array('activate', 'scan', 'sendActivityLog', 'restoreFile', 'deleteFile', 'removeExclusion', 'activityLogUpdate', 'ticker', 'loadIssues', 'updateIssueStatus', 'deleteIssue', 'updateAllIssues', 'reverseLookup', 'unlockOutIP', 'unblockIP', 'blockIP', 'loadStaticPanel', 'saveConfig', 'clearAllBlocked') as $func){
1098
  add_action('wp_ajax_wordfence_' . $func, 'wordfence::ajaxReceiver');
1099
  }
1100
+ wp_enqueue_style('wordfence-main-style', WP_PLUGIN_URL . '/wordfence/css/main.css', '', WORDFENCE_VERSION);
1101
+ wp_enqueue_style('wordfence-colorbox-style', WP_PLUGIN_URL . '/wordfence/css/colorbox.css', '', WORDFENCE_VERSION);
1102
+ wp_enqueue_style('wordfence-dttable-style', WP_PLUGIN_URL . '/wordfence/css/dt_table.css', '', WORDFENCE_VERSION);
1103
 
1104
  wp_enqueue_script('json2');
1105
+ wp_enqueue_script('jquery.tmpl', wfUtils::getBaseURL() . 'js/jquery.tmpl.min.js', array('jquery'), WORDFENCE_VERSION);
1106
+ wp_enqueue_script('jquery.colorbox', wfUtils::getBaseURL() . 'js/jquery.colorbox-min.js', array('jquery'), WORDFENCE_VERSION);
1107
+ wp_enqueue_script('jquery.dataTables', wfUtils::getBaseURL() . 'js/jquery.dataTables.min.js', array('jquery'), WORDFENCE_VERSION);
1108
  //wp_enqueue_script('jquery.tools', wfUtils::getBaseURL() . 'js/jquery.tools.min.js', array('jquery'));
1109
+ wp_enqueue_script('wordfenceAdminjs', wfUtils::getBaseURL() . 'js/admin.js', array('jquery'), WORDFENCE_VERSION);
1110
  wp_localize_script('wordfenceAdminjs', 'WordfenceAdminVars', array(
1111
  'ajaxURL' => admin_url('admin-ajax.php'),
1112
  'firstNonce' => wp_create_nonce('wp-ajax'),
lib/wordfenceConstants.php CHANGED
@@ -1,5 +1,5 @@
1
  <?php
2
- define('WORDFENCE_VERSION', 1.5);
3
  define('WORDFENCE_API_URL', 'https://noc1.wordfence.com/');
4
  define('WORDFENCE_MAX_SCAN_TIME', 600);
5
  define('WORDFENCE_TRANSIENTS_TIMEOUT', 3600); //how long are items cached in seconds e.g. files downloaded for diffing
1
  <?php
2
+ define('WORDFENCE_API_VERSION', 1.5);
3
  define('WORDFENCE_API_URL', 'https://noc1.wordfence.com/');
4
  define('WORDFENCE_MAX_SCAN_TIME', 600);
5
  define('WORDFENCE_TRANSIENTS_TIMEOUT', 3600); //how long are items cached in seconds e.g. files downloaded for diffing
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.3.2
6
- Stable tag: 2.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
 
@@ -53,7 +53,7 @@ To install Wordfence Security and start protecting your WordPress website:
53
  1. Wordfence is now activated. Go to the scan menu and start your first security scan. Scheduled security scanning will also be enabled.
54
  1. Once your first scan has completed a list of security threats will appear. Go through them one by one to secure your site.
55
  1. Visit the Wordfence options page to enter your email address so that you can receive email security alerts.
56
- 1. Optionally change your security level or click the advanced options link to see individual security scanning and protection options.
57
  1. Click the "Live Traffic" menu option to watch your site activity in real-time. Situational awareness is an important part of website security.
58
 
59
  To install Wordfence on WordPress Multi-Site installations (support is currently in Beta):
@@ -72,7 +72,7 @@ To install Wordfence on WordPress Multi-Site installations (support is currently
72
 
73
  = What does Wordfence Security do that other WordPress security plugins don't do? =
74
 
75
- * Wordfence security scans including checking all your files, comments and posts for URL's in Google's Safe Browsing list.
76
  * All Wordfence security scans happen hourly instead of daily or even less frequently.
77
  * Wordfence scans do not consume large amounts of your precious bandwidth because all scans happen on your web server which makes them very fast.
78
  * Wordfence fully supports WordPress Multi-Site which means you can security scan every blog in your Multi-Site installation with one click.
@@ -152,6 +152,18 @@ 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
  = 2.0.5 =
156
  * If your plugin PHP files are viewable by the world, we now give you a detailed warning on the seriousness of this security threat with ability to view the offending .htaccess files.
157
  * Added a debug mode in options for very verbose logging and marking errors in red.
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.3.2
6
+ Stable tag: 2.0.6
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
 
53
  1. Wordfence is now activated. Go to the scan menu and start your first security scan. Scheduled security scanning will also be enabled.
54
  1. Once your first scan has completed a list of security threats will appear. Go through them one by one to secure your site.
55
  1. Visit the Wordfence options page to enter your email address so that you can receive email security alerts.
56
+ 1. Optionally change your security level or adjust the advanced options to set individual security scanning and protection options for your site.
57
  1. Click the "Live Traffic" menu option to watch your site activity in real-time. Situational awareness is an important part of website security.
58
 
59
  To install Wordfence on WordPress Multi-Site installations (support is currently in Beta):
72
 
73
  = What does Wordfence Security do that other WordPress security plugins don't do? =
74
 
75
+ * Wordfence security scans check all your files, comments and posts for URL's in Google's Safe Browsing list.
76
  * All Wordfence security scans happen hourly instead of daily or even less frequently.
77
  * Wordfence scans do not consume large amounts of your precious bandwidth because all scans happen on your web server which makes them very fast.
78
  * Wordfence fully supports WordPress Multi-Site which means you can security scan every blog in your Multi-Site installation with one click.
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
+ = 2.0.6 =
156
+ * Added IP whitelisting including ability to whitelist ranges that are excluded from firewall and login security measures.
157
+ * RFC1918 private networks and loopback address is automatically whitelisted to prevent firewall or login security blocking internal routers and proxy servers, internal firewalls and internal users.
158
+ * Added WORDFENCE_VERSION constant to improve version lookup performance.
159
+ * Fixed issue that caused security scans to not start and humans to not be logged in live traffic. Wordfence makes security scan script and visitors script executable on install or upgrade now.
160
+ * Fixed bug that caused disk space scanning to still show an issue found in security scan summary even when user chooses to ignore the security issue.
161
+ * Made disk space thresholds 1 and 1.5% space remaining because many hosts have very large disks where 1% is gigabytes.
162
+ * Made wordfence database handle cache deal with concurrent connections to different databases.
163
+ * Improved Wordfence database library's error reporting.
164
+ * Improved performance when Wordfence looks up it's own version during security scans and other operations.
165
+ * Removed three rules in base wordfence htaccess that could cause 500 errors on servers that don't allow these options to be overridden. Does not affect htaccess security because we inherit the base htaccess and still protect our lib/ directory with our own htaccess.
166
+
167
  = 2.0.5 =
168
  * If your plugin PHP files are viewable by the world, we now give you a detailed warning on the seriousness of this security threat with ability to view the offending .htaccess files.
169
  * Added a debug mode in options for very verbose logging and marking errors in red.
wordfence.php CHANGED
@@ -4,9 +4,12 @@ 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: 2.0.5
8
  Author URI: http://wordfence.com/
9
  */
 
 
 
10
  require_once('lib/wordfenceConstants.php');
11
  require_once('lib/wordfenceClass.php');
12
  register_activation_hook(WP_PLUGIN_DIR . '/wordfence/wordfence.php', 'wordfence::installPlugin');
4
  Plugin URI: http://wordfence.com/
5
  Description: Wordfence Security - Anti-virus and Firewall security plugin for WordPress
6
  Author: Mark Maunder
7
+ Version: 2.0.6
8
  Author URI: http://wordfence.com/
9
  */
10
+ define('WORDFENCE_VERSION', '2.0.6');
11
+
12
+
13
  require_once('lib/wordfenceConstants.php');
14
  require_once('lib/wordfenceClass.php');
15
  register_activation_hook(WP_PLUGIN_DIR . '/wordfence/wordfence.php', 'wordfence::installPlugin');