From cd06a0a1ed36e13da5702dbab249fedb503548b8 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Mon, 29 Jun 2026 04:55:15 +0000 Subject: [PATCH] =?UTF-8?q?=EB=B3=B4=EC=95=88:=20=ED=8C=8C=EC=9D=BC/?= =?UTF-8?q?=EB=94=94=EB=A0=89=ED=86=A0=EB=A6=AC=EB=AA=85=20XSS=20=EB=B0=A9?= =?UTF-8?q?=EC=96=B4=20=EB=B0=8F=20URL=20=EC=9D=B8=EC=BD=94=EB=94=A9=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `escapeHtml` 및 `encodeUrlPath` 확장 함수 추가 - `process_dir` 내 HTML 렌더링 시 디렉토리 및 파일명에 이스케이프 및 URL 인코딩 적용 - Jacoco 설정 및 명령어 커버리지 100% 테스트 코드 작성 --- .jules/sentinel.md | 4 + build.gradle | 10 ++ src/main/kotlin/html4tree/main.kt | 24 +++- src/test/kotlin/html4tree/GoFailTest.kt | 19 +++ src/test/kotlin/html4tree/Html4treeTest.kt | 125 ++++++++++++++++++ .../html4tree/LinkedListPullNullTest.kt | 16 +++ src/test/kotlin/html4tree/LinkedListTest.kt | 19 +++ src/test/kotlin/html4tree/MainKtEdgeTest.kt | 24 ++++ src/test/kotlin/html4tree/MainKtTest.kt | 18 +++ src/test/kotlin/html4tree/UtilTest.kt | 38 ++++++ 10 files changed, 294 insertions(+), 3 deletions(-) create mode 100644 .jules/sentinel.md create mode 100644 src/test/kotlin/html4tree/GoFailTest.kt create mode 100644 src/test/kotlin/html4tree/Html4treeTest.kt create mode 100644 src/test/kotlin/html4tree/LinkedListPullNullTest.kt create mode 100644 src/test/kotlin/html4tree/LinkedListTest.kt create mode 100644 src/test/kotlin/html4tree/MainKtEdgeTest.kt create mode 100644 src/test/kotlin/html4tree/MainKtTest.kt create mode 100644 src/test/kotlin/html4tree/UtilTest.kt diff --git a/.jules/sentinel.md b/.jules/sentinel.md new file mode 100644 index 00000000..653a1c2b --- /dev/null +++ b/.jules/sentinel.md @@ -0,0 +1,4 @@ +## 2023-10-25 - XSS 및 URL 인코딩 취약점 수정 (Sentinel) +**Vulnerability:** `html4tree`의 `process_dir` 로직에서 디렉토리 및 파일명을 이스케이프 및 인코딩 없이 직접 HTML의 링크와 타이틀, `href` 속성에 바인딩하여 XSS 공격 및 띄어쓰기가 있는 파일명 접근 에러(URL Path 깨짐)가 발생할 수 있었습니다. +**Learning:** 단순한 `String` 이어붙이기 방식으로 HTML을 렌더링할 때는 사용자 입력이나 외부 상태(이 경우 파일 시스템 상의 파일 이름)에 의해 브라우저가 악의적인 스크립트를 파싱하게 될 위험성이 존재한다는 것을 이 코드베이스에서 확인할 수 있었습니다. 특히 Kotlin의 raw string literal(`"""`)을 사용할 때도 변수 삽입 부분은 철저히 필터링되어야 합니다. +**Prevention:** `String.escapeHtml()`과 `String.encodeUrlPath()`라는 확장 함수를 만들어 HTML 엔티티 치환(특히 `<`, `>`, `&`, `"`, `'`)과 `java.net.URLEncoder.encode`를 결합하여 안전하게 출력하도록 수정했습니다. 나아가, 추후 유사한 HTML 템플릿 렌더링 시에는 파일명과 같이 통제 불가능한 문자열에 대해서는 항상 이스케이프 함수를 거치도록 해야 합니다. diff --git a/build.gradle b/build.gradle index 8e088074..f82a80da 100644 --- a/build.gradle +++ b/build.gradle @@ -11,9 +11,19 @@ buildscript { apply plugin: 'kotlin' apply plugin: 'application' +apply plugin: 'jacoco' mainClassName = 'html4tree.MainKt' +jacocoTestReport { + reports { + xml.enabled false + csv.enabled false + html.enabled true + } +} +test.finalizedBy jacocoTestReport + defaultTasks 'build' repositories { diff --git a/src/main/kotlin/html4tree/main.kt b/src/main/kotlin/html4tree/main.kt index daaead3d..609f4c71 100644 --- a/src/main/kotlin/html4tree/main.kt +++ b/src/main/kotlin/html4tree/main.kt @@ -74,6 +74,18 @@ fun process_ignore_file(curr_dir: File): List { return files_to_exclude } +fun String.escapeHtml(): String { + return this.replace("&", "&") + .replace("<", "<") + .replace(">", ">") + .replace("\"", """) + .replace("'", "'") +} + +fun String.encodeUrlPath(): String { + return java.net.URLEncoder.encode(this, "UTF-8").replace("+", "%20") +} + fun process_dir(curr_dir: File){ val exclude: List = process_ignore_file(curr_dir) @@ -86,14 +98,15 @@ fun process_dir(curr_dir: File){ """ + val escapedDirName = curr_dir.getName().escapeHtml() val index_top = """ - ${curr_dir.getName()} + ${escapedDirName} ${css} -

${curr_dir.getName()}

+

${escapedDirName}