September 28, 2025 ITHU

Building a Secure IIS Baseline: Preparing for PHP, .NET, and Beyond in an Active Directory Environment

When setting up a new IIS server, it’s tempting to jump straight into installing PHP, .NET, or a CMS. But before adding any applications, creating a secure baseline HTTPS site ensures your environment starts on the right foot. A strong baseline covers folder structure (public vs private), SSL certificates, application pools, and security headers — all critical pieces of a hardened web platform inside an Active Directory environment.

With this foundation in place, future sites — whether they’re classic PHP apps, Razor Pages, or static intranet sites — inherit the same security-first design.

In this guide, we’ll walk through building a baseline IIS site with HTTPS, isolating app pools, structuring sites on a dedicated drive, and preparing for multiple workloads.

Why Secure Internal IIS Sites in an Active Directory Environment

It’s a common misconception that internal websites don’t need the same protections as public-facing applications. After all, they’re behind the firewall and only accessible to domain users — so what’s the risk? The reality is that internal IIS sites often expose some of the most sensitive functionality in an Active Directory environment.

  • Credential handling: Many intranet sites include login forms, directory lookups, or single sign-on integrations that directly touch AD. Without HTTPS, these credentials can be intercepted, replayed, or abused in NTLM relay attacks.
  • Privilege escalation: If a site is misconfigured, attackers who compromise one machine can pivot into IIS and use it to run code or harvest higher-privilege tokens.
  • Trust chain exposure: Internal applications are often implicitly trusted. An insecure IIS site can weaken the security posture of the entire domain by becoming a foothold for lateral movement.
  • Config and data leaks: Misplaced web.config files, PHP includes, or backup dumps in a public folder can hand over sensitive data without the attacker needing to exploit a vulnerability.

By applying a secure baseline — enforced HTTPS, isolated application pools, public/private folder separation, and hardened headers — every new site inherits the same defensive posture. Instead of reacting to individual issues, you build security into the platform from the start.

Why Not Use the Default inetpub Folder

By default, IIS installs sites under C:\inetpub\wwwroot. While this works for quick testing, it isn’t ideal for a secure or scalable environment — especially inside Active Directory. Hosting everything in the inetpub folder mixes system files with application content and makes it harder to enforce least-privilege access.

A better approach is to create a dedicated drive, such as D:\Sites\, and keep each site in its own folder. For example:

D:\Sites\secure_baseline\
├── public\
├── private\
└── logs\

This separation brings several advantages:

  • Isolation from the OS: The operating system and IIS binaries stay on C:\, while your sites are contained on D:\.
  • Cleaner permissions: NTFS ACLs can be set per site and per application pool, reducing cross-site access risks.
  • Scalability: Adding new sites is as simple as creating a new folder under D:\Sites\.
  • Recovery and maintenance: If Windows needs to be reinstalled, your sites remain untouched on a separate drive.
  • Logging and performance: Application logs and cache files won’t clutter or fill the system drive.

This design makes every site predictable, isolated, and easier to secure — a key benefit when building a consistent IIS baseline across your environment.

Requirements for a Secure IIS Baseline Site

Before creating the baseline site at secure_baseline.bugnbuyco.local, the following requirements should be in place. These ensure the foundation is hardened and consistent across the environment:

Dedicated Drive for Sites

  • Use a separate drive (e.g., D:\Sites\) instead of the default inetpub.
  • Each site gets its own folder with public, private, and logs subfolders.

SSL/TLS Certificate from Ubuntu CA

  • Request and sign the certificate using the Ubuntu-based CA (Click here for Setup).
  • Include secure_baseline.bugnbuyco.local in the certificate’s SAN.
  • Apply this certificate to the IIS HTTPS binding.
  • (Note: the AD CA remains for domain authentication only, not for IIS site SSL).

Application Pool Isolation

  • Create a dedicated application pool for the site (e.g., SecureBaselineAppPool).
  • Use ApplicationPoolIdentity or a gMSA for domain-integrated apps.
  • Grant the pool identity NTFS permissions only on that site’s folders.

Security Headers & Web Config

  • Enforce HTTPS redirection via web.config.

Apply standard hardening headers:

  • X-Frame-Options
  • X-Content-Type-Options
  • Referrer-Policy
  • Content-Security-Policy

Active Directory Integration

  • Ensure Kerberos is preferred for authentication.
  • Disable or restrict NTLM where possible to reduce relay risks.
  • Keep AD CA certificates strictly for identity/auth, not web encryption.

Verification & Testing

  • Confirm port 80 is closed or redirects to 443.
  • Test SSL certificate chain from a client machine (Kali/Windows).
  • Use tools like nmap, curl, or browser dev tools to verify headers and HTTPS enforcement.

✅ Recommended Order

  1. Create the Folder Structure First

In this case I have a dedicated folder in D Driver called Sites.

D:\Sites\secure_baseline\
├── public\ # Web root - only files served to clients (HTML, CSS, JS, images, PHP entry points)
├── private\ # Not web accessible - configs, includes, DB connection files
├── logs\ # Application or PHP error logs, IIS site-specific logs (if redirected here)
└── backups\ # Optional - DB dumps, config backups, exported settings (keep secured & restricted)

Drop in a simple index.html under public\ so you can test IIS binding later.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Secure Baseline - BugNBuyCo</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
text-align: center;
margin-top: 100px;
color: #333;
}
h1 {
color: #0066cc;
}
</style>
</head>
<body>
<h1>✅ Secure Baseline Site</h1>
<p>You have successfully set up <strong>secure_baseline.bugnbuyco.local</strong> with HTTPS.</p>
</body>
</html>

2. Create the DNS Record

Since the internal Active Directory domain is “bugnbuyco.local“, a new DNS record needs to be created for the baseline site. The hostname will be “secure_baseline.bugnbuyco.local“, and it should be added on the Domain Controller within the internal DNS zone, pointing to the IIS server’s internal IP address 10.10.20.22.

3. Generate & Bind SSL Certificate Requesting and Signing an IIS SSL Certificate with an Ubuntu Certificate Authority

  • On the IIS server, generate a CSR for secure_baseline.bugnbuyco.local.
  • Sign it using your Ubuntu CA.
  • Import the signed cert back into Windows and bind it to the new IIS site on port 443.

4. Create the IIS Site

Open IIS Manager and right click on Sites and select “Add Website“.

 

🔒 Production-Grade IIS Website Binding Settings

Site name / App Pool

  • ✅ Unique site name (secure_baseline.bugnbuyco.local).
  • ✅ Dedicated app pool → isolate processes.
  • 🔑 After creation: set pool to No Managed Code (for PHP/HTML only) and consider running under a gMSA for least privilege.

Physical path

  • ✅ Keep on a dedicated drive (D:\Sites\… or E:\Sites\…).

🔑 Make sure NTFS permissions are tight:

  • App Pool Identity → Read/Execute only on public.
  • Read-only on private.
  • Write only on logs.

Binding

  • Type: https → ✅ only use HTTPS.
  • IP address: bind to the specific server IP (10.10.20.22) instead of “All Unassigned”. Prevents accidental exposure if multiple NICs are added.
  • Port: 443 (default).
  • Host name: must exactly match the cert (secure_baseline.bugnbuyco.local).

Require Server Name Indication (SNI):

  • ✅ Enable SNI if you plan to host multiple SSL sites on the same server/IP.
  • ❌ Leave off if this is the only SSL site bound to that IP.

TLS & HTTP options

  • ✅ Disable Legacy TLS → remove TLS 1.0/1.1 support.
  • ✅ Disable QUIC → experimental, not needed in internal production.
  • ❌ Keep TLS 1.3 (most secure).
  • ⚖️ HTTP/2: keep enabled if performance is needed; disable if you want less surface area.
  • ❌ Don’t disable OCSP stapling (leave enabled, helps revocation checking).
  • ❌ Don’t disable TLS 1.3.

SSL Certificate

  • ✅ Use your Ubuntu CA–issued cert for web SSL.
  • 🔑 Ensure intermediate CA chain is imported into Trusted Root + Intermediate stores on servers and clients.
  • ✅ Private key permissions restricted to the App Pool Identity only.

IIS now shows the site as working.

Visiting the site shows no SSL errors. When the Ubuntu CA was set up, its root certificate was distributed across the domain using Group Policy, ensuring all domain-joined systems trust it. I also imported the CA certificate into my Kali Linux machine so it recognizes the issued certificates, allowing seamless trust for the next stage of testing.

Verifying TLS 1.0 is Disabled

One of the most important checks in hardening IIS is confirming that TLS 1.0 is fully disabled. Microsoft has formally deprecated TLS 1.0 and 1.1 across Windows Server, IIS, and .NET because of known weaknesses such as downgrade attacks and vulnerabilities like BEAST and POODLE. Modern best practice is to use only TLS 1.2 and TLS 1.3, which provide stronger encryption and support forward secrecy.

Testing this is straightforward with tools such as nmap or testssl.sh. In our case, scanning secure_baseline.bugnbuyco.local showed only TLS 1.2 and TLS 1.3 ciphers available, confirming that older protocols are completely disabled and the server is aligned with Microsoft’s decommissioning guidance.

Testing with NMAP

CMD: nmap –script ssl-enum-ciphers -p 443 secure_baseline.bugnbuyco.local

OutPut:

┌──(zeroscorpion㉿kali)-[~]
└─$ nmap --script ssl-enum-ciphers -p 443 secure_baseline.bugnbuyco.local
Starting Nmap 7.95 ( https://nmap.org ) at 2025-09-28 15:59 AEST
Nmap scan report for secure_baseline.bugnbuyco.local (10.10.20.22)
Host is up (0.00077s latency).

PORT STATE SERVICE
443/tcp open https
| ssl-enum-ciphers: 
| TLSv1.2: 
| ciphers: 
| TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (secp384r1) - A
| TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (ecdh_x25519) - A
| compressors: 
| NULL
| cipher preference: server
| TLSv1.3: 
| ciphers: 
| TLS_AKE_WITH_AES_256_GCM_SHA384 (secp384r1) - A
| TLS_AKE_WITH_AES_128_GCM_SHA256 (ecdh_x25519) - A
| cipher preference: server
|_ least strength: A

Results:

This scan confirms that only TLS 1.2 and TLS 1.3 are enabled, with strong AES-GCM ciphers and perfect forward secrecy. TLS 1.0/1.1 are disabled, no weak ciphers are present, and the server’s configuration earns an overall A rating.

Creating a Custom Secure web.config File

By default, IIS doesn’t enable strong security headers or restrict HTTP methods. This leaves room for issues such as clickjacking, MIME-type sniffing, and the use of unsafe HTTP verbs like TRACE. To harden your baseline site, we’ll create a custom web.config file that enforces HTTPS, adds critical response headers, and locks down allowed methods.

This file will serve as a reusable template for all future sites in your environment, ensuring every deployment inherits the same protections without needing to configure each setting manually in IIS Manager.

📝 Plan

1. Force HTTPS with Redirect

  • Ensure all HTTP traffic is redirected to HTTPS.

2. Enable HSTS (HTTP Strict Transport Security)

  • Add Strict-Transport-Security with a short max-age for testing, later extend to 1 year.

3. Add Security Headers

  • X-Frame-Options → prevent clickjacking
  • X-Content-Type-Options → block MIME sniffing
  • Content-Security-Policy → restrict resource loading
  • Referrer-Policy → control referrer information

4. Restrict HTTP Methods

  • Allow only GET, POST, HEAD
  • Block unsafe methods like TRACE, OPTIONS, PUT, DELETE.

5. Verification

  • Use nmap –script http-security-headers to confirm headers.
  • Use nmap –script http-methods to check allowed verbs.

Testing HSTS (HTTP Strict Transport Security)

With TLS 1.0/1.1 disabled and only strong protocols available, the next step is confirming that HSTS is working as expected. HSTS ensures browsers always connect using HTTPS and won’t allow users to bypass certificate warnings.

You can test this with NMAP again

CMD: nmap –script http-security-headers -p 443 secure_baseline.bugnbuyco.local

OutPut:

┌──(zeroscorpion㉿kali)-[~]
└─$ nmap –script http-security-headers -p 443 secure_baseline.bugnbuyco.local
Starting Nmap 7.95 ( https://nmap.org ) at 2025-09-28 15:58 AEST
Nmap scan report for secure_baseline.bugnbuyco.local (10.10.20.22)
Host is up (0.0011s latency).

PORT STATE SERVICE
443/tcp open https
| http-security-headers:
| Strict_Transport_Security:
|_ HSTS not configured in HTTPS Server

Results:

  • ✅ Port 443 is open and HTTPS is working.
  • ❌ Strict-Transport-Security (HSTS) is still not configured.

👉 This means browsers can connect securely, but they aren’t being told to enforce HTTPS only. You’ll need to add the HSTS header in your web.config or via IIS response headers before the scan will confirm it.

Testing HTTP Methods

With HTTPS enforced and security headers in place, the next step is verifying which HTTP methods the server allows. IIS may expose unnecessary verbs such as TRACE, OPTIONS, PUT, or DELETE, which can be abused by attackers. Only a minimal set of methods should be enabled — typically GET, POST, and HEAD.

You can test allowed methods with:

CMD: nmap –script http-methods -p 443 secure_baseline.bugnbuyco.local

OutPut:

┌──(zeroscorpion㉿kali)-[~]
└─$ nmap --script http-methods -p 443 secure_baseline.bugnbuyco.local
Starting Nmap 7.95 ( https://nmap.org ) at 2025-09-28 16:31 AEST
Nmap scan report for secure_baseline.bugnbuyco.local (10.10.20.22)
Host is up (0.0011s latency).

PORT STATE SERVICE
443/tcp open https
| http-methods:
| Supported Methods: OPTIONS TRACE GET HEAD POST
|_ Potentially risky methods: TRACE

Results:

  • ✅ Port 443 is open and HTTPS is working.
  • ❌ The server supports additional methods: OPTIONS and TRACE.
  • ⚠️ TRACE is flagged as a potentially risky method and should be disabled for a secure baseline.

👉 Only GET, POST, and HEAD should be permitted in production.

Testing Security Headers

With HTTPS enforced and TLS configured, the next step is verifying that the site is returning the required security headers. Without these headers, browsers may allow insecure behavior such as clickjacking, MIME-type sniffing, or loading content from untrusted sources.

You can test the headers with:

CMD: nmap –script http-security-headers -p 443 secure_baseline.bugnbuyco.local

OutPut:

┌──(zeroscorpion㉿kali)-[~]
└─$ nmap --script http-security-headers -p 443 secure_baseline.bugnbuyco.local
Starting Nmap 7.95 ( https://nmap.org ) at 2025-09-28 16:36 AEST
Nmap scan report for secure_baseline.bugnbuyco.local (10.10.20.22)
Host is up (0.00096s latency).

PORT STATE SERVICE
443/tcp open https
| http-security-headers:
| Strict_Transport_Security:
|_ HSTS not configured in HTTPS Server

Results:

  • ✅ Port 443 is open and HTTPS is working.
  • ❌ Strict-Transport-Security (HSTS) is not configured.
  • ❌ Other key security headers are also missing (X-Frame-Options, X-Content-Type-Options, Content-Security-Policy, Referrer-Policy).

👉 These headers need to be added in the site’s web.config file to complete the secure baseline.

Creating the Custom web.config File

To avoid reconfiguring each new site from scratch, we’ll build a custom baseline web.config file that contains all of our hardened settings — TLS enforcement, security headers, restricted HTTP methods, and default document configuration.

This file will be stored in a central folder so it can be easily copied into the public directory of any new IIS site. By doing this, every site we set up will automatically inherit the same secure baseline without having to repeat the configuration manually in IIS Manager.

This approach ensures consistency, speed, and security across all future deployments.

File Contents:

Testing again with NMAP

HSTS and Security Headers

CMD:  nmap –script http-security-headers -p 443 secure_baseline.bugnbuyco.local

Output:

──(zeroscorpion㉿kali)-[~]
└─$ nmap --script http-security-headers -p 443 secure_baseline.bugnbuyco.local
Starting Nmap 7.95 ( https://nmap.org ) at 2025-09-28 16:56 AEST
Nmap scan report for secure_baseline.bugnbuyco.local (10.10.20.22)
Host is up (0.0010s latency).

PORT STATE SERVICE
443/tcp open https
| http-security-headers: 
| Strict_Transport_Security: 
| Header: Strict-Transport-Security: max-age=3600
| X_Frame_Options: 
| Header: X-Frame-Options: DENY
| Description: The browser must not display this content in any frame.
| X_Content_Type_Options: 
| Header: X-Content-Type-Options: nosniff
| Description: Will prevent the browser from MIME-sniffing a response away from the declared content-type. 
| Content_Security_Policy: 
| Header: Content-Security-Policy: default-src 'self';
|_ Description: Define loading policy for all resources type in case of a resource type dedicated directive is not defined (fallback).

Put Methods

CMD: nmap –script http-methods -p 443 secure_baseline.bugnbuyco.local

Output:

┌──(zeroscorpion㉿kali)-[~]
└─$ nmap --script http-methods -p 443 secure_baseline.bugnbuyco.local 
Starting Nmap 7.95 ( https://nmap.org ) at 2025-09-28 16:57 AEST
Nmap scan report for secure_baseline.bugnbuyco.local (10.10.20.22)
Host is up (0.00080s latency).

PORT STATE SERVICE
443/tcp open https
| http-methods: 
|_ Supported Methods: GET HEAD POST
MAC Address: 56:51:9B:EA:3D:AC (Unknown)

🔒 Secure Baseline Site Update

Port Bindings

  • ✅ Site is bound only to port 443 (HTTPS) — no port 80 downgrade risk.

TLS Configuration

  • ✅ Only TLS 1.2 and TLS 1.3 enabled.
  • ✅ Strong AES-GCM ciphers with Perfect Forward Secrecy.
  • ❌ TLS 1.0/1.1 fully disabled.

HTTP Methods

  • ✅ Restricted to GET, POST, HEAD.
  • ❌ TRACE, OPTIONS, PUT, DELETE blocked.

Security Headers

  • ✅ Strict-Transport-Security: max-age=3600 (testing value).
  • ✅ X-Frame-Options: DENY.
  • ✅ X-Content-Type-Options: nosniff.
  • ✅ Content-Security-Policy: default-src ‘self’;.
  • ✅ Referrer-Policy: no-referrer.

Custom web.config

  • ✅ All hardened settings captured in a reusable config file.
  • ✅ Stored centrally for easy deployment to future sites.

⚡ Status: The baseline site secure_baseline.bugnbuyco.local is now fully hardened. TLS is modern, only safe methods are allowed, core security headers are in place, and a reusable web.config ensures all future sites start secure by default.

Summary

In this walkthrough, we built secure_baseline.bugnbuyco.local as the foundation for all future IIS sites in our Active Directory environment. Starting from a clean install, we focused on security-first principles to ensure every new site inherits the same hardened posture.

Here’s what we achieved:

Folder Structure & Isolation

  • Created a dedicated site directory on a separate drive (D:\Sites\secure_baseline\) with public, private, logs, and backups folders.
  • Assigned a dedicated application pool for isolation.

TLS & Certificates

  • Bound the site to port 443 only, eliminating HTTP downgrade paths.
  • Disabled TLS 1.0/1.1, leaving only TLS 1.2 and 1.3 with strong AES-GCM ciphers and Perfect Forward Secrecy.
  • Secured the site with a certificate issued by our Ubuntu CA, trusted across the domain and Kali testing machine.

Security Headers

  • Enforced HTTPS with HSTS (Strict-Transport-Security).
  • Added baseline headers: X-Frame-Options, X-Content-Type-Options, Content-Security-Policy, and Referrer-Policy.

HTTP Methods

  • Restricted methods to only GET, POST, and HEAD.
  • Blocked risky methods such as TRACE, OPTIONS, PUT, and DELETE.

Custom web.config

  • Consolidated all hardened settings into a reusable web.config file.
  • Included default documents (index.php, index.html) and request filtering rules.
  • Stored centrally for easy deployment to every future IIS site.

By following these steps, we now have a production-ready secure baseline for IIS that supports PHP, .NET, and other applications inside an Active Directory environment. Every new site we host will start with consistent security, reducing misconfigurations and ensuring compliance with modern best practices.