From e1f503430d24f043643724ab59b150333431be86 Mon Sep 17 00:00:00 2001 From: Altafur Rahman Date: Mon, 30 Dec 2024 04:08:30 +0600 Subject: [PATCH] =?UTF-8?q?Enhance=20URL=20validation=20in=20project=20cre?= =?UTF-8?q?ation=20to=20block=20private=20IPs=20and=20i=E2=80=A6=20(#3170)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Enhance URL validation in project creation to block private IPs and improve error handling * Improve URL validation in project creation to block private and reserved IP addresses * Improve URL validation in project creation to block private and reserved IP addresses --- website/views/project.py | 41 +++++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/website/views/project.py b/website/views/project.py index 86509c390..34355d29b 100644 --- a/website/views/project.py +++ b/website/views/project.py @@ -1,10 +1,13 @@ +import ipaddress import json import logging import re +import socket import time from datetime import datetime, timedelta from io import BytesIO from pathlib import Path +from urllib.parse import urlparse import django_filters import matplotlib.pyplot as plt @@ -445,14 +448,36 @@ def validate_url(url): # Validate URL format try: URLValidator(schemes=["http", "https"])(url) - except ValidationError: - return False + parsed = urlparse(url) + hostname = parsed.hostname + if not hostname: + return False - # Check if URL is accessible - try: - response = requests.head(url, timeout=5, allow_redirects=True) - return response.status_code == 200 - except requests.RequestException: + try: + addr_info = socket.getaddrinfo(hostname, None) + except socket.gaierror: + # DNS resolution failed; hostname is not resolvable + return False + for info in addr_info: + ip = info[4][0] + try: + ip_obj = ipaddress.ip_address(ip) + if ( + ip_obj.is_private + or ip_obj.is_loopback + or ip_obj.is_reserved + or ip_obj.is_multicast + or ip_obj.is_link_local + or ip_obj.is_unspecified + ): + # Disallowed IP range detected + return False + except ValueError: + # Invalid IP address format + return False + return True + + except (ValidationError, ValueError): return False # Validate project URL @@ -738,5 +763,3 @@ def get_issue_count(full_name, query): }, status=403, ) - except Exception as e: - return JsonResponse({"error": str(e), "code": "UNKNOWN_ERROR"}, status=400)