Created
September 17, 2025 20:05
-
-
Save Mutale85/00bffc7b0bdede1e5d2790f292ecdfc4 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Sometimes in cyberpanel, you may experience a situtaion where you are logged out eachtime you wish to navigate to another page from the base page. | |
| You amy also encounter the following errors. | |
| “errorMessage”: “Session reuse detected, IPAddress logged.”, “error_message”: “Session reuse detected, IPAddress logged.”} | |
| The best way to sor this out, logging in via ssh, | |
| Step 1. | |
| You open the terminal or command promt. | |
| Step 2. | |
| ssh root@ip_address | |
| enter_password | |
| Step 3. | |
| root@user:~# cp /usr/local/CyberCP/CyberCP/secMiddleware.py /usr/local/CyberCP/CyberCP/secMiddleware.py.bak | |
| root@user:~# nano /usr/local/CyberCP/CyberCP/secMiddleware.py | |
| in the secMiddleware.py you delete everything there and then pasted in the code below. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # coding=utf-8 | |
| import os.path | |
| from plogical.CyberCPLogFileWriter import CyberCPLogFileWriter as logging | |
| from django.shortcuts import HttpResponse, render | |
| import json | |
| import re | |
| from loginSystem.models import Administrator | |
| class secMiddleware: | |
| HIGH = 0 | |
| LOW = 1 | |
| def get_client_ip(request): | |
| ip = request.META.get('HTTP_CF_CONNECTING_IP') | |
| if ip is None: | |
| ip = request.META.get('REMOTE_ADDR') | |
| return ip | |
| def __init__(self, get_response): | |
| self.get_response = get_response | |
| def __call__(self, request): | |
| ###### | |
| from plogical.processUtilities import ProcessUtilities | |
| FinalURL = request.build_absolute_uri().split('?')[0] | |
| from urllib.parse import urlparse | |
| pathActual = urlparse(FinalURL).path | |
| # Debug logging removed for performance | |
| # Define webhook pattern for secure matching | |
| import re | |
| webhook_pattern = re.compile(r'^/websites/[^/]+/(webhook|gitNotify)/?$') | |
| if pathActual == "/backup/localInitiate" or pathActual == '/' or pathActual == '/verifyLogin' or pathActual == '/logout' or pathActual.startswith('/api')\ | |
| or webhook_pattern.match(pathActual) or pathActual.startswith('/cloudAPI'): | |
| pass | |
| else: | |
| # Session check logging removed | |
| try: | |
| val = request.session['userID'] | |
| except: | |
| if bool(request.body): | |
| final_dic = { | |
| 'error_message': "This request need session.", | |
| "errorMessage": "This request need session."} | |
| final_json = json.dumps(final_dic) | |
| return HttpResponse(final_json) | |
| else: | |
| from django.shortcuts import redirect | |
| from loginSystem.views import loadLoginPage | |
| return redirect(loadLoginPage) | |
| # if os.path.exists(ProcessUtilities.debugPath): | |
| # logging.writeToFile(f'Final actual URL without QS {FinalURL}') | |
| # Request method logging removed | |
| ########################## | |
| try: | |
| uID = request.session['userID'] | |
| admin = Administrator.objects.get(pk=uID) | |
| ipAddr = request.META.get('True-Client-IP') # Use 'True-Client-IP' for Cloudflare | |
| if ipAddr.find('.') > -1: | |
| if request.session['ipAddr'] == ipAddr or admin.securityLevel == secMiddleware.LOW: | |
| pass | |
| else: | |
| del request.session['userID'] | |
| del request.session['ipAddr'] | |
| logging.writeToFile(request.META.get('True-Client-IP')) | |
| final_dic = {'error_message': "Session reuse detected, IPAddress logged.", | |
| "errorMessage": "Session reuse detected, IPAddress logged."} | |
| final_json = json.dumps(final_dic) | |
| return HttpResponse(final_json) | |
| else: | |
| ipAddr = request.META.get('True-Client-IP').split(':')[:3] | |
| if request.session['ipAddr'] == ipAddr or admin.securityLevel == secMiddleware.LOW: | |
| pass | |
| else: | |
| del request.session['userID'] | |
| del request.session['ipAddr'] | |
| logging.writeToFile(request.META.get('True-Client-IP')) | |
| final_dic = {'error_message': "Session reuse detected, IPAddress logged.", | |
| "errorMessage": "Session reuse detected, IPAddress logged."} | |
| final_json = json.dumps(final_dic) | |
| return HttpResponse(final_json) | |
| except: | |
| pass | |
| if bool(request.body): | |
| try: | |
| # Body scanning logging removed | |
| # Skip validation entirely for webhook endpoints | |
| # Webhook URLs are: /websites/<domain>/webhook or /websites/<domain>/gitNotify | |
| # Use the same webhook pattern defined above | |
| if webhook_pattern.match(pathActual): | |
| response = self.get_response(request) | |
| return response | |
| # logging.writeToFile(request.body) | |
| try: | |
| data = json.loads(request.body) | |
| except: | |
| data = request.POST | |
| for key, value in data.items(): | |
| valueAlreadyChecked = 0 | |
| # Key/value scanning logging removed | |
| # Skip validation for ports key to allow port ranges with colons | |
| # but only for CSF modifyPorts endpoint | |
| if key == 'ports' and pathActual == '/firewall/modifyPorts': | |
| # Validate that ports only contain numbers, commas, and colons | |
| if type(value) == str: | |
| import re | |
| # Allow only: digits, commas, colons, and whitespace | |
| if re.match(r'^[\d,:,\s]+$', value): | |
| continue | |
| else: | |
| logging.writeToFile(f"Invalid port format in CSF configuration: {value}") | |
| final_dic = { | |
| 'error_message': "Invalid port format. Only numbers, commas, and colons are allowed for port ranges.", | |
| "errorMessage": "Invalid port format. Only numbers, commas, and colons are allowed for port ranges."} | |
| final_json = json.dumps(final_dic) | |
| return HttpResponse(final_json) | |
| continue | |
| elif key == 'ports': | |
| # For other endpoints, ports key continues to skip validation | |
| continue | |
| # Allow protocol parameter for CSF modifyPorts endpoint | |
| if key == 'protocol' and pathActual == '/firewall/modifyPorts': | |
| # Validate protocol values | |
| if value in ['TCP_IN', 'TCP_OUT', 'UDP_IN', 'UDP_OUT']: | |
| continue | |
| else: | |
| logging.writeToFile(f"Invalid protocol in CSF configuration: {value}") | |
| final_dic = { | |
| 'error_message': "Invalid protocol. Only TCP_IN, TCP_OUT, UDP_IN, UDP_OUT are allowed.", | |
| "errorMessage": "Invalid protocol. Only TCP_IN, TCP_OUT, UDP_IN, UDP_OUT are allowed."} | |
| final_json = json.dumps(final_dic) | |
| return HttpResponse(final_json) | |
| if type(value) == str or type(value) == bytes: | |
| pass | |
| elif type(value) == list: | |
| valueAlreadyChecked = 1 | |
| # List type logging removed | |
| for items in value: | |
| if isinstance(items, str) and (items.find('- -') > -1 or items.find('\n') > -1 or items.find(';') > -1 or items.find( | |
| '&&') > -1 or items.find('|') > -1 or items.find('...') > -1 \ | |
| or items.find("`") > -1 or items.find("$") > -1 or items.find( | |
| "(") > -1 or items.find(")") > -1 \ | |
| or items.find("'") > -1 or items.find("[") > -1 or items.find( | |
| "]") > -1 or items.find("{") > -1 or items.find("}") > -1 \ | |
| or items.find(":") > -1 or items.find("<") > -1 or items.find( | |
| ">") > -1 or items.find("&") > -1): | |
| logging.writeToFile(request.body) | |
| final_dic = { | |
| 'error_message': "Data supplied is not accepted, following characters are not allowed in the input ` $ & ( ) [ ] { } ; : ‘ < >.", | |
| "errorMessage": "Data supplied is not accepted, following characters are not allowed in the input ` $ & ( ) [ ] { } ; : ‘ < >."} | |
| final_json = json.dumps(final_dic) | |
| return HttpResponse(final_json) | |
| else: | |
| continue | |
| if key == 'backupDestinations': | |
| if re.match('^[a-z|0-9]+:[a-z|0-9|\.]+\/?[A-Z|a-z|0-9|\.]*$', | |
| value) == None and value != 'local': | |
| logging.writeToFile(request.body) | |
| final_dic = {'error_message': "Data supplied is not accepted.", | |
| "errorMessage": "Data supplied is not accepted."} | |
| final_json = json.dumps(final_dic) | |
| return HttpResponse(final_json) | |
| # Allow JSON structure characters for API endpoints but keep security checks for dangerous characters | |
| isAPIEndpoint = (pathActual.find('api/remoteTransfer') > -1 or pathActual.find('api/verifyConn') > -1 or | |
| pathActual.find('saveSpamAssassinConfigurations') > -1 or | |
| pathActual.find('docker') > -1 or pathActual.find('cloudAPI') > -1 or | |
| pathActual.find('verifyLogin') > -1 or pathActual.find('submitUserCreation') > -1 or | |
| pathActual.find('/api/') > -1 or pathActual.find('aiscanner/scheduled-scans') > -1) | |
| if isAPIEndpoint: | |
| # For API endpoints, still check for the most dangerous command injection characters | |
| if isinstance(value, (str, bytes)) and (value.find('- -') > -1 or value.find('\n') > -1 or value.find(';') > -1 or | |
| value.find('&&') > -1 or value.find('||') > -1 or value.find('|') > -1 or | |
| value.find('...') > -1 or value.find("`") > -1 or value.find("$") > -1 or | |
| value.find('../') > -1 or value.find('../../') > -1): | |
| logging.writeToFile(request.body) | |
| final_dic = { | |
| 'error_message': "API request contains potentially dangerous characters: `;`, `&&`, `||`, `|`, `` ` ``, `$`, `../` are not allowed.", | |
| "errorMessage": "API request contains potentially dangerous characters." | |
| } | |
| final_json = json.dumps(final_dic) | |
| return HttpResponse(final_json) | |
| continue | |
| if key == 'MainDashboardCSS' or key == 'ownerPassword' or key == 'scriptUrl' or key == 'CLAMAV_VIRUS' or key == "Rspamdserver" or key == 'smtpd_milters' \ | |
| or key == 'non_smtpd_milters' or key == 'key' or key == 'cert' or key == 'recordContentAAAA' or key == 'backupDestinations'\ | |
| or key == 'ports' \ | |
| or key == 'imageByPass' or key == 'passwordByPass' or key == 'PasswordByPass' or key == 'cronCommand' \ | |
| or key == 'emailMessage' or key == 'configData' or key == 'rewriteRules' \ | |
| or key == 'modSecRules' or key == 'recordContentTXT' or key == 'SecAuditLogRelevantStatus' \ | |
| or key == 'fileContent' or key == 'commands' or key == 'gitHost' or key == 'ipv6' or key == 'contentNow' \ | |
| or key == 'time_of_day' or key == 'notification_emails' or key == 'domains': | |
| continue | |
| # Skip validation for API endpoints that need JSON structure characters | |
| if not isAPIEndpoint and valueAlreadyChecked == 0: | |
| # Only check string values, skip lists and other types | |
| if (type(value) == str or type(value) == bytes) and (value.find('- -') > -1 or value.find('\n') > -1 or value.find(';') > -1 or value.find( | |
| '&&') > -1 or value.find('|') > -1 or value.find('...') > -1 \ | |
| or value.find("`") > -1 or value.find("$") > -1 or value.find("(") > -1 or value.find( | |
| ")") > -1 \ | |
| or value.find("'") > -1 or value.find("[") > -1 or value.find("]") > -1 or value.find( | |
| "{") > -1 or value.find("}") > -1 \ | |
| or value.find(":") > -1 or value.find("<") > -1 or value.find(">") > -1 or value.find( | |
| "&") > -1): | |
| logging.writeToFile(request.body) | |
| final_dic = { | |
| 'error_message': "Data supplied is not accepted, following characters are not allowed in the input ` $ & ( ) [ ] { } ; : ‘ < >.", | |
| "errorMessage": "Data supplied is not accepted, following characters are not allowed in the input ` $ & ( ) [ ] { } ; : ‘ < >."} | |
| final_json = json.dumps(final_dic) | |
| return HttpResponse(final_json) | |
| # Skip key validation for API endpoints that need JSON structure characters | |
| if not isAPIEndpoint and (key.find(';') > -1 or key.find('&&') > -1 or key.find('|') > -1 or key.find('...') > -1 \ | |
| or key.find("`") > -1 or key.find("$") > -1 or key.find("(") > -1 or key.find(")") > -1 \ | |
| or key.find("'") > -1 or key.find("[") > -1 or key.find("]") > -1 or key.find( | |
| "{") > -1 or key.find("}") > -1 \ | |
| or key.find(":") > -1 or key.find("<") > -1 or key.find(">") > -1 or key.find("&") > -1): | |
| logging.writeToFile(request.body) | |
| final_dic = {'error_message': "Data supplied is not accepted.", | |
| "errorMessage": "Data supplied is not accepted following characters are not allowed in the input ` $ & ( ) [ ] { } ; : ‘ < >."} | |
| final_json = json.dumps(final_dic) | |
| return HttpResponse(final_json) | |
| except BaseException as msg: | |
| final_dic = {'error_message': f"Error: {str(msg)}", | |
| "errorMessage": f"Error: {str(msg)}"} | |
| final_json = json.dumps(final_dic) | |
| return HttpResponse(final_json) | |
| else: | |
| # No body logging removed | |
| pass | |
| # else: | |
| # try: | |
| # if request.path.find('cloudAPI/') > -1 or request.path.find('api/') > -1: | |
| # pass | |
| # else: | |
| # uID = request.session['userID'] | |
| # except: | |
| # return render(request, 'loginSystem/login.html', {}) | |
| response = self.get_response(request) | |
| response['X-XSS-Protection'] = "1; mode=block" | |
| response['X-Frame-Options'] = "sameorigin" | |
| response['Content-Security-Policy'] = "script-src 'self' https://www.jsdelivr.com" | |
| response['Content-Security-Policy'] = "connect-src *;" | |
| response['Content-Security-Policy'] = "font-src 'self' 'unsafe-inline' https://www.jsdelivr.com https://fonts.googleapis.com" | |
| response[ | |
| 'Content-Security-Policy'] = "style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://www.jsdelivr.com https://cdnjs.cloudflare.com https://maxcdn.bootstrapcdn.com https://cdn.jsdelivr.net" | |
| # response['Content-Security-Policy'] = "default-src 'self' cyberpanel.cloud *.cyberpanel.cloud" | |
| response['X-Content-Type-Options'] = "nosniff" | |
| response['Referrer-Policy'] = "same-origin" | |
| return response |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment