77from django .urls import reverse
88from django .conf import settings
99from django .middleware .locale import LocaleMiddleware
10+ from django .http import HttpResponseNotFound
1011from django .utils import translation
12+ from django .shortcuts import render
13+
1114logger = logging .getLogger ('admin_logout_logger' )
15+ Honeypot_logger = logging .getLogger ("honeypot_logger" )
1216
1317class AutoLogoutMiddleware (MiddlewareMixin ):
1418 """
@@ -27,9 +31,6 @@ def process_request(self, request):
2731 request .session ['admin_session' ] = True
2832
2933
30-
31-
32-
3334class LogRequestMiddleware :
3435 """
3536 Middleware to log IP address and accessed URL.
@@ -39,18 +40,15 @@ def __init__(self, get_response):
3940 self .get_response = get_response
4041
4142 def __call__ (self , request ):
42- # Process the request
4343 response = self .get_response (request )
4444
45- # Log the IP and page accessed
4645 if request .user .is_authenticated :
4746 session_ip = request .session .get ('ip_address' )
4847 session_ua = request .session .get ('user_agent' )
4948 session_token = request .session .get ('session_token' )
5049 current_ip = self .get_client_ip (request )
5150 current_ua = request .META .get ('HTTP_USER_AGENT' )
5251
53- # Skip hijacking checks for OAuth authentication paths to prevent redirect loops
5452 is_oauth_path = (
5553 request .path .startswith ('/complete/' ) or
5654 request .path .startswith ('/oauth/' ) or
@@ -59,60 +57,38 @@ def __call__(self, request):
5957 'complete' in request .path or
6058 'azuread' in request .path
6159 )
62-
63- # Check if user was authenticated via OAuth
6460 is_oauth_user = request .session .get ('oauth_authenticated' , False )
65-
66- # Check if this is a social auth completion
6761 is_social_auth = 'social' in request .path or 'complete' in request .path
68-
69- # If this is an OAuth path, dashboard, OAuth user, or social auth, set session data instead of checking
62+
7063 if is_oauth_path or is_oauth_user or is_social_auth :
71- # Set session data for OAuth users to prevent future hijacking checks
7264 request .session ['ip_address' ] = current_ip
7365 request .session ['user_agent' ] = current_ua
7466 request .session ['session_token' ] = request .session .session_key
7567 logger .info (f"OAuth/social auth path/user detected - setting session data for user { request .user .email } " )
7668 else :
77- # Only perform hijacking checks for non-OAuth paths
78- # Check for IP address mismatch
7969 if session_ip and session_ip != current_ip :
8070 logger .warning (f"Session IP mismatch! Session IP: { session_ip } , Current IP: { current_ip } " )
8171 request .session .flush ()
82- return redirect ('login' ) # Redirect to login
72+ return redirect ('login' )
8373
84- # Check for User-Agent mismatch
8574 if session_ua and session_ua != current_ua :
8675 logger .warning (f"Session UA mismatch! Session UA: { session_ua } , Current UA: { current_ua } " )
8776 request .session .flush ()
8877 return redirect ('login' )
8978
90- # Check for session token mismatch
9179 if session_token and session_token != request .session .session_key :
9280 logger .warning (f"Session token mismatch! Session token: { session_token } , Current session ID: { request .session .session_key } " )
9381 request .session .flush ()
9482 return redirect ('login' )
95-
96- # Log the IP and accessed URL if no hijacking is detected
9783 self .log_request (request )
98-
9984 return response
10085
101- # Continue processing the request
102- return self .get_response (request )
103-
104-
105-
10686 def log_request (self , request ):
10787 ip = self .get_client_ip (request )
10888 path = request .path
109-
110- # Log the information
11189 logger .info (f"IP: { ip } accessed { path } " )
90+
11291 def get_client_ip (self , request ):
113- """
114- Extracts client IP address from request headers.
115- """
11692 x_forwarded_for = request .META .get ('HTTP_X_FORWARDED_FOR' )
11793 if x_forwarded_for :
11894 ip = x_forwarded_for .split (',' )[0 ]
@@ -121,8 +97,6 @@ def get_client_ip(self, request):
12197 return ip
12298
12399
124-
125-
126100try :
127101 from django .utils .translation import LANGUAGE_SESSION_KEY # Django 4+
128102except Exception :
@@ -134,15 +108,13 @@ class LocaleMiddlewareDefaultEnglish(LocaleMiddleware):
134108 2) If neither exists => Ignore the browser's Accept-Language setting and force settings.LANGUAGE_CODE (English)
135109 """
136110 def process_request (self , request ):
137- # check cookie/session
138111 cookie_name = getattr (settings , "LANGUAGE_COOKIE_NAME" , "django_language" )
139112 lang = request .COOKIES .get (cookie_name )
140113
141114 if not lang and hasattr (request , "session" ):
142115 lang = request .session .get (LANGUAGE_SESSION_KEY )
143116
144117 if not lang :
145- # No user selection => Force default to English, ignore Accept-Language
146118 lang = settings .LANGUAGE_CODE
147119
148120 translation .activate (lang )
@@ -154,38 +126,25 @@ class SecurityHeadersMiddleware:
154126 Middleware to add security headers that help mitigate vulnerabilities
155127 in third-party JavaScript libraries and prevent common attacks.
156128 """
157-
158129 def __init__ (self , get_response ):
159130 self .get_response = get_response
160131
161132 def __call__ (self , request ):
162133 response = self .get_response (request )
163-
164- # Content Security Policy to prevent XSS and code injection
165134 response ['Content-Security-Policy' ] = (
166135 "default-src 'self'; "
167- "script-src 'self' 'unsafe-inline' 'unsafe-eval'; " # unsafe-eval needed for some dev tools
136+ "script-src 'self' 'unsafe-inline' 'unsafe-eval'; "
168137 "style-src 'self' 'unsafe-inline'; "
169138 "img-src 'self' data: https:; "
170139 "font-src 'self' https:; "
171140 "connect-src 'self'; "
172141 "frame-ancestors 'none'; "
173142 "base-uri 'self';"
174143 )
175-
176- # Prevent clickjacking
177144 response ['X-Frame-Options' ] = 'DENY'
178-
179- # Prevent MIME type sniffing
180145 response ['X-Content-Type-Options' ] = 'nosniff'
181-
182- # Enable XSS protection
183146 response ['X-XSS-Protection' ] = '1; mode=block'
184-
185- # Prevent referrer leakage
186147 response ['Referrer-Policy' ] = 'strict-origin-when-cross-origin'
187-
188- # Permissions policy
189148 response ['Permissions-Policy' ] = (
190149 'geolocation=(), '
191150 'microphone=(), '
@@ -196,5 +155,51 @@ def __call__(self, request):
196155 'accelerometer=(), '
197156 'gyroscope=()'
198157 )
199-
200- return response
158+ return response
159+
160+ class HoneypotMiddleware :
161+ """
162+ Middleware to detect and log requests to honeypot (fake) paths.
163+ Normal users will never visit these paths.
164+ If triggered, log the attempt and return a 404 page.
165+ """
166+ HONEYPOT_PATHS = [
167+ "/admin-secret" ,
168+ "/Main-admin" ,
169+ "/superuser" ,
170+ "/dashboard-old" ,
171+ "/backup.sql" ,
172+ "/db.dump" ,
173+ "/config.php" ,
174+ "/env.bak" ,
175+ "/administration-login" ,
176+ "/auth-test" ,
177+ "/secure-login" ,
178+ "/test-page" ,
179+ "/debug/" ,
180+ "/old-site/"
181+ ]
182+
183+ def __init__ (self , get_response ):
184+ self .get_response = get_response
185+
186+ def __call__ (self , request ):
187+ path = request .path
188+
189+ if path in self .HONEYPOT_PATHS :
190+ ip = self .get_client_ip (request )
191+ ua = request .META .get ("HTTP_USER_AGENT" , "unknown" )
192+ Honeypot_logger .warning (
193+ f"HONEYPOT TRIGGERED: Path={ path } , IP={ ip } , User-Agent={ ua } "
194+ )
195+ return render (request , "404.html" , status = 404 )
196+
197+ return self .get_response (request )
198+
199+ def get_client_ip (self , request ):
200+ x_forwarded_for = request .META .get ("HTTP_X_FORWARDED_FOR" )
201+ if x_forwarded_for :
202+ ip = x_forwarded_for .split ("," )[0 ]
203+ else :
204+ ip = request .META .get ("REMOTE_ADDR" , "" )
205+ return ip
0 commit comments