PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 5.4.1
Defender Security – Malware Scanner, Login Security & Firewall v5.4.1
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 5.4.1, at src/component/http/remote-address/class-remote-address.php

255 lines 6.0 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 return (array) apply_filters( 'wpdef_firewall_trusted_proxies', $this->trusted_proxies );
93 }
94
95 /**
96 * Set list of trusted proxy addresses.
97 *
98 * @param array $trusted_proxies The array of trusted proxy IP addresses or CIDR ranges.
99 *
100 * @return $this
101 */
102 public function set_trusted_proxies( array $trusted_proxies ): self {
103 $this->trusted_proxies = $trusted_proxies;
104
105 return $this;
106 }
107
108 /**
109 * Set the header to introspect for proxy IPs.
110 *
111 * @param string $header The header to set for proxy IPs. Defaults to 'X-Forwarded-For'.
112 *
113 * @return $this
114 */
115 public function set_proxy_header( $header = 'X-Forwarded-For' ): self {
116 $this->proxy_header = $this->normalize_proxy_header( $header );
117
118 return $this;
119 }
120
121 /**
122 * Set the trusted proxy preset.
123 *
124 * @param string $trusted_proxy_preset The trusted proxy preset to set.
125 *
126 * @return $this
127 */
128 public function set_trusted_proxy_preset( string $trusted_proxy_preset ): self {
129 $this->trusted_proxy_preset = $trusted_proxy_preset;
130
131 return $this;
132 }
133
134 /**
135 * Returns client IP address.
136 *
137 * @return string IP address.
138 */
139 public function get_ip_address(): string {
140 $ip = $this->get_ip_address_from_proxy();
141
142 if ( $ip ) {
143 return $ip;
144 }
145
146 return defender_get_data_from_request( 'REMOTE_ADDR', 's' );
147 }
148
149 /**
150 * Attempt to get the IP address for a proxied client.
151 *
152 * @see http://tools.ietf.org/html/draft-ietf-appsawg-http-forwarded-10#section-5.2
153 * @return false|string
154 */
155 protected function get_ip_address_from_proxy() {
156 if ( ! $this->use_proxy ) {
157 return false;
158 }
159
160 $header = $this->proxy_header;
161
162 $server = defender_get_data_from_request( null, 's' );
163 if ( ! isset( $server[ $header ] ) || empty( $server[ $header ] ) ) {
164 return false;
165 }
166
167 $trusted_proxies = $this->get_trusted_proxies();
168
169 // Extract IPs.
170 $ips = array_reverse( explode( ',', $server[ $header ] ) );
171 foreach ( $ips as $ip ) {
172 // trim, so we can compare against trusted proxies properly.
173 $ip = trim( $ip );
174
175 // @see http://en.wikipedia.org/wiki/X-Forwarded-For .
176 // Since we've removed any known, trusted proxy servers, the right-most
177 // address represents the first IP we do not know about -- i.e., we do
178 // not know if it is a proxy server, or a client. As such, we treat it
179 // as the originating IP.
180 foreach ( $trusted_proxies as $trusted_proxy ) {
181 if (
182 ( false !== strpos( $trusted_proxy, '/' ) && $this->compare_cidr( $ip, $trusted_proxy ) ) ||
183 $trusted_proxy === $ip
184 ) {
185 continue 2;
186 }
187 }
188
189 if ( $this->is_ip_in_trusted_proxy_preset( $ip ) ) {
190 continue;
191 }
192
193 return $ip;
194 }
195
196 return false;
197 }
198
199 /**
200 * Normalize a header string.
201 * Normalizes a header string to a format that is compatible with
202 * $_SERVER.
203 *
204 * @param string $header The header string to normalize.
205 *
206 * @return string
207 */
208 protected function normalize_proxy_header( $header ): string {
209 $header = strtoupper( $header );
210 $header = str_replace( '-', '_', $header );
211
212 if ( 0 !== strpos( $header, 'HTTP_' ) ) {
213 $header = 'HTTP_' . $header;
214 }
215
216 return $header;
217 }
218
219 /**
220 * Check if IP is in trusted proxy preset.
221 *
222 * @param string $ip The IP address to check.
223 *
224 * @return bool
225 */
226 public function is_ip_in_trusted_proxy_preset( string $ip ): bool {
227 $trusted_ips = array();
228 if ( ! empty( $this->trusted_proxy_preset ) ) {
229 /**
230 * Retrieve Trusted_Proxy_Preset instance.
231 *
232 * @var Trusted_Proxy_Preset $trusted_proxy_preset ;
233 */
234 $trusted_proxy_preset = wd_di()->get( Trusted_Proxy_Preset::class );
235 $trusted_proxy_preset->set_proxy_preset( $this->trusted_proxy_preset );
236 $trusted_ips = $trusted_proxy_preset->get_ips();
237 }
238
239 if ( empty( $trusted_ips ) ) {
240 return false;
241 }
242
243 foreach ( $trusted_ips as $trusted_ip ) {
244 if (
245 ( false !== strpos( $trusted_ip, '/' ) && $this->compare_cidr( $ip, $trusted_ip ) ) ||
246 $trusted_ip === $ip
247 ) {
248 return true;
249 }
250 }
251
252 return false;
253 }
254 }
255