PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 6.2.2
Defender Security – Malware Scanner, Login Security & Firewall v6.2.2
6.3.0 6.2.3 6.2.4 6.2.0 6.2.1 6.2.2 6.1.0 5.3.1 5.4.0 5.4.1 5.5.0 5.5.1 5.6.0 5.6.1 5.6.2 5.7.0 5.7.1 5.7.2 5.8.0 5.8.1 5.9.0 6.0.0 6.0.1 3.0.1 3.1.0 All 141 releases
defender-security / src / component / http / remote-address / class-remote-address.php

class-remote-address.php in Defender Security – Malware Scanner, Login Security & Firewall 6.2.2, at src/component/http/remote-address/class-remote-address.php

258 lines 6.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Handles the determination of the remote IP address based on server settings and configurations.
4 *
5 * @package WP_Defender\Component\Http\Remote_Address
6 */
7
8 namespace WP_Defender\Component\Http\Remote_Address;
9
10 use WP_Defender\Traits\IP;
11 use WP_Defender\Component\Trusted_Proxy_Preset\Trusted_Proxy_Preset;
12
13 /**
14 * Inspired from Laminas.
15 *
16 * @see https://github.com/laminas/laminas-http/blob/2.16.0/src/PhpEnvironment/RemoteAddress.php
17 */
18 class Remote_Address {
19
20 use IP;
21
22 /**
23 * Whether to use proxy addresses or not.
24 * As default this setting is disabled - IP address is mostly needed to increase
25 * security. HTTP_* are not reliable since can easily be spoofed. It can be enabled
26 * just for more flexibility, but if user uses proxy to connect to trusted services
27 * it's his/her own risk, only reliable field for IP address is $_SERVER['REMOTE_ADDR'].
28 *
29 * @var bool
30 */
31 protected $use_proxy = false;
32
33 /**
34 * List of trusted proxy IP addresses.
35 *
36 * @var array
37 */
38 protected $trusted_proxies = array();
39
40 /**
41 * HTTP header to introspect for proxies.
42 *
43 * @var string
44 */
45 protected $proxy_header = 'HTTP_X_FORWARDED_FOR';
46
47 /**
48 * The trusted proxy preset.
49 *
50 * @var string
51 */
52 protected $trusted_proxy_preset = '';
53
54 /**
55 * Changes proxy handling setting.
56 * This must be static method, since validators are recovered automatically
57 * at session read, so this is the only way to switch setting.
58 *
59 * @param bool $use_proxy Whether to check also proxied IP addresses.
60 *
61 * @return $this
62 */
63 public function set_use_proxy( $use_proxy = true ): self {
64 $this->use_proxy = $use_proxy;
65
66 return $this;
67 }
68
69 /**
70 * Checks proxy handling setting.
71 *
72 * @return bool Current setting value.
73 */
74 public function get_use_proxy(): bool {
75 return $this->use_proxy;
76 }
77
78 /**
79 * Get the list of trusted proxy addresses.
80 *
81 * @return array
82 * @since 4.6.0
83 */
84 public function get_trusted_proxies(): array {
85 /**
86 * Filter the list of trusted proxies.
87 *
88 * @param array $trusted_proxies List of trusted proxy IP addresses or CIDR ranges.
89 *
90 * @since 4.6.0
91 */
92 $trusted_proxies = apply_filters( 'wpdef_firewall_trusted_proxies', $this->trusted_proxies );
93 $trusted_proxies = ! is_array( $trusted_proxies ) ? (array) $trusted_proxies : $trusted_proxies;
94
95 return $trusted_proxies;
96 }
97
98 /**
99 * Set list of trusted proxy addresses.
100 *
101 * @param array $trusted_proxies The array of trusted proxy IP addresses or CIDR ranges.
102 *
103 * @return $this
104 */
105 public function set_trusted_proxies( array $trusted_proxies ): self {
106 $this->trusted_proxies = $trusted_proxies;
107
108 return $this;
109 }
110
111 /**
112 * Set the header to introspect for proxy IPs.
113 *
114 * @param string $header The header to set for proxy IPs. Defaults to 'X-Forwarded-For'.
115 *
116 * @return $this
117 */
118 public function set_proxy_header( $header = 'X-Forwarded-For' ): self {
119 $this->proxy_header = $this->normalize_proxy_header( $header );
120
121 return $this;
122 }
123
124 /**
125 * Set the trusted proxy preset.
126 *
127 * @param string $trusted_proxy_preset The trusted proxy preset to set.
128 *
129 * @return $this
130 */
131 public function set_trusted_proxy_preset( string $trusted_proxy_preset ): self {
132 $this->trusted_proxy_preset = $trusted_proxy_preset;
133
134 return $this;
135 }
136
137 /**
138 * Returns client IP address.
139 *
140 * @return string IP address.
141 */
142 public function get_ip_address(): string {
143 $ip = $this->get_ip_address_from_proxy();
144
145 if ( $ip ) {
146 return $ip;
147 }
148
149 return defender_get_data_from_request( 'REMOTE_ADDR', 's' );
150 }
151
152 /**
153 * Attempt to get the IP address for a proxied client.
154 *
155 * @see http://tools.ietf.org/html/draft-ietf-appsawg-http-forwarded-10#section-5.2
156 * @return false|string
157 */
158 protected function get_ip_address_from_proxy() {
159 if ( ! $this->use_proxy ) {
160 return false;
161 }
162
163 $header = $this->proxy_header;
164
165 $server = defender_get_data_from_request( null, 's' );
166 if ( ! isset( $server[ $header ] ) || ! is_string( $server[ $header ] ) || '' === $server[ $header ] ) {
167 return false;
168 }
169
170 $trusted_proxies = $this->get_trusted_proxies();
171
172 // Extract IPs.
173 $ips = array_reverse( explode( ',', $server[ $header ] ) );
174 foreach ( $ips as $ip ) {
175 // trim, so we can compare against trusted proxies properly.
176 $ip = trim( $ip );
177
178 // @see http://en.wikipedia.org/wiki/X-Forwarded-For .
179 // Since we've removed any known, trusted proxy servers, the right-most
180 // address represents the first IP we do not know about -- i.e., we do
181 // not know if it is a proxy server, or a client. As such, we treat it
182 // as the originating IP.
183 foreach ( $trusted_proxies as $trusted_proxy ) {
184 if (
185 ( false !== strpos( $trusted_proxy, '/' ) && $this->compare_cidr( $ip, $trusted_proxy ) ) ||
186 $trusted_proxy === $ip
187 ) {
188 continue 2;
189 }
190 }
191
192 if ( $this->is_ip_in_trusted_proxy_preset( $ip ) ) {
193 continue;
194 }
195
196 return $ip;
197 }
198
199 return false;
200 }
201
202 /**
203 * Normalize a header string.
204 * Normalizes a header string to a format that is compatible with
205 * $_SERVER.
206 *
207 * @param string $header The header string to normalize.
208 *
209 * @return string
210 */
211 protected function normalize_proxy_header( $header ): string {
212 $header = strtoupper( $header );
213 $header = str_replace( '-', '_', $header );
214
215 if ( 0 !== strpos( $header, 'HTTP_' ) ) {
216 $header = 'HTTP_' . $header;
217 }
218
219 return $header;
220 }
221
222 /**
223 * Check if IP is in trusted proxy preset.
224 *
225 * @param string $ip The IP address to check.
226 *
227 * @return bool
228 */
229 public function is_ip_in_trusted_proxy_preset( string $ip ): bool {
230 $trusted_ips = array();
231 if ( '' !== $this->trusted_proxy_preset ) {
232 /**
233 * Retrieve Trusted_Proxy_Preset instance.
234 *
235 * @var Trusted_Proxy_Preset $trusted_proxy_preset ;
236 */
237 $trusted_proxy_preset = wd_di()->get( Trusted_Proxy_Preset::class );
238 $trusted_proxy_preset->set_proxy_preset( $this->trusted_proxy_preset );
239 $trusted_ips = $trusted_proxy_preset->get_ips();
240 }
241
242 if ( ! is_array( $trusted_ips ) || array() === $trusted_ips ) {
243 return false;
244 }
245
246 foreach ( $trusted_ips as $trusted_ip ) {
247 if (
248 ( false !== strpos( $trusted_ip, '/' ) && $this->compare_cidr( $ip, $trusted_ip ) ) ||
249 $trusted_ip === $ip
250 ) {
251 return true;
252 }
253 }
254
255 return false;
256 }
257 }
258