Software /
code /
prosody
Comparison
plugins/mod_http.lua @ 13126:d043834f15d2
mod_http: Use RFC 7239 Forwarded header to find original client IP
Prefer over X-Forwarded-* since it has an actual specification.
Main practical difference is that Forwarded may carry more properties
than only the IP address since it is a structured header.
Since we parse it into an array, it is easier to do the logical thing
and iterate backwards trough proxies until an untrusted one is
encountered. Compare the handling of X-Forwarded-For.
The 'secure' field now accounts for the full chain of proxies, which
must be secure all the way to be considered secure.
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Sat, 03 Jun 2023 17:10:04 +0200 |
parent | 13125:90394be5e6a5 |
child | 13127:f45a29b32f7a |
comparison
equal
deleted
inserted
replaced
13125:90394be5e6a5 | 13126:d043834f15d2 |
---|---|
13 | 13 |
14 local portmanager = require "prosody.core.portmanager"; | 14 local portmanager = require "prosody.core.portmanager"; |
15 local moduleapi = require "prosody.core.moduleapi"; | 15 local moduleapi = require "prosody.core.moduleapi"; |
16 local url_parse = require "socket.url".parse; | 16 local url_parse = require "socket.url".parse; |
17 local url_build = require "socket.url".build; | 17 local url_build = require "socket.url".build; |
18 local normalize_path = require "prosody.util.http".normalize_path; | 18 local http_util = require "prosody.util.http"; |
19 local normalize_path = http_util.normalize_path; | |
19 local set = require "prosody.util.set"; | 20 local set = require "prosody.util.set"; |
20 local array = require "util.array"; | 21 local array = require "util.array"; |
21 | 22 |
22 local ip_util = require "prosody.util.ip"; | 23 local ip_util = require "prosody.util.ip"; |
23 local new_ip = ip_util.new_ip; | 24 local new_ip = ip_util.new_ip; |
317 end | 318 end |
318 | 319 |
319 local function get_forwarded_connection_info(request) --> ip:string, secure:boolean | 320 local function get_forwarded_connection_info(request) --> ip:string, secure:boolean |
320 local ip = request.ip; | 321 local ip = request.ip; |
321 local secure = request.secure; -- set by net.http.server | 322 local secure = request.secure; -- set by net.http.server |
323 | |
324 local forwarded = http_util.parse_forwarded(request.headers.forwarded); | |
325 if forwarded then | |
326 request.forwarded = forwarded; | |
327 for i = #forwarded, 1, -1 do | |
328 local proxy = forwarded[i] | |
329 if is_trusted_proxy(ip) then | |
330 ip = normal_ip(proxy["for"]); | |
331 secure = secure and proxy.proto == "https"; | |
332 else | |
333 break | |
334 end | |
335 end | |
336 | |
337 -- Ignore legacy X-Forwarded-For and X-Forwarded-Proto, handling both seems unfeasible. | |
338 return ip, secure; | |
339 end | |
340 | |
322 local forwarded_for = request.headers.x_forwarded_for; | 341 local forwarded_for = request.headers.x_forwarded_for; |
323 if forwarded_for then | 342 if forwarded_for then |
324 -- luacheck: ignore 631 | 343 -- luacheck: ignore 631 |
325 -- This logic looks weird at first, but it makes sense. | 344 -- This logic looks weird at first, but it makes sense. |
326 -- The for loop will take the last non-trusted-proxy IP from `forwarded_for`. | 345 -- The for loop will take the last non-trusted-proxy IP from `forwarded_for`. |