File size: 2,591 Bytes
0baf9d9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# Location: features.py
import re
from urllib.parse import urlparse

def extract_url_features(url):
    """

    Transforms a raw URL string into a fixed 14-dimensional numerical vector.

    Bakes protocol layout logic directly into the metrics—no hardcoded strings.

    """
    url_str = str(url).strip()
    
    # Normalize scheme purely for structural parsing accuracy
    if not url_str.lower().startswith(('http://', 'https://')):
        parse_target = 'http://' + url_str
    else:
        parse_target = url_str
    
    try:
        parsed = urlparse(parse_target)
        
        # FIX: Extract the true domain name using parsed.hostname instead of parsed.netloc.
        # parsed.netloc returns 'youtube@evil-site.com', which contaminates the host measurements.
        # parsed.hostname correctly isolates and returns 'evil-site.com'.
        host = parsed.hostname if parsed.hostname else url_str
        path = parsed.path if parsed.path else ""
        
        # Ensure the anomaly flag catches userinfo components reliably across both parsers
        has_userinfo_anomaly = 1.0 if (parsed.username or parsed.password or '@' in parsed.netloc) else 0.0
    except Exception:
        host = url_str
        path = ""
        has_userinfo_anomaly = 0.0

    # Feature engineering pipeline (Maintained at exactly 14 Dimensions)
    features = [
        len(url_str),                               # 1. Total length
        len(host),                                  # 2. Hostname layout length (Corrected to true domain length)
        url_str.count('.'),                         # 3. Subdomain count
        url_str.count('-'),                         # 4. Hyphen count
        has_userinfo_anomaly,                       # 5. Structural Credential Injection Anomaly Flag
        url_str.count('?'),                         # 6. Query parameters
        url_str.count('='),                         # 7. Variable assignments
        url_str.count('_'),                         # 8. Underscores
        1 if re.search(r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}', host) else 0, # 9. IP address in hostname
        host.count('.'),                            # 10. Dots in hostname specifically
        path.count('/'),                            # 11. Directory depth
        sum(1 for c in url_str if c.isdigit()),     # 12. Total numbers in URL
        1 if parsed.scheme == "https" else 0,       # 13. Uses HTTPS
        1 if url_str.lower().startswith(('bit.ly', 'tinyurl')) else 0 # 14. Shortener
    ]
    
    return features