From 6ee05487c6e471f74ea02c996fa41403f8acd874 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Sun, 5 Jul 2026 03:38:29 +0000 Subject: [PATCH] =?UTF-8?q?=EB=B3=B4=EC=95=88=20=ED=97=A4=EB=8D=94(CSP=20?= =?UTF-8?q?=EB=B0=8F=20Referrer-Policy)=20=EC=B6=94=EA=B0=80=20=EB=B0=8F?= =?UTF-8?q?=20symlink=20=EA=B2=BD=EB=A1=9C=20=ED=95=B4=EC=84=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * HTML 생성 시 XSS, Clickjacking 방지를 위한 엄격한 Content-Security-Policy 추가 * Referrer-Policy 추가로 내부 경로 노출 방지 * topDir에 canonicalFile 대신 absoluteFile.normalize()를 사용하여 명시적 심볼릭 링크 방어 우회 방지 --- .jules/sentinel.md | 4 ++++ src/main/kotlin/html4tree/main.kt | 7 ++++--- src/test/kotlin/html4tree/MainTest.kt | 3 ++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/.jules/sentinel.md b/.jules/sentinel.md index 6c61284..562a191 100644 --- a/.jules/sentinel.md +++ b/.jules/sentinel.md @@ -22,3 +22,7 @@ **Vulnerability:** Defense in Depth (CSP Missing) **Learning:** Even when inputs are properly escaped, statically generated HTML that displays file/directory structures should implement a Content Security Policy (CSP) to provide an extra layer of defense against potential XSS bypasses. **Prevention:** Include a strict CSP meta tag (e.g., `default-src 'none'; style-src 'unsafe-inline';`) in auto-generated HTML headers when external scripts or resources are not required. +## 2024-07-05 - Enhance Security Headers for Static HTML +**Vulnerability:** Insufficient HTTP response headers in statically generated HTML (missing Referrer-Policy and strict CSP directives), potentially exposing local environment details or allowing clickjacking/base injection. +**Learning:** Even statically generated offline HTML index pages require robust security headers (via meta tags) to implement defense-in-depth, as they might be viewed in various browser contexts. +**Prevention:** Consistently apply strict Content-Security-Policy (including base-uri, form-action, frame-ancestors) and Referrer-Policy meta tags in all generated HTML templates by default. diff --git a/src/main/kotlin/html4tree/main.kt b/src/main/kotlin/html4tree/main.kt index 2e2809f..70607a7 100644 --- a/src/main/kotlin/html4tree/main.kt +++ b/src/main/kotlin/html4tree/main.kt @@ -23,7 +23,7 @@ fun main(args: Array) = Html4tree().main(args) fun go(topDir: String, maxLevel: Int) { require(topDir.isNotBlank()) - val top_dir = File(topDir).canonicalFile + val top_dir = File(topDir).absoluteFile.toPath().normalize().toFile() require(Files.isDirectory(top_dir.toPath(), LinkOption.NOFOLLOW_LINKS)) { "Top directory must be an existing non-symlink directory" } val ll = LinkedList() @@ -158,8 +158,9 @@ fun process_dir(curr_dir: File){ - - + + + ${curr_dir.getName().escapeHtml()} ${css} diff --git a/src/test/kotlin/html4tree/MainTest.kt b/src/test/kotlin/html4tree/MainTest.kt index e8a3082..7ab841d 100644 --- a/src/test/kotlin/html4tree/MainTest.kt +++ b/src/test/kotlin/html4tree/MainTest.kt @@ -159,7 +159,8 @@ class MainTest { assertTrue(htmlContent.contains("📁")) assertFalse(htmlContent.contains("test.ignore")) assertTrue(htmlContent.contains("Content-Security-Policy")) - assertTrue(htmlContent.contains("default-src 'none'; style-src 'unsafe-inline';")) + assertTrue(htmlContent.contains("default-src 'none'; style-src 'unsafe-inline'; base-uri 'none'; form-action 'none'; frame-ancestors 'none';")) + assertTrue(htmlContent.contains("name=\"referrer\" content=\"no-referrer\"")) } @Test