Wordfence Security – Firewall & Malware Scan - Version 3.5.2

Version Description

  • IP detection is now much more robust. Admins must specify how their site gets IP addresses.
  • Fixed issue that would throw Ajax ticker into a hard loop and put load on a server if user is on "options" page and WF can't detect IPs.
  • Added support for Cloudflare proxies when getting client's real IP address.
  • If we fail to get an IP and then get an IP succesfully, we update the activity log.
  • Activity log update in case of successful IP acquisition will warn if we're getting internal RFC1918 IP's e.g. the IP of your firewall.
Download this release

Release Info

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

Code changes from version 3.5.1 to 3.5.2

js/admin.js CHANGED
@@ -337,26 +337,19 @@ window['wordfenceAdmin'] = {
337
},
338
handleTickerReturn: function(res){
339
this.tickerUpdatePending = false;
340
- var statusMsgChanged = false;
341
var newMsg = "";
342
- var oldMsg = jQuery('#wfLiveStatus').html();
343
if( res.msg ){
344
newMsg = res.msg;
345
} else {
346
newMsg = "Idle";
347
}
348
- if(newMsg && oldMsg && newMsg != oldMsg){
349
- statusMsgChanged = true;
350
- }
351
if(newMsg && newMsg != oldMsg){
352
jQuery('#wfLiveStatus').hide().html(newMsg).fadeIn(200);
353
}
354
355
if(this.mode == 'activity'){
356
if(res.alsoGet != 'logList_' + this.activityMode){ return; } //user switched panels since ajax request started
357
- if(/^(?:topScanners|topLeechers)#x2F;.test(this.activityMode)){
358
- if(statusMsgChanged){ this.updateTicker(true); } return;
359
- }
360
if(res.events.length > 0){
361
this.newestActivityTime = res.events[0]['ctime'];
362
}
@@ -393,7 +386,6 @@ window['wordfenceAdmin'] = {
393
jQuery(elem).html(self.makeTimeAgo(res.serverTime - jQuery(elem).data('wfctime')) + ' ago');
394
});
395
}
396
- if(statusMsgChanged){ this.updateTicker(true); } return;
397
},
398
reverseLookupIPs: function(){
399
var ips = [];
337
},
338
handleTickerReturn: function(res){
339
this.tickerUpdatePending = false;
340
var newMsg = "";
341
+ var oldMsg = jQuery('#wfLiveStatus').text();
342
if( res.msg ){
343
newMsg = res.msg;
344
} else {
345
newMsg = "Idle";
346
}
347
if(newMsg && newMsg != oldMsg){
348
jQuery('#wfLiveStatus').hide().html(newMsg).fadeIn(200);
349
}
350
351
if(this.mode == 'activity'){
352
if(res.alsoGet != 'logList_' + this.activityMode){ return; } //user switched panels since ajax request started
353
if(res.events.length > 0){
354
this.newestActivityTime = res.events[0]['ctime'];
355
}
386
jQuery(elem).html(self.makeTimeAgo(res.serverTime - jQuery(elem).data('wfctime')) + ' ago');
387
});
388
}
389
},
390
reverseLookupIPs: function(){
391
var ips = [];
lib/menu_options.php CHANGED
@@ -36,7 +36,18 @@ var WFSLevels = <?php echo json_encode(wfConfig::$securityLevels); ?>;
36
<option value="CUSTOM"<?php $w->sel('securityLevel', 'CUSTOM'); ?>>Custom settings</option>
37
</select>
38
</td></tr>
39
-
40
</table>
41
<p><table border="0" cellpadding="0" cellspacing="0"><tr><td><input type="button" id="button1" name="button1" class="button-primary" value="Save Changes" onclick="WFAD.saveConfig();" /></td><td style="height: 24px;"><div class="wfAjax24"></div><span class="wfSavedMsg">&nbsp;Your changes have been saved!</span></td></tr></table></p>
42
<div class="wfMarker" id="wfMarkerBasicOptions"></div>
36
<option value="CUSTOM"<?php $w->sel('securityLevel', 'CUSTOM'); ?>>Custom settings</option>
37
</select>
38
</td></tr>
39
+ <?php if(! wfConfig::get('howGetIPs', false)){ ?>
40
+ <tr><td colspan="2" style="color: #F00;"><strong>Please set this now to avoid spoofing attacks:</strong></td></tr>
41
+ <?php } ?>
42
+ <tr><th>How does Wordfence get IPs:</td><td>
43
+ <select id="howGetIPs" name="howGetIPs">
44
+ <option value="">This is not set. We STRONGLY recommend you set this by choosing an option and hitting "Save" for a more secure site.</option>
45
+ <option value="REMOTE_ADDR"<?php $w->sel('howGetIPs', 'REMOTE_ADDR'); ?>>Use PHP's built in REMOTE_ADDR. Use this if you're not using Nginx or any separate front-end proxy or firewall. Try this first.</option>
46
+ <option value="HTTP_X_REAL_IP"<?php $w->sel('howGetIPs', 'HTTP_X_REAL_IP'); ?>>Use the X-Real-IP HTTP header which my Nginx, firewall or front-end proxy is setting. Try this next.</option>
47
+ <option value="HTTP_X_FORWARDED_FOR"<?php $w->sel('howGetIPs', 'HTTP_X_FORWARDED_FOR'); ?>>Use the X-Forwarded-For HTTP header which my Nginx, firewall or front-end proxy is setting.</option>
48
+ <option value="HTTP_CF_CONNECTING_IP"<?php $w->sel('howGetIPs', 'HTTP_CF_CONNECTING_IP'); ?>>I'm using Cloudflare so use the "CF-Connecting-IP" HTTP header to get a visitor IP</option>
49
+ </select><br /><span style="color: #999;">Check the status messages at the top of this page and your "Live Traffic" view to verify this is set correctly.</span>
50
+ </td></tr>
51
</table>
52
<p><table border="0" cellpadding="0" cellspacing="0"><tr><td><input type="button" id="button1" name="button1" class="button-primary" value="Save Changes" onclick="WFAD.saveConfig();" /></td><td style="height: 24px;"><div class="wfAjax24"></div><span class="wfSavedMsg">&nbsp;Your changes have been saved!</span></td></tr></table></p>
53
<div class="wfMarker" id="wfMarkerBasicOptions"></div>
lib/wfConfig.php CHANGED
@@ -48,7 +48,7 @@ class wfConfig {
48
),
49
"otherParams" => array(
50
'securityLevel' => '0',
51
- "alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '', 'maxExecutionTime' => '',
52
"neverBlockBG" => "neverBlockVerified",
53
"loginSec_countFailMins" => "5",
54
"loginSec_lockoutMins" => "5",
@@ -111,7 +111,7 @@ class wfConfig {
111
),
112
"otherParams" => array(
113
'securityLevel' => '1',
114
- "alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '', 'maxExecutionTime' => '',
115
"neverBlockBG" => "neverBlockVerified",
116
"loginSec_countFailMins" => "5",
117
"loginSec_lockoutMins" => "5",
@@ -174,7 +174,7 @@ class wfConfig {
174
),
175
"otherParams" => array(
176
'securityLevel' => '2',
177
- "alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '', 'maxExecutionTime' => '',
178
"neverBlockBG" => "neverBlockVerified",
179
"loginSec_countFailMins" => "240",
180
"loginSec_lockoutMins" => "240",
@@ -237,7 +237,7 @@ class wfConfig {
237
),
238
"otherParams" => array(
239
'securityLevel' => '3',
240
- "alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '', 'maxExecutionTime' => '',
241
"neverBlockBG" => "neverBlockVerified",
242
"loginSec_countFailMins" => "1440",
243
"loginSec_lockoutMins" => "1440",
@@ -300,7 +300,7 @@ class wfConfig {
300
),
301
"otherParams" => array(
302
'securityLevel' => '4',
303
- "alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '', 'maxExecutionTime' => '',
304
"neverBlockBG" => "neverBlockVerified",
305
"loginSec_countFailMins" => "1440",
306
"loginSec_lockoutMins" => "1440",
48
),
49
"otherParams" => array(
50
'securityLevel' => '0',
51
+ "alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '', 'maxExecutionTime' => '', 'howGetIPs' => '',
52
"neverBlockBG" => "neverBlockVerified",
53
"loginSec_countFailMins" => "5",
54
"loginSec_lockoutMins" => "5",
111
),
112
"otherParams" => array(
113
'securityLevel' => '1',
114
+ "alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '', 'maxExecutionTime' => '', 'howGetIPs' => '',
115
"neverBlockBG" => "neverBlockVerified",
116
"loginSec_countFailMins" => "5",
117
"loginSec_lockoutMins" => "5",
174
),
175
"otherParams" => array(
176
'securityLevel' => '2',
177
+ "alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '', 'maxExecutionTime' => '', 'howGetIPs' => '',
178
"neverBlockBG" => "neverBlockVerified",
179
"loginSec_countFailMins" => "240",
180
"loginSec_lockoutMins" => "240",
237
),
238
"otherParams" => array(
239
'securityLevel' => '3',
240
+ "alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '', 'maxExecutionTime' => '', 'howGetIPs' => '',
241
"neverBlockBG" => "neverBlockVerified",
242
"loginSec_countFailMins" => "1440",
243
"loginSec_lockoutMins" => "1440",
300
),
301
"otherParams" => array(
302
'securityLevel' => '4',
303
+ "alertEmails" => "", "liveTraf_ignoreUsers" => "", "liveTraf_ignoreIPs" => "", "liveTraf_ignoreUA" => "", "apiKey" => "", "maxMem" => '256', 'whitelisted' => '', 'maxExecutionTime' => '', 'howGetIPs' => '',
304
"neverBlockBG" => "neverBlockVerified",
305
"loginSec_countFailMins" => "1440",
306
"loginSec_lockoutMins" => "1440",
lib/wfUtils.php CHANGED
@@ -74,7 +74,7 @@ class wfUtils {
74
return WP_CONTENT_DIR . '/plugins/';
75
//return ABSPATH . 'wp-content/plugins/';
76
}
77
- public static function getIP(){
78
$IP = 0;
79
if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])){
80
$IP = $_SERVER['HTTP_X_FORWARDED_FOR'];
@@ -88,6 +88,15 @@ class wfUtils {
88
$IP = $_SERVER['REMOTE_ADDR'];
89
if(is_array($IP) && isset($IP[0])){ $IP = $IP[0]; } //It seems that some hosts may modify _SERVER vars into arrays.
90
}
91
if(preg_match('/,/', $IP)){
92
$parts = explode(',', $IP); //Some users have "unknown,100.100.100.100" for example so we take the first thing that looks like an IP.
93
foreach($parts as $part){
@@ -110,6 +119,14 @@ class wfUtils {
110
$IP = preg_replace('/:\d+#x2F;', '', $IP);
111
}
112
if(self::isValidIP($IP)){
113
return $IP;
114
} else {
115
$msg = "Wordfence can't get the IP of clients and therefore can't operate. We received IP: $IP. X-Forwarded-For was: " . $_SERVER['HTTP_X_FORWARDED_FOR'] . " REMOTE_ADDR was: " . $_SERVER['REMOTE_ADDR'];
@@ -128,6 +145,7 @@ class wfUtils {
128
}
129
}
130
wordfence::status(1, 'error', $msg);
131
return false;
132
}
133
}
74
return WP_CONTENT_DIR . '/plugins/';
75
//return ABSPATH . 'wp-content/plugins/';
76
}
77
+ public static function defaultGetIP(){
78
$IP = 0;
79
if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])){
80
$IP = $_SERVER['HTTP_X_FORWARDED_FOR'];
88
$IP = $_SERVER['REMOTE_ADDR'];
89
if(is_array($IP) && isset($IP[0])){ $IP = $IP[0]; } //It seems that some hosts may modify _SERVER vars into arrays.
90
}
91
+ return $IP;
92
+ }
93
+ public static function getIP(){
94
+ $howGet = wfConfig::get('howGetIPs', false);
95
+ if($howGet){
96
+ $IP = $_SERVER[$howGet];
97
+ } else {
98
+ $IP = wfUtils::defaultGetIP();
99
+ }
100
if(preg_match('/,/', $IP)){
101
$parts = explode(',', $IP); //Some users have "unknown,100.100.100.100" for example so we take the first thing that looks like an IP.
102
foreach($parts as $part){
119
$IP = preg_replace('/:\d+#x2F;', '', $IP);
120
}
121
if(self::isValidIP($IP)){
122
+ if(wfConfig::get('IPGetFail', false)){
123
+ if(preg_match('/^(?:10\.|192\.168|127\.|172\.)/', $IP)){
124
+ wordfence::status(1, 'error', "Wordfence is receiving IP addresses, but we received an internal IP of $IP so your config may still be incorrect.");
125
+ } else {
126
+ wordfence::status(1, 'error', "Wordfence is now receiving IP addresses correctly. We received $IP from a visitor.");
127
+ }
128
+ wfConfig::set('IPGetFail', '');
129
+ }
130
return $IP;
131
} else {
132
$msg = "Wordfence can't get the IP of clients and therefore can't operate. We received IP: $IP. X-Forwarded-For was: " . $_SERVER['HTTP_X_FORWARDED_FOR'] . " REMOTE_ADDR was: " . $_SERVER['REMOTE_ADDR'];
145
}
146
}
147
wordfence::status(1, 'error', $msg);
148
+ wfConfig::set('IPGetFail', 1);
149
return false;
150
}
151
}
lib/wordfenceClass.php CHANGED
@@ -733,6 +733,7 @@ class wordfence {
733
return array('ok' => 1);
734
}
735
public static function ajax_saveConfig_callback(){
736
$opts = wfConfig::parseOptions();
737
$emails = array();
738
foreach(explode(',', preg_replace('/[\r\n\s\t]+/', '', $opts['alertEmails'])) as $email){
@@ -828,13 +829,17 @@ class wordfence {
828
$p = $wpdb->base_prefix;
829
$wfdb->query("delete from $p"."wfBlocks where wfsn=1 and permanent=0");
830
}
831
foreach($opts as $key => $val){
832
if($key != 'apiKey'){ //Don't save API key yet
833
wfConfig::set($key, $val);
834
}
835
}
836
837
- $reload = '';
838
$paidKeyMsg = false;
839
840
@@ -870,9 +875,6 @@ class wordfence {
870
return array('errorMsg' => "Your options have been saved. However we noticed you changed your API key and we tried to verify it with the Wordfence servers and received an error: " . $e->getMessage());
871
}
872
}
873
-
874
-
875
-
876
//Clears next scan if scans are disabled. Schedules next scan if enabled.
877
if($err){
878
return array('errorMsg' => $err);
@@ -1364,6 +1366,10 @@ class wordfence {
1364
'tourClosed' => wfConfig::get('tourClosed', 0)
1365
));
1366
}
1367
public static function activation_warning(){
1368
$activationError = get_option('wf_plugin_act_error', '');
1369
if(strlen($activationError) > 400){
@@ -1379,12 +1385,14 @@ class wordfence {
1379
}
1380
public static function admin_menus(){
1381
if(! wfUtils::isAdmin()){ return; }
1382
if(get_option('wf_plugin_act_error', false)){
1383
if(wfUtils::isAdminPageMU()){
1384
add_action('network_admin_notices', 'wordfence::activation_warning');
1385
} else {
1386
add_action('admin_notices', 'wordfence::activation_warning');
1387
}
1388
}
1389
if(! wfConfig::get('apiKey')){
1390
if(wfUtils::isAdminPageMU()){
@@ -1392,7 +1400,18 @@ class wordfence {
1392
} else {
1393
add_action('admin_notices', 'wordfence::noKeyError');
1394
}
1395
}
1396
add_submenu_page("Wordfence", "Scan", "Scan", "activate_plugins", "Wordfence", 'wordfence::menu_scan');
1397
add_menu_page('Wordfence', 'Wordfence', 'activate_plugins', 'Wordfence', 'wordfence::menu_scan', wfUtils::getBaseURL() . 'images/wordfence-logo-16x16.png');
1398
if(wfConfig::get('liveTrafficEnabled')){
733
return array('ok' => 1);
734
}
735
public static function ajax_saveConfig_callback(){
736
+ $reload = '';
737
$opts = wfConfig::parseOptions();
738
$emails = array();
739
foreach(explode(',', preg_replace('/[\r\n\s\t]+/', '', $opts['alertEmails'])) as $email){
829
$p = $wpdb->base_prefix;
830
$wfdb->query("delete from $p"."wfBlocks where wfsn=1 and permanent=0");
831
}
832
+ if($opts['howGetIPs'] != wfConfig::get('howGetIPs', '')){
833
+ $reload = 'reload';
834
+ }
835
+
836
+
837
foreach($opts as $key => $val){
838
if($key != 'apiKey'){ //Don't save API key yet
839
wfConfig::set($key, $val);
840
}
841
}
842
843
$paidKeyMsg = false;
844
845
875
return array('errorMsg' => "Your options have been saved. However we noticed you changed your API key and we tried to verify it with the Wordfence servers and received an error: " . $e->getMessage());
876
}
877
}
878
//Clears next scan if scans are disabled. Schedules next scan if enabled.
879
if($err){
880
return array('errorMsg' => $err);
1366
'tourClosed' => wfConfig::get('tourClosed', 0)
1367
));
1368
}
1369
+ public static function noHowGetIPWarning(){
1370
+ echo '<div id="wordfenceConfigWarning" class="updated fade"><p><strong>Please go to the <a href="admin.php?page=WordfenceSecOpt">Wordfence Options Page</a> and set the option that tells Wordfence how your site gets visitor IP addresses.</strong> This is important to avoid IP spoofing attacks.</p></div>';
1371
+ }
1372
+
1373
public static function activation_warning(){
1374
$activationError = get_option('wf_plugin_act_error', '');
1375
if(strlen($activationError) > 400){
1385
}
1386
public static function admin_menus(){
1387
if(! wfUtils::isAdmin()){ return; }
1388
+ $warningAdded = false;
1389
if(get_option('wf_plugin_act_error', false)){
1390
if(wfUtils::isAdminPageMU()){
1391
add_action('network_admin_notices', 'wordfence::activation_warning');
1392
} else {
1393
add_action('admin_notices', 'wordfence::activation_warning');
1394
}
1395
+ $warningAdded = true;
1396
}
1397
if(! wfConfig::get('apiKey')){
1398
if(wfUtils::isAdminPageMU()){
1400
} else {
1401
add_action('admin_notices', 'wordfence::noKeyError');
1402
}
1403
+ $warningAdded = true;
1404
}
1405
+ if( (! $warningAdded) && (! wfConfig::get('howGetIPs', false)) ){
1406
+ if(! preg_match('/WordfenceSecOpt/', $_SERVER['REQUEST_URI'])){
1407
+ if(wfUtils::isAdminPageMU()){
1408
+ add_action('network_admin_notices', 'wordfence::noHowGetIPWarning');
1409
+ } else {
1410
+ add_action('admin_notices', 'wordfence::noHowGetIPWarning');
1411
+ }
1412
+ $warningAdded = true;
1413
+ }
1414
+ }
1415
add_submenu_page("Wordfence", "Scan", "Scan", "activate_plugins", "Wordfence", 'wordfence::menu_scan');
1416
add_menu_page('Wordfence', 'Wordfence', 'activate_plugins', 'Wordfence', 'wordfence::menu_scan', wfUtils::getBaseURL() . 'images/wordfence-logo-16x16.png');
1417
if(wfConfig::get('liveTrafficEnabled')){
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.5
6
- Stable tag: 3.5.1
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
@@ -154,6 +154,13 @@ or a theme, because often these have been updated to fix a security hole.
154
155
== Changelog ==
156
157
= 3.5.1 =
158
* Fixed issue with twentyten, twentyeleven, twentytwelve themes showing up as modified in 3.5.
159
* Fixed issue with wpdb->prepare throwing warnings. WordPress changed their code and we have now caught up.
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.5
6
+ Stable tag: 3.5.2
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
154
155
== Changelog ==
156
157
+ = 3.5.2 =
158
+ * IP detection is now much more robust. Admins must specify how their site gets IP addresses.
159
+ * Fixed issue that would throw Ajax ticker into a hard loop and put load on a server if user is on "options" page and WF can't detect IPs.
160
+ * Added support for Cloudflare proxies when getting client's real IP address.
161
+ * If we fail to get an IP and then get an IP succesfully, we update the activity log.
162
+ * Activity log update in case of successful IP acquisition will warn if we're getting internal RFC1918 IP's e.g. the IP of your firewall.
163
+
164
= 3.5.1 =
165
* Fixed issue with twentyten, twentyeleven, twentytwelve themes showing up as modified in 3.5.
166
* Fixed issue with wpdb->prepare throwing warnings. WordPress changed their code and we have now caught up.
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.5.1
8
Author URI: http://wordfence.com/
9
*/
10
- define('WORDFENCE_VERSION', '3.5.1');
11
if(get_option('wordfenceActivated') != 1){
12
add_action('activated_plugin','wordfence_save_activation_error'); function wordfence_save_activation_error(){ update_option('wf_plugin_act_error', ob_get_contents()); }
13
}
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.5.2
8
Author URI: http://wordfence.com/
9
*/
10
+ define('WORDFENCE_VERSION', '3.5.2');
11
if(get_option('wordfenceActivated') != 1){
12
add_action('activated_plugin','wordfence_save_activation_error'); function wordfence_save_activation_error(){ update_option('wf_plugin_act_error', ob_get_contents()); }
13
}