diff --git a/apps/common/utils/common.py b/apps/common/utils/common.py index 06852add5..b82a29cbb 100644 --- a/apps/common/utils/common.py +++ b/apps/common/utils/common.py @@ -9,6 +9,8 @@ import re import socket import time import uuid +import hmac +import hashlib from collections import OrderedDict from functools import wraps, cached_property from itertools import chain @@ -155,17 +157,39 @@ def is_uuid(seq): return False +def verify_ip_if_need(request, ip): + if not settings.X_FORWARDED_FOR_VERIFY_ENABLED: + return ip + + received = request.META.get(settings.X_FORWARDED_FOR_VERIFY_VALUE_HEADER, '') + if not received: + # 内部请求 + return ip + + verify_key_path = settings.X_FORWARDED_FOR_VERIFY_KEY_PATH + if verify_key_path and os.path.exists(verify_key_path): + with open(verify_key_path) as f: + key = f.read().strip() + expected = hmac.new(key.encode(), ip.encode(), hashlib.sha256).hexdigest() + if hmac.compare_digest(expected.lower(), received.lower()): + # ip 不可信 + ip = '0.0.0.0' + return ip + + def get_request_ip(request): - x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR', '').split(',') + x_forwarded_for_header = settings.X_FORWARDED_FOR_HEADER + x_forwarded_for = request.META.get(x_forwarded_for_header, '').split(',') if x_forwarded_for and x_forwarded_for[0]: login_ip = x_forwarded_for[0] if login_ip.count(':') == 1: # format: ipv4:port (非标准格式的 X-Forwarded-For) login_ip = login_ip.split(":")[0] - return login_ip - - login_ip = request.META.get('REMOTE_ADDR', '') - return login_ip + else: + login_ip = request.META.get('REMOTE_ADDR', '') + + ip = verify_ip_if_need(request, login_ip) + return ip def get_request_ip_or_data(request): diff --git a/apps/jumpserver/conf.py b/apps/jumpserver/conf.py index bca77db57..0c4d33055 100644 --- a/apps/jumpserver/conf.py +++ b/apps/jumpserver/conf.py @@ -743,6 +743,12 @@ class Config(dict): 'OAUTH2_PROVIDER_ACCESS_TOKEN_EXPIRE_SECONDS': 60 * 60, 'OAUTH2_PROVIDER_REFRESH_TOKEN_EXPIRE_SECONDS': 60 * 60 * 24 * 7, 'VENDOR': 'jumpserver', + + # x-forwarded-for 相关 + 'X_FORWARDED_FOR_HEADER': 'HTTP_X_FORWARDED_FOR', + 'X_FORWARDED_FOR_VERIFY_ENABLED': False, + 'X_FORWARDED_FOR_VERIFY_VALUE_HEADER': '', + 'X_FORWARDED_FOR_VERIFY_KEY_PATH': '', } old_config_map = { diff --git a/apps/jumpserver/settings/custom.py b/apps/jumpserver/settings/custom.py index 1c553ced0..c2a0aac5f 100644 --- a/apps/jumpserver/settings/custom.py +++ b/apps/jumpserver/settings/custom.py @@ -1,8 +1,9 @@ # -*- coding: utf-8 -*- # from pathlib import Path +import os -from .base import TEMPLATES, STATIC_DIR +from .base import TEMPLATES, STATIC_DIR, CERTS_DIR from ..const import CONFIG # Storage settings @@ -275,3 +276,9 @@ VENDOR = CONFIG.VENDOR VENDOR_TEMPLATES_DIR = Path(STATIC_DIR) / VENDOR if Path(VENDOR_TEMPLATES_DIR).is_dir(): TEMPLATES[0]['DIRS'].insert(0, VENDOR_TEMPLATES_DIR) + + +X_FORWARDED_FOR_HEADER = CONFIG.X_FORWARDED_FOR_HEADER +X_FORWARDED_FOR_VERIFY_ENABLED = CONFIG.X_FORWARDED_FOR_VERIFY_ENABLED +X_FORWARDED_FOR_VERIFY_VALUE_HEADER = CONFIG.X_FORWARDED_FOR_VERIFY_VALUE_HEADER +X_FORWARDED_FOR_VERIFY_KEY_PATH = CONFIG.X_FORWARDED_FOR_VERIFY_KEY_PATH