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`.