Users Online

· Guests Online: 9

· Members Online: 0

· Total Members: 229
· Newest Member: Zarfdrilhor

Forum Threads

Newest Threads
No Threads created
Hottest Threads
No Threads created

Latest Articles

Website Blocking — Enterprise Implementation

Website Blocking — Enterprise Implementation

 

 

Architecture Options

Method 1: Local Hosts File        → Per machine, simple

Method 2: Group Policy / DNS      → Domain-wide, recommended

Method 3: Proxy Server (Squid)    → Full content filtering

Method 4: DNS Sinkhole (Pi-hole)  → Network-wide blocking

Method 5: Firewall / iptables     → Deep packet level

 

 

 

Method 1: Hosts File via GPO (Domain-Wide)

 

powershell

# Script: Deploy-WebBlocking.ps1

# Push blocked sites to all domain machines via hosts file

 

param(

    [string]$BlockListFile = "C:\Scripts\blocked_sites.txt",

    [string]$HostsFile     = "C:\Windows\System32\drivers\etc\hosts",

    [string]$LogFile       = "C:\Logs\WebBlock.log"

)

 

# ── Blocked Sites List ──────────────────────────────────────────────

$blockedSites = @(

    # Personal Email

    "gmail.com", "www.gmail.com", "mail.google.com",

    "outlook.live.com", "hotmail.com", "yahoo.com", "mail.yahoo.com",

    "protonmail.com", "tutanota.com",

 

    # Social Media

    "facebook.com", "www.facebook.com",

    "twitter.com", "x.com",

    "instagram.com", "tiktok.com",

    "snapchat.com", "reddit.com",

    "linkedin.com",   # Remove if needed for business

 

    # File Sharing / Cloud Storage

    "wetransfer.com", "dropbox.com",

    "mega.nz", "mediafire.com",

    "pastebin.com", "paste.ee",

 

    # Streaming

    "youtube.com", "www.youtube.com",

    "netflix.com", "primevideo.com",

    "twitch.tv", "spotify.com",

 

    # Gaming

    "steam.com", "store.steampowered.com",

    "epicgames.com", "roblox.com"

)

 

function Write-Log($msg) {

    $ts = Get-Date -Format "yyyy-MM-dd HH:mm:ss"

    "$ts $msg" | Tee-Object -FilePath $LogFile -Append

}

 

# ── Backup original hosts file ──────────────────────────────────────

$backup = "$HostsFile.bak_$(Get-Date -Format 'yyyyMMdd')"

if (-not (Test-Path $backup)) {

    Copy-Item $HostsFile $backup

    Write-Log "Hosts backup: $backup"

}

 

# ── Read current hosts ──────────────────────────────────────────────

$currentHosts = Get-Content $HostsFile

 

# ── Remove old block entries ────────────────────────────────────────

$cleaned = $currentHosts | Where-Object { $_ -notmatch "# CORP-BLOCK" }

 

# ── Add new block entries ────────────────────────────────────────────

$newEntries = @("", "# ── CORPORATE WEB BLOCKS — DO NOT EDIT ── CORP-BLOCK-START ──")

foreach ($site in $blockedSites) {

    $newEntries += "0.0.0.0 $site  # CORP-BLOCK"

    $newEntries += "0.0.0.0 www.$site  # CORP-BLOCK"

}

$newEntries += "# ── CORP-BLOCK-END ──"

 

# ── Write final hosts file ───────────────────────────────────────────

($cleaned + $newEntries) | Set-Content $HostsFile -Encoding UTF8

Write-Log "Blocked $($blockedSites.Count) sites on $env:COMPUTERNAME"

 

# ── Flush DNS cache ──────────────────────────────────────────────────

ipconfig /flushdns | Out-Null

Write-Log "DNS cache flushed"

 

Write-Host "[✔] Web blocking applied: $($blockedSites.Count) sites blocked" -ForegroundColor Green

 

 

 

Method 2: Internet Explorer / Edge GPO Restrictions

Computer Configuration →

  Administrative Templates →

    Windows Components →

      Microsoft Edge →

        Block access to a list of URLs

 

Add URLs:

  gmail.com

  *facebook.com

  *twitter.com

  *youtube.com

 

Via Registry (push via GPO):


powershell

# Block sites in Edge/Chrome via registry

$regPath = "HKLM:\SOFTWARE\Policies\Microsoft\Edge\URLBlocklist"

if (-not (Test-Path $regPath)) {

    New-Item -Path $regPath -Force | Out-Null

}

 

$blockedURLs = @(

    "gmail.com", "facebook.com", "twitter.com",

    "instagram.com", "youtube.com", "tiktok.com",

    "dropbox.com", "wetransfer.com"

)

 

$i = 1

foreach ($url in $blockedURLs) {

    Set-ItemProperty -Path $regPath -Name "$i" -Value $url

    $i++

}

 

Write-Host "[✔] Edge URL blocklist applied via registry"

 

 

Method 3: Windows Firewall Rules

powershell

# Block by IP ranges (Gmail/Google IPs)

$googleIPs = @(

    "142.250.0.0/15", "172.217.0.0/16",

    "74.125.0.0/16",  "64.233.160.0/19",

    "66.249.64.0/19", "216.58.192.0/19"

)

 

foreach ($ip in $googleIPs) {

    $ruleName = "BLOCK-GOOGLE-$($ip -replace '[./]','-')"

    New-NetFirewallRule `

        -DisplayName $ruleName `

        -Direction   Outbound `

        -Action      Block `

        -RemoteAddress $ip `

        -Profile     Any `

        -Enabled     True | Out-Null

    Write-Host "[+] Blocked: $ip"

}

 

Write-Host "[✔] Firewall rules applied"

Part 2: Linux — Multiple Methods


Method 1: Hosts File Blocking

bash

#!/bin/bash

# deploy_web_blocking.sh — Linux hosts file blocker

 

HOSTS_FILE="/etc/hosts"

BACKUP="/etc/hosts.bak.$(date +%Y%m%d)"

LOG="/var/log/web-blocking.log"

 

log() { echo "$(date '+%Y-%m-%d %H:%M:%S') $1" | tee -a "$LOG"; }

 

# Blocked sites list

BLOCKED_SITES=(

    # Personal Email

    "gmail.com" "mail.google.com"

    "outlook.live.com" "hotmail.com"

    "yahoo.com" "mail.yahoo.com"

    "protonmail.com" "tutanota.com"

 

    # Social Media

    "facebook.com" "twitter.com" "x.com"

    "instagram.com" "tiktok.com"

    "snapchat.com" "reddit.com"

 

    # Cloud Storage / File Sharing

    "dropbox.com" "wetransfer.com"

    "mega.nz" "mediafire.com"

    "pastebin.com"

 

    # Streaming

    "youtube.com" "netflix.com"

    "twitch.tv" "spotify.com"

    "primevideo.com"

 

    # Gaming

    "steampowered.com" "epicgames.com"

    "roblox.com"

)

 

# Backup

[ ! -f "$BACKUP" ] && cp "$HOSTS_FILE" "$BACKUP" && log "Backup: $BACKUP"

 

# Remove old entries

sed -i '/# CORP-BLOCK/d' "$HOSTS_FILE"

sed -i '/CORP-BLOCK-START/,/CORP-BLOCK-END/d' "$HOSTS_FILE"

 

# Add new block entries

{

    echo ""

    echo "# ── CORPORATE WEB BLOCKS — DO NOT EDIT — CORP-BLOCK-START ──"

    for site in "${BLOCKED_SITES[@]}"; do

        echo "0.0.0.0 $site        # CORP-BLOCK"

        echo "0.0.0.0 www.$site    # CORP-BLOCK"

    done

    echo "# ── CORP-BLOCK-END ──"

} >> "$HOSTS_FILE"

 

# Flush DNS cache

systemd-resolve --flush-caches 2>/dev/null || \

    service nscd restart 2>/dev/null || \

    resolvectl flush-caches 2>/dev/null

 

log "Blocked ${#BLOCKED_SITES[@]} sites on $(hostname)"

echo "[✔] Web blocking applied: ${#BLOCKED_SITES[@]} sites blocked"

Method 2: Squid Proxy — Full Content Filtering (Recommended)

 

bash

# Install Squid

sudo apt install squid -y          # Ubuntu/Debian

sudo dnf install squid -y          # RHEL/Fedora

Main config — /etc/squid/squid.conf:

squid

# ── Squid Corporate Web Filter ──────────────────────────────────────

 

# Network ACLs

acl localnet src 192.168.0.0/16

acl localnet src 10.0.0.0/8

acl SSL_ports port 443

acl Safe_ports port 80 443 8080

acl CONNECT method CONNECT

 

# Block list files

acl blocked_sites   dstdomain "/etc/squid/blocked_domains.txt"

acl blocked_words   url_regex -i "/etc/squid/blocked_keywords.txt"

acl social_media    dstdomain "/etc/squid/social_media.txt"

acl personal_email  dstdomain "/etc/squid/personal_email.txt"

acl file_sharing    dstdomain "/etc/squid/file_sharing.txt"

 

# Time ACLs

acl work_hours time MTWHF 08:00-18:00

acl lunch_time time MTWHF 12:00-13:00

 

# ── DENY RULES ──────────────────────────────────────────────────────

http_access deny blocked_sites

http_access deny personal_email

http_access deny social_media

http_access deny !work_hours       # Block everything outside work hours

http_access deny file_sharing

 

# Allow local network during work hours

http_access allow localnet work_hours

http_access deny all

 

# Proxy settings

http_port 3128

https_port 3129 intercept ssl-bump \

    cert=/etc/squid/ssl/squid-ca.crt \

    key=/etc/squid/ssl/squid-ca.key

 

# SSL Bump for HTTPS inspection

ssl_bump splice all

 

# Logging

access_log /var/log/squid/access.log combined

cache_log  /var/log/squid/cache.log

 

# Block page

deny_info http://usb-monitor.company.com/blocked.html all

 

cache_mem 256 MB

maximum_object_size 10 MB

Blocked domains files:

bash

# /etc/squid/personal_email.txt

cat > /etc/squid/personal_email.txt <<EOF

gmail.com

mail.google.com

googlemail.com

outlook.live.com

hotmail.com

live.com

yahoo.com

mail.yahoo.com

ymail.com

protonmail.com

tutanota.com

zoho.com

guerrillamail.com

temp-mail.org

10minutemail.com

EOF

 

# /etc/squid/social_media.txt

cat > /etc/squid/social_media.txt <<EOF

facebook.com

fbcdn.net

twitter.com

t.co

x.com

instagram.com

cdninstagram.com

tiktok.com

tiktokcdn.com

snapchat.com

reddit.com

redd.it

pinterest.com

tumblr.com

EOF

 

# /etc/squid/file_sharing.txt

cat > /etc/squid/file_sharing.txt <<EOF

dropbox.com

dropboxusercontent.com

wetransfer.com

we.tl

mega.nz

mediafire.com

rapidshare.com

zippyshare.com

pastebin.com

hastebin.com

EOF

bash

# Start Squid

sudo squid -k parse     # Test config

sudo systemctl enable --now squid

sudo systemctl status squid

 

 

 

Method 3: DNS Sinkhole (Network-Wide)

bash

# Install dnsmasq

sudo apt install dnsmasq -y

 

# Add block entries

cat >> /etc/dnsmasq.conf <<EOF

 

# Corporate Web Blocks

address=/gmail.com/0.0.0.0

address=/mail.google.com/0.0.0.0

address=/facebook.com/0.0.0.0

address=/twitter.com/0.0.0.0

address=/x.com/0.0.0.0

address=/instagram.com/0.0.0.0

address=/tiktok.com/0.0.0.0

address=/youtube.com/0.0.0.0

address=/dropbox.com/0.0.0.0

address=/wetransfer.com/0.0.0.0

address=/reddit.com/0.0.0.0

address=/snapchat.com/0.0.0.0

address=/netflix.com/0.0.0.0

address=/spotify.com/0.0.0.0

EOF

 

sudo systemctl restart dnsmasq

 

 

 

Method 4: iptables Firewall Rules

 

 

bash

#!/bin/bash

# Block websites at firewall level

 

# Flush existing web-block rules

iptables -D OUTPUT -j WEB_BLOCK 2>/dev/null

iptables -F WEB_BLOCK 2>/dev/null

iptables -X WEB_BLOCK 2>/dev/null

 

# Create new chain

iptables -N WEB_BLOCK

iptables -I OUTPUT -j WEB_BLOCK

 

# Resolve and block domains

DOMAINS=(

    "gmail.com" "facebook.com" "twitter.com"

    "instagram.com" "tiktok.com" "youtube.com"

    "dropbox.com" "wetransfer.com" "reddit.com"

)

 

for domain in "${DOMAINS[@]}"; do

    IPS=$(dig +short "$domain" | grep -E '^[0-9]+\.')

    for ip in $IPS; do

        iptables -A WEB_BLOCK -d "$ip" -j DROP

        echo "[+] Blocked $domain → $ip"

    done

done

 

# Save rules

iptables-save > /etc/iptables/rules.v4

echo "[✔] Firewall web blocking applied"

 

 

 

 

 

Part 3: Centralized Block List Manager

Save as /opt/web-blocker/manage_blocklist.py:

 


python

#!/usr/bin/env python3

"""

Centralized Web Block List Manager

Manage, deploy, and audit website blocking across all machines

"""

 

import json, os, subprocess, paramiko

from datetime import datetime

 

CONFIG_FILE  = "/opt/web-blocker/config.json"

REPORT_FILE  = "/var/www/html/usb-dashboard/webblocker.html"

 

# ── Default block categories ─────────────────────────────────────────

DEFAULT_CATEGORIES = {

    "personal_email": {

        "enabled": True,

        "sites": ["gmail.com","mail.google.com","hotmail.com",

                  "yahoo.com","protonmail.com","tutanota.com"]

    },

    "social_media": {

        "enabled": True,

        "sites": ["facebook.com","twitter.com","x.com",

                  "instagram.com","tiktok.com","snapchat.com","reddit.com"]

    },

    "file_sharing": {

        "enabled": True,

        "sites": ["dropbox.com","wetransfer.com","mega.nz",

                  "mediafire.com","pastebin.com"]

    },

    "streaming": {

        "enabled": True,

        "sites": ["youtube.com","netflix.com","twitch.tv",

                  "spotify.com","primevideo.com"]

    },

    "gaming": {

        "enabled": False,

        "sites": ["steampowered.com","epicgames.com","roblox.com"]

    }

}

 

def load_config():

    if os.path.exists(CONFIG_FILE):

        with open(CONFIG_FILE) as f:

            return json.load(f)

    return DEFAULT_CATEGORIES

 

def save_config(config):

    os.makedirs(os.path.dirname(CONFIG_FILE), exist_ok=True)

    with open(CONFIG_FILE, "w") as f:

        json.dump(config, f, indent=2)

 

def get_all_blocked_sites(config):

    sites = []

    for cat, data in config.items():

        if data["enabled"]:

            sites.extend(data["sites"])

    return sorted(set(sites))

 

def deploy_to_linux(host, ssh_key, blocked_sites):

    """Deploy block list to Linux machine via SSH"""

    try:

        client = paramiko.SSHClient()

        client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

        client.connect(host, key_filename=ssh_key, timeout=10)

 

        # Build hosts entries

        entries = "\n".join([

            f"0.0.0.0 {s}     # CORP-BLOCK\n0.0.0.0 www.{s}  # CORP-BLOCK"

            for s in blocked_sites

        ])

 

        cmd = f"""

        sed -i '/# CORP-BLOCK/d' /etc/hosts

        echo '# CORP-BLOCK-START' >> /etc/hosts

        echo '{entries}' >> /etc/hosts

        echo '# CORP-BLOCK-END' >> /etc/hosts

        systemd-resolve --flush-caches 2>/dev/null || true

        echo "OK"

        """

        _, stdout, _ = client.exec_command(cmd)

        result = stdout.read().decode().strip()

        client.close()

        return result == "OK"

    except Exception as e:

        print(f"[ERROR] {host}: {e}")

        return False

 

def generate_status_page(config, machines):

    cats_html = ""

    for cat, data in config.items():

        status_color = "#2ecc71" if data["enabled"] else "#e74c3c"

        status_text  = "ACTIVE" if data["enabled"] else "DISABLED"

        sites_html   = "".join(f"<span style='background:#2c2f3e;padding:2px 8px;"

                               f"border-radius:4px;font-size:0.8em;margin:2px'>{s}</span>"

                               for s in data["sites"])

        cats_html += f"""

        <div style='background:#1a1d27;border-radius:8px;padding:16px;margin-bottom:12px;

                    border-left:4px solid {status_color}'>

          <div style='display:flex;justify-content:space-between;align-items:center'>

            <strong style='text-transform:capitalize'>{cat.replace("_"," ")}</strong>

            <span style='background:{status_color};color:white;padding:2px 10px;

                  border-radius:12px;font-size:0.8em'>{status_text}</span>

          </div>

          <div style='margin-top:10px;display:flex;flex-wrap:wrap;gap:4px'>{sites_html}</div>

        </div>"""

 

    total_blocked = len(get_all_blocked_sites(config))

    html = f"""<!DOCTYPE html>

<html>

<head>

<meta charset="UTF-8">

<meta http-equiv="refresh" content="300">

<title>Web Blocker Status</title>

<style>

  body {{ font-family:Segoe UI,Ubuntu,sans-serif;background:#0f1117;

         color:#e0e0e0;padding:30px; }}

  h1   {{ color:#e74c3c; }}

  .summary {{ display:flex;gap:16px;margin:20px 0;flex-wrap:wrap; }}

  .card {{ background:#1a1d27;border-radius:10px;padding:18px 24px;

           border-left:4px solid #e74c3c;min-width:130px;text-align:center; }}

  .card h3 {{ font-size:2em;color:#e74c3c;margin:0; }}

  .card p  {{ color:#888;font-size:0.85em;margin:4px 0 0; }}

</style>

</head>

<body>

<h1>🚫 Web Blocking Status</h1>

<p style='color:#666'>Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</p>

<div class="summary">

  <div class="card"><h3>{total_blocked}</h3><p>Sites Blocked</p></div>

  <div class="card"><h3>{len(machines)}</h3><p>Machines</p></div>

  <div class="card"><h3>{sum(1 for c in config.values() if c['enabled'])}</h3><p>Active Categories</p></div>

</div>

<h2 style='color:#e74c3c;margin:20px 0 12px'>Block Categories</h2>

{cats_html}

</body>

</html>"""

 

    os.makedirs(os.path.dirname(REPORT_FILE), exist_ok=True)

    with open(REPORT_FILE, "w") as f:

        f.write(html)

    print(f"[✔] Status page: {REPORT_FILE}")

 

if __name__ == "__main__":

    config = load_config()

    sites  = get_all_blocked_sites(config)

    print(f"[*] Total blocked sites: {len(sites)}")

    machines = ["192.168.1.10", "192.168.1.11"]  # Add your machines

    generate_status_page(config, machines)

    save_config(config)

 

 

Deployment Summary

bash

# Linux — deploy immediately

chmod +x /opt/web-blocker/deploy_web_blocking.sh

sudo /opt/web-blocker/deploy_web_blocking.sh

 

# Push to all Linux machines via Ansible

ansible all -m script -a "/opt/web-blocker/deploy_web_blocking.sh" \

    --become -i /etc/ansible/hosts

 

# Windows — push via GPO startup script

# Place USB-WebBlock.ps1 in SYSVOL and link to GPO

 

# Schedule daily refresh (block lists update)

echo "0 6 * * * root /opt/web-blocker/deploy_web_blocking.sh" \

    >> /etc/crontab


Quick Reference — Methods vs Scale

Method

Scale

Bypass Risk

Best For

Hosts file

Per machine

Medium

Small teams

GPO + Registry

Domain-wide

Medium

Windows AD

Squid Proxy

Network-wide

Low

Enterprises

DNS Sinkhole

Network-wide

Medium

All devices

iptables/Firewall

Network-wide

Low

Linux-heavy

Commercial DLP

Enterprise

Very Low

Large orgs

 

 

 

 

 

 

 

 

 

 

 

custom block page (branded 403 page employees see), bypass request workflow (employees request access), or per-department policies (e.g. Marketing can access social media)?

 

 

Part 1: Custom Branded Block Page

Save as /var/www/html/blocked/index.html:

html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Access Blocked — Company IT Policy</title>
<style>
  * { box-sizing: border-box; margin: 0; padding: 0; }
  body {
    font-family: Segoe UI, Ubuntu, sans-serif;
    background: #0f1117;
    color: #e0e0e0;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 20px;
  }
  .container {
    background: #1a1d27;
    border-radius: 16px;
    padding: 40px;
    max-width: 580px;
    width: 100%;
    text-align: center;
    border-top: 4px solid #e74c3c;
    box-shadow: 0 8px 32px rgba(0,0,0,0.4);
  }
  .icon { font-size: 4em; margin-bottom: 16px; }
  .logo {
    font-size: 1em;
    color: #666;
    margin-bottom: 24px;
    letter-spacing: 2px;
    text-transform: uppercase;
  }
  h1 { color: #e74c3c; font-size: 1.6em; margin-bottom: 10px; }
  p  { color: #888; font-size: 0.95em; line-height: 1.7; margin-bottom: 20px; }
  .site-box {
    background: #0f1117;
    border: 1px solid #2c2f3e;
    border-radius: 8px;
    padding: 12px 20px;
    font-family: monospace;
    font-size: 1em;
    color: #e74c3c;
    margin-bottom: 24px;
    word-break: break-all;
  }
  .reason {
    background: #2c2f3e;
    border-radius: 8px;
    padding: 12px 16px;
    font-size: 0.85em;
    color: #aaa;
    margin-bottom: 28px;
    text-align: left;
  }
  .reason strong { color: #e0e0e0; }
  .btn {
    display: inline-block;
    padding: 12px 28px;
    border-radius: 8px;
    font-size: 0.95em;
    font-weight: 600;
    cursor: pointer;
    text-decoration: none;
    border: none;
    transition: opacity 0.2s;
    margin: 6px;
  }
  .btn:hover { opacity: 0.85; }
  .btn-primary { background: #e74c3c; color: white; }
  .btn-secondary {
    background: transparent;
    color: #7fb3d3;
    border: 1px solid #2c2f3e;
  }
  .divider {
    border: none;
    border-top: 1px solid #2c2f3e;
    margin: 28px 0;
  }
  .info-row {
    display: flex;
    justify-content: space-between;
    font-size: 0.78em;
    color: #555;
    flex-wrap: wrap;
    gap: 6px;
  }
  .modal-overlay {
    display: none;
    position: fixed; inset: 0;
    background: rgba(0,0,0,0.7);
    z-index: 100;
    align-items: center;
    justify-content: center;
  }
  .modal-overlay.active { display: flex; }
  .modal {
    background: #1a1d27;
    border-radius: 14px;
    padding: 32px;
    max-width: 480px;
    width: 90%;
    border-top: 3px solid #3498db;
  }
  .modal h2 { color: #3498db; margin-bottom: 16px; font-size: 1.2em; }
  .modal input, .modal select, .modal textarea {
    width: 100%;
    background: #0f1117;
    border: 1px solid #2c2f3e;
    border-radius: 8px;
    color: #e0e0e0;
    padding: 10px 14px;
    font-size: 0.9em;
    margin-bottom: 14px;
    font-family: inherit;
    outline: none;
  }
  .modal textarea { height: 90px; resize: vertical; }
  .modal input:focus, .modal select:focus, .modal textarea:focus {
    border-color: #3498db;
  }
  .modal label { font-size: 0.82em; color: #888; display: block; margin-bottom: 5px; }
  .success-msg {
    display: none;
    background: #1a3a2a;
    border: 1px solid #2ecc71;
    border-radius: 8px;
    padding: 16px;
    color: #2ecc71;
    font-size: 0.9em;
    margin-top: 12px;
  }
</style>
</head>
<body>
 
<div class="container">
  <div class="icon">🚫</div>
  <div class="logo"> Company IT Security</div>
  <h1>Access Blocked</h1>
  <p>This website has been blocked by your organization's IT security policy.</p>
 
  <div class="site-box" id="blocked-url">
    <!-- Filled by JS or Squid -->
    <span id="url-display">This website</span>
  </div>
 
  <div class="reason">
    <strong>Reason:</strong>
    <span id="block-reason">Personal email / unauthorized web service</span><br><br>
    <strong>Policy:</strong> IT Security Policy v2.4 — Acceptable Use of Internet Resources<br>
    <strong>Category:</strong> <span id="block-category">Personal Communication</span>
  </div>
 
  <div>
    <button class="btn btn-primary" onclick="openRequestModal()">
      🔓 Request Access
    </button>
    <a class="btn btn-secondary" href="javascript:history.back()">
      ← Go Back
    </a>
  </div>
 
  <hr class="divider">
 
  <div class="info-row">
    <span>🖥 Host: <span id="hostname-display">WORKSTATION</span></span>
    <span>👤 User: <span id="user-display">employee</span></span>
    <span>🕐 <span id="time-display"></span></span>
    <span>📞 IT Help: ext. 1234</span>
  </div>
</div>
 
<!-- Access Request Modal -->
<div class="modal-overlay" id="requestModal">
  <div class="modal">
    <h2>🔓 Request Website Access</h2>
 
    <label>Your Name</label>
    <input type="text" id="req-name" placeholder="Full Name">
 
    <label>Employee ID</label>
    <input type="text" id="req-empid" placeholder="EMP-XXXXX">
 
    <label>Department</label>
    <select id="req-dept">
      <option value="">Select Department</option>
      <option>Engineering</option>
      <option>Marketing</option>
      <option>Finance</option>
      <option>HR</option>
      <option>Sales</option>
      <option>Operations</option>
      <option>Executive</option>
    </select>
 
    <label>Website you need access to</label>
    <input type="text" id="req-site" placeholder="e.g. gmail.com">
 
    <label>Business Justification</label>
    <textarea id="req-reason"
      placeholder="Why do you need access? How does it relate to your work?"></textarea>
 
    <label>Manager Email (for approval)</label>
    <input type="email" id="req-manager" placeholder="manager@company.com">
 
    <div style="display:flex;gap:10px;margin-top:6px">
      <button class="btn btn-primary" style="flex:1" onclick="submitRequest()">
        📨 Submit Request
      </button>
      <button class="btn btn-secondary" onclick="closeRequestModal()">
        Cancel
      </button>
    </div>
 
    <div class="success-msg" id="success-msg">
       Request submitted! Your manager and IT will review within 24 hours.
      Reference ID: <strong id="ref-id"></strong>
    </div>
  </div>
</div>
 
<script>
  // Fill dynamic fields
  const params = new URLSearchParams(window.location.search);
  document.getElementById('url-display').textContent =
    params.get('url') || document.referrer || 'The requested site';
  document.getElementById('block-reason').textContent =
    params.get('reason') || 'Unauthorized web service';
  document.getElementById('block-category').textContent =
    params.get('category') || 'Restricted Content';
  document.getElementById('time-display').textContent =
    new Date().toLocaleString();
 
  // Auto-fill site in modal
  document.getElementById('req-site').value =
    params.get('url') || '';
 
  function openRequestModal() {
    document.getElementById('requestModal').classList.add('active');
  }
  function closeRequestModal() {
    document.getElementById('requestModal').classList.remove('active');
    document.getElementById('success-msg').style.display = 'none';
  }
 
  async function submitRequest() {
    const name    = document.getElementById('req-name').value.trim();
    const empid   = document.getElementById('req-empid').value.trim();
    const dept    = document.getElementById('req-dept').value;
    const site    = document.getElementById('req-site').value.trim();
    const reason  = document.getElementById('req-reason').value.trim();
    const manager = document.getElementById('req-manager').value.trim();
 
    if (!name || !site || !reason || !manager || !dept) {
      alert('Please fill in all fields.'); return;
    }
 
    const refId = 'REQ-' + Date.now().toString(36).toUpperCase();
    const payload = { name, empid, dept, site, reason, manager,
                      refId, timestamp: new Date().toISOString(),
                      blockedUrl: params.get('url') || '' };
 
    try {
      await fetch('/api/access-request', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(payload)
      });
    } catch(e) { /* offline fallback — still show success */ }
 
    document.getElementById('ref-id').textContent = refId;
    document.getElementById('success-msg').style.display = 'block';
    setTimeout(closeRequestModal, 4000);
  }
</script>
</body>
</html>



Part 2: Bypass Request Workflow Backend

Save as /opt/web-blocker/request_server.py:

python

#!/usr/bin/env python3
"""
Web Access Request Workflow Backend
Handles bypass requests, manager approvals, and auto-deploys exceptions
"""
 
from http.server import HTTPServer, BaseHTTPRequestHandler
import json, smtplib, sqlite3, os, subprocess
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from datetime import datetime
from urllib.parse import urlparse, parse_qs
 
DB_FILE      = "/var/lib/web-blocker/requests.db"
SMTP_SERVER  = "smtp.company.com"
SMTP_PORT    = 587
SMTP_USER    = "it-security@company.com"
SMTP_PASS    = "your_smtp_password"
APPROVE_BASE = "https://usb-monitor.company.com/approve"
IT_EMAIL     = "it-security@company.com"
 
os.makedirs(os.path.dirname(DB_FILE), exist_ok=True)
 
# ── Database ─────────────────────────────────────────────────────────
def init_db():
    conn = sqlite3.connect(DB_FILE)
    conn.execute("""
        CREATE TABLE IF NOT EXISTS requests (
            ref_id      TEXT PRIMARY KEY,
            name        TEXT,
            emp_id      TEXT,
            department  TEXT,
            site        TEXT,
            reason      TEXT,
            manager     TEXT,
            status      TEXT DEFAULT 'pending',
            created_at  TEXT,
            updated_at  TEXT,
            blocked_url TEXT,
            notes       TEXT
        )
    """)
    conn.commit()
    conn.close()
 
def save_request(data):
    conn = sqlite3.connect(DB_FILE)
    conn.execute("""
        INSERT OR REPLACE INTO requests
        (ref_id, name, emp_id, department, site, reason,
         manager, status, created_at, updated_at, blocked_url)
        VALUES (?,?,?,?,?,?,?,'pending',?,?,?)
    """, (
        data["refId"], data["name"], data.get("empid",""),
        data["dept"], data["site"], data["reason"],
        data["manager"], data["timestamp"], data["timestamp"],
        data.get("blockedUrl","")
    ))
    conn.commit()
    conn.close()
 
def update_request(ref_id, status, notes=""):
    conn = sqlite3.connect(DB_FILE)
    conn.execute("""
        UPDATE requests SET status=?, updated_at=?, notes=?
        WHERE ref_id=?
    """, (status, datetime.now().isoformat(), notes, ref_id))
    conn.commit()
    conn.close()
 
def get_all_requests():
    conn = sqlite3.connect(DB_FILE)
    conn.row_factory = sqlite3.Row
    rows = conn.execute(
        "SELECT * FROM requests ORDER BY created_at DESC"
    ).fetchall()
    conn.close()
    return [dict(r) for r in rows]
 
def get_request(ref_id):
    conn = sqlite3.connect(DB_FILE)
    conn.row_factory = sqlite3.Row
    row = conn.execute(
        "SELECT * FROM requests WHERE ref_id=?", (ref_id,)
    ).fetchone()
    conn.close()
    return dict(row) if row else None
 
# ── Email ────────────────────────────────────────────────────────────
def send_email(to, subject, html):
    try:
        msg = MIMEMultipart("alternative")
        msg["Subject"] = subject
        msg["From"]    = SMTP_USER
        msg["To"]      = to
        msg.attach(MIMEText(html, "html"))
        with smtplib.SMTP(SMTP_SERVER, SMTP_PORT) as s:
            s.starttls()
            s.login(SMTP_USER, SMTP_PASS)
            s.sendmail(SMTP_USER, [to], msg.as_string())
        print(f"[EMAIL] Sent to {to}: {subject}")
    except Exception as e:
        print(f"[EMAIL ERROR] {e}")
 
def notify_manager(req):
    approve_url = f"{APPROVE_BASE}?ref={req['ref_id']}&action=approve"
    deny_url    = f"{APPROVE_BASE}?ref={req['ref_id']}&action=deny"
    html = f"""
    <div style="font-family:sans-serif;max-width:600px;margin:auto">
      <div style="background:#2c3e50;color:white;padding:16px 20px;border-radius:8px 8px 0 0">
        <h2 style="margin:0">🔓 Web Access Request — Approval Required</h2>
      </div>
      <div style="background:#f9f9f9;padding:24px;border:1px solid #ddd">
        <table style="width:100%;border-collapse:collapse">
          <tr><td style="padding:8px;color:#666;width:140px">Reference</td>
              <td style="padding:8px;font-weight:bold">{req['ref_id']}</td></tr>
          <tr style="background:#fff"><td style="padding:8px;color:#666">Employee</td>
              <td style="padding:8px">{req['name']} ({req['emp_id']})</td></tr>
          <tr><td style="padding:8px;color:#666">Department</td>
              <td style="padding:8px">{req['department']}</td></tr>
          <tr style="background:#fff"><td style="padding:8px;color:#666">Site Requested</td>
              <td style="padding:8px;font-weight:bold;color:#e74c3c">{req['site']}</td></tr>
          <tr><td style="padding:8px;color:#666">Justification</td>
              <td style="padding:8px">{req['reason']}</td></tr>
          <tr style="background:#fff"><td style="padding:8px;color:#666">Submitted</td>
              <td style="padding:8px">{req['created_at'][:19]}</td></tr>
        </table>
        <div style="margin-top:24px;text-align:center">
          <a href="{approve_url}" style="background:#2ecc71;color:white;padding:12px 28px;
             border-radius:8px;text-decoration:none;font-weight:bold;margin:6px;
             display:inline-block"> Approve Access</a>
          <a href="{deny_url}" style="background:#e74c3c;color:white;padding:12px 28px;
             border-radius:8px;text-decoration:none;font-weight:bold;margin:6px;
             display:inline-block"> Deny Request</a>
        </div>
        <p style="color:#999;font-size:0.8em;margin-top:20px;text-align:center">
          IT Security | Company Name | This is an automated message
        </p>
      </div>
    </div>"""
    send_email(req["manager"],
               f"[ACTION REQUIRED] Web Access Request — {req['name']} → {req['site']}",
               html)
 
def notify_employee(req, approved):
    status_color = "#2ecc71" if approved else "#e74c3c"
    status_text  = "APPROVED ✅" if approved else "DENIED ❌"
    msg = ("Your request has been approved. Access will be granted within 30 minutes."
           if approved else
           "Your request was not approved. Contact IT if you believe this is an error.")
    html = f"""
    <div style="font-family:sans-serif;max-width:600px;margin:auto">
      <div style="background:{status_color};color:white;padding:16px 20px;
                  border-radius:8px 8px 0 0">
        <h2 style="margin:0">Web Access Request: {status_text}</h2>
      </div>
      <div style="background:#f9f9f9;padding:24px;border:1px solid #ddd">
        <p>Hi {req['name']},</p>
        <p style="margin:12px 0">{msg}</p>
        <table style="width:100%;border-collapse:collapse;margin-top:16px">
          <tr><td style="padding:8px;color:#666;width:140px">Reference</td>
              <td style="padding:8px">{req['ref_id']}</td></tr>
          <tr style="background:#fff"><td style="padding:8px;color:#666">Site</td>
              <td style="padding:8px">{req['site']}</td></tr>
          <tr><td style="padding:8px;color:#666">Status</td>
              <td style="padding:8px;font-weight:bold">{status_text}</td></tr>
        </table>
        <p style="color:#999;font-size:0.8em;margin-top:20px">
          IT Help Desk: ext. 1234 | it-security@company.com
        </p>
      </div>
    </div>"""
    # Send to employee via IT (no direct employee email in request)
    send_email(IT_EMAIL,
               f"Web Access {status_text} — {req['name']} — {req['site']}",
               html)
 
# ── Apply Exception ───────────────────────────────────────────────────
def apply_exception(site, action="allow"):
    """Add or remove a site from the block list"""
    HOSTS = "/etc/hosts"
    SQUID_WHITELIST = "/etc/squid/whitelist.txt"
 
    # Hosts file exception
    if action == "allow":
        subprocess.run(["sed", "-i",
            f"/0\\.0\\.0\\.0 {site}/d", HOSTS], check=False)
        subprocess.run(["sed", "-i",
            f"/0\\.0\\.0\\.0 www\\.{site}/d", HOSTS], check=False)
        # Add to Squid whitelist
        with open(SQUID_WHITELIST, "a") as f:
            f.write(f"{site}\n")
        subprocess.run(["squid", "-k", "reconfigure"], check=False)
        print(f"[+] Exception applied: {site} → ALLOWED")
    else:
        print(f"[+] Site remains blocked: {site}")
 
    subprocess.run(["systemd-resolve", "--flush-caches"],
                   check=False, capture_output=True)
 
# ── HTTP Request Handler ──────────────────────────────────────────────
class RequestHandler(BaseHTTPRequestHandler):
 
    def log_message(self, format, *args):
        pass  # Suppress default logs
 
    def send_json(self, code, data):
        body = json.dumps(data).encode()
        self.send_response(code)
        self.send_header("Content-Type", "application/json")
        self.send_header("Access-Control-Allow-Origin", "*")
        self.send_header("Content-Length", len(body))
        self.end_headers()
        self.wfile.write(body)
 
    def send_html(self, code, html):
        body = html.encode()
        self.send_response(code)
        self.send_header("Content-Type", "text/html")
        self.end_headers()
        self.wfile.write(body)
 
    def do_OPTIONS(self):
        self.send_response(200)
        self.send_header("Access-Control-Allow-Origin", "*")
        self.send_header("Access-Control-Allow-Methods", "POST,GET")
        self.send_header("Access-Control-Allow-Headers", "Content-Type")
        self.end_headers()
 
    def do_POST(self):
        if self.path == "/api/access-request":
            length = int(self.headers.get("Content-Length", 0))
            body   = json.loads(self.rfile.read(length))
            save_request(body)
            notify_manager(body)
            print(f"[REQUEST] {body['refId']} — {body['name']} → {body['site']}")
            self.send_json(200, {"status": "ok", "refId": body["refId"]})
 
    def do_GET(self):
        parsed = urlparse(self.path)
        params = parse_qs(parsed.query)
 
        # Approval endpoint
        if parsed.path == "/approve":
            ref_id = params.get("ref", [""])[0]
            action = params.get("action", [""])[0]
            req    = get_request(ref_id)
 
            if not req:
                self.send_html(404, "<h1>Request not found</h1>")
                return
 
            approved = action == "approve"
            update_request(ref_id, "approved" if approved else "denied")
 
            if approved:
                apply_exception(req["site"], "allow")
 
            notify_employee(req, approved)
            status = "APPROVED ✅" if approved else "DENIED ❌"
            color  = "#2ecc71" if approved else "#e74c3c"
            self.send_html(200, f"""
            <html><body style="font-family:sans-serif;text-align:center;
                  padding:60px;background:#0f1117;color:#e0e0e0">
              <div style="background:#1a1d27;border-radius:16px;padding:40px;
                          max-width:480px;margin:auto;border-top:4px solid {color}">
                <h1 style="color:{color}">{status}</h1>
                <p>Request <strong>{ref_id}</strong> for
                   <strong>{req['site']}</strong> has been {action}d.</p>
                <p style="color:#666;margin-top:16px">Employee will be notified.</p>
              </div>
            </body></html>""")
            return
 
        # Admin dashboard
        if parsed.path == "/admin/requests":
            requests = get_all_requests()
            rows = ""
            for r in requests:
                sc = {"approved":"#2ecc71","denied":"#e74c3c"}.get(r["status"],"#f39c12")
                rows += f"""<tr>
                  <td>{r['ref_id']}</td><td>{r['name']}</td>
                  <td>{r['department']}</td>
                  <td style='color:#e74c3c;font-weight:bold'>{r['site']}</td>
                  <td><span style='background:{sc};color:white;padding:2px 10px;
                      border-radius:10px;font-size:0.8em'>{r['status'].upper()}</span></td>
                  <td>{r['created_at'][:16]}</td>
                  <td style='font-size:0.8em;color:#888'>{r['reason'][:60]}...</td>
                </tr>"""
 
            self.send_html(200, f"""
            <!DOCTYPE html><html><head><meta charset='UTF-8'>
            <meta http-equiv='refresh' content='60'>
            <title>Access Requests</title>
            <style>
              body{{font-family:Segoe UI,sans-serif;background:#0f1117;
                   color:#e0e0e0;padding:30px}}
              h1{{color:#e74c3c}}
              table{{width:100%;border-collapse:collapse;background:#1a1d27;
                    border-radius:10px;overflow:hidden;margin-top:20px}}
              th{{background:#2c2f3e;color:#aaa;padding:11px 13px;text-align:left}}
              td{{padding:10px 13px;border-bottom:1px solid #1e2130;font-size:0.85em}}
              tr:hover td{{background:#1e2130}}
            </style></head><body>
            <h1>🔓 Web Access Requests</h1>
            <p style='color:#666'>Total: {len(requests)} | Auto-refreshes every 60s</p>
            <table>
              <tr><th>Ref ID</th><th>Name</th><th>Dept</th><th>Site</th>
                  <th>Status</th><th>Submitted</th><th>Reason</th></tr>
              {rows}
            </table></body></html>""")
            return
 
        self.send_json(404, {"error": "not found"})
 
# ── Start Server ──────────────────────────────────────────────────────
if __name__ == "__main__":
    init_db()
    print("[*] Access Request Server running on :8080")
    print(f"[*] Admin dashboard: http://localhost:8080/admin/requests")
    HTTPServer(("0.0.0.0", 8080), RequestHandler).serve_forever()

 


Comments

No Comments have been Posted.

Post Comment

Please Login to Post a Comment.

Ratings

Rating is available to Members only.

Please login or register to vote.

No Ratings have been Posted.
Render time: 1.83 seconds
29,296,633 unique visits