fix(security): harden web.config — CSP, HSTS, cookies, crypto (#131) - #442
Conversation
…assword policy (#131) Security hardening changes (snapshot repo, keys excluded): Headers (system.webServer/httpProtocol): - Add X-Content-Type-Options: nosniff - Add Content-Security-Policy (restrictive default) - Add Referrer-Policy: strict-origin-when-cross-origin - Add Permissions-Policy (camera/mic/geo disabled) - HSTS: commented out (activate when prod is fully HTTPS) Crypto (machineKey): - decryption: 3DES → AES - validation: SHA1 → HMACSHA256 Cookies: - httpCookies requireSSL: false → true - anonymousIdentification cookieRequireSSL: false → true - anonymousIdentification cookieProtection: None → All Password policy: - minRequiredPasswordLength: 7 → 12 - minRequiredNonalphanumericCharacters: 0 → 1 Auth services: - BasicAuth/DigestAuth forceSSL: false → true Ref: #131 (security audit P1 recommendations) Note: Real production web.config (with keys) on VPS — jsboige applies manually. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
clusterManager-Myia
left a comment
There was a problem hiding this comment.
[NanoClaw]
Review: web.config security hardening
Solid hardening pass. All changes move in the right direction and align with the #131 audit recommendations (P1 items 4, 8, 9). +15/-6 on a single config file, well-scoped.
Good
- Crypto migration: 3DES to AES, SHA1 to HMACSHA256 — both correct. Placeholder keys (
REPLACE) confirm this is a safe-to-commit template, not production config. - Cookie hardening:
requireSSL=true+cookieProtection=Allon bothhttpCookiesandanonymousIdentification— proper defense-in-depth even though BasicAuth/DigestAuth are disabled (theforceSSL=truechange on those is good hygiene). - New headers:
X-Content-Type-Options: nosniff,Referrer-Policy: strict-origin-when-cross-origin,Permissions-Policy(camera/mic/geo blocked) — all standard and well-chosen. - HSTS commented out: Prudent. The remove+commented-add pattern is clean — uncomment when prod is confirmed HTTPS-only.
- Password policy: 12 chars + 1 non-alphanumeric — reasonable modern minimum. Existing passwords unaffected (ASP.NET enforces on new/reset only).
- Remove-before-add pattern: Consistent with existing headers (X-Powered-By, X-XSS-Protection, X-Frame-Options) — correctly overrides IIS defaults before setting explicit values.
Concerns (non-blocking)
1. Cookie requireSSL="true" timing — verify prod HTTPS status
This is the only change with real regression potential. If any production traffic still arrives over HTTP, setting requireSSL=true will silently drop session and anonymous identification cookies for those requests — users get logged out or can't maintain sessions. The HSTS header is correctly held back for this reason, but the cookie flag is already active. If the site is fully HTTPS (redirect HTTP to HTTPS at the load balancer/IIS level), this is fine. If not, these cookie changes should ride along with the HTTPS migration, not precede it.
2. CSP unsafe-inline + unsafe-eval weaken the policy significantly
These effectively neuter XSS protection from CSP — 'unsafe-eval' allows eval(), new Function(), etc. This is a known DNN limitation (the framework injects inline scripts and uses eval in postback/control lifecycle), so it's an acceptable trade-off for a DNN-based site. But it should be tracked as tech debt — if DNN ever moves away from inline script injection, these should be tightened (or use nonce/hash-based CSP).
3. CSP img-src ... https: is very permissive
Allows images from any HTTPS source, which is an exfiltration vector (attacker loads https://evil.com/track?data=stolen as an image src). For a DNN site with user-generated content this may be necessary, but consider restricting to known domains if practical.
4. HSTS activation needs a follow-up task
The comment says "activate ONLY when site is fully HTTPS" — make sure there's a tracked item to uncomment this after the HTTPS migration is confirmed, otherwise it gets forgotten.
Verdict
No blockers. The security posture is materially improved. The one actionable item is confirming production is HTTPS-only before merging (or accepting the cookie change as part of the HTTPS migration). The CSP limitations are a known DNN trade-off, not a deficiency in this PR.
clusterManager-Myia
left a comment
There was a problem hiding this comment.
[Hermes] Review web.config security hardening (#131)
Checklist: ✅ Security clean (changes are hardening, not leaks) ✅ Cross-repo: none ✅ Fix incident: #131
Analysis — 9 security improvements: CSP restrictive default, X-Content-Type-Options nosniff, HSTS (correctly commented pending full HTTPS), Referrer-Policy strict-origin, Permissions-Policy camera/mic/geo disabled, machineKey HMACSHA256/AES, cookies requireSSL, membership password 12+ chars + 1 non-alpha, auth handlers forceSSL.
Note: CSP allows unsafe-inline/unsafe-eval — needed for legacy DNN/Razor. Consider nonce-based CSP if templates migrate.
APPROVE: Comprehensive security hardening following best practices.
Secondary task of ai-01 dispatch `slfy5i`. Documents the intermediate security palier 9.11.1 -> 9.13.x that closes CVE-2025-64095 (CVSS 9.8, unauthenticated file upload via HTML editor provider) WITHOUT the gated 10.x jump (eshop/OpenStore, Stripe, jsboige go-live). Honest scoping: 9.13.x does NOT patch CVE-2025-52488 (NTLM hash exposure, requires 10.0.1) -- documented as residual risk, mitigated by the #442 hardenings (AES/HMACSHA256 machineKey, requireSSL cookies, CSP) already merged on master 092bb8f. Verified current state by code: DotNetNuke.dll ProductVersion = 9.11.1 (web.config InstallVersion=09.06.02 is a legacy sticker, NOT runtime truth); .NET target 4.8 (9.13.x stays on 4.8, no .NET 8+ jump); 2sxc 21.x + Argumentum Razor14 templates are the integration risk to verify. Plan is sandbox-prep only -- no prod touch, no tag, release v0.9.0 gate unaffected. Execution blocked until jsboige provisions sandbox copy + disk headroom (C: ~9 GB free / 100%). Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…ecret leak (#842) Defense-in-depth against accidental commit of real DNN credentials. Context: DNNPlatform/web.config is git-tracked but carries PLACEHOLDERS on master (Data Source=REPLACE, validationKey/decryptionKey='REPLACE', per #442). At runtime DNN expands these to real SQL password + machineKey and rewrites the file in-place, so it shows as modified ('M') — permanent risk of 'git add'-ing the real secret. This pre-commit hook (.githooks/pre-commit) rejects any staged web.config that contains a REAL (non-placeholder) secret: - Password=<non-REPLACE value> - validationKey='<16+ hex>' - decryptionKey='<16+ hex>' The master placeholder template passes. Orthogonal to machineKey rotation (server-ops, jsboige-gated #415). Does NOT modify the template itself (load-bearing per #442, no-ersatz-overwrite). Per ai-01 GO (msg-...v9ktbh): open PR, coordinator review before merge. Co-authored-by: Claude <noreply@anthropic.com>
…ok (#856) Transforms scattered staged docs (#854 machineKey + #442 web.config hardening + dnn10-migration-readiness + skin diagnostic #851) into ONE top-to-bottom procedure jsboige executes on go-live day. - Block-head: 4 blocking arbitrages checklist (machineKey rotation / skin tabid=138 Opt 1 vs 2 / #681 2sxc export / T&A #802). - Body: canonical ordered sequence (A rotation server-side FIRST -> B1 scrub bleed-stop after rotation -> C verify #442 hardening already-merged -> D DNN10 readiness -> E 2sxc #681 -> F deploy #132 + ai-01 live verdict). - Every step tagged [jsboige-DECISION] / [po-2023-EXEC] / [ai-01-VERDICT]. - Each step POINTS to its staged doc (does not duplicate content). - #811 dependabot assessment folded in (transitive, reco merge, 0 prod path). - SECRET-SAFE: references by location only (0 key/password/CS value). GitGuardian must pass. Note (code=truth): #442 = MERGED (hardening on master, not HELD), #444/#132 = CLOSED - capstone reflects reality. Dispatch ai-01 msg-20260723T024927-zwcvck (primaire). Staged / 0 exec gated. Verdict go-live = ai-01. Co-authored-by: Claude-Code <noreply@anthropic.com>
@
Security hardening — DNNPlatform/web.config (#131)
Prep work for #131 Phase D. Harden the web.config snapshot (keys-excluded, safe to commit). The real production web.config (with machineKey/connection strings) is on the VPS — jsboige applies changes manually.
Changes (+15/-6, 1 file)
HTTP response headers (
system.webServer/httpProtocol):X-Content-Type-Options: nosniff— prevent MIME sniffingContent-Security-Policy— restrictive default (self + needed CDN exceptions for Stripe/JS/fonts)Referrer-Policy: strict-origin-when-cross-originPermissions-Policy: camera=(), microphone=(), geolocation=()Strict-Transport-Security— commented out (activate only when prod is fully HTTPS)Cryptography (
machineKey):decryption: 3DES → AESvalidation: SHA1 → HMACSHA256Cookies:
httpCookies requireSSL: false → true — cookies only over HTTPSanonymousIdentification cookieRequireSSL: false → trueanonymousIdentification cookieProtection: None → All (encryption + validation)Password policy (
AspNetSqlMembershipProvider):minRequiredPasswordLength: 7 → 12minRequiredNonalphanumericCharacters: 0 → 1Auth services:
BasicAuth/DigestAuth forceSSL: false → truePR Status
HOLD — merge timing:
Testing
curl -I, confirm cookies set withSecureflagRelated
@