Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .jules/sentinel.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,8 @@
**Vulnerability:** 정적 HTML 생성 λ„κ΅¬μ—μ„œ 맀번 λ‹€λ₯Έ Nonceλ₯Ό λ™μ μœΌλ‘œ μƒμ„±ν•˜μ—¬ CSP에 μ μš©ν•˜λŠ” 것은, 캐싱 νš¨μœ¨μ„ μ €ν•˜μ‹œν‚¬ 뿐만 μ•„λ‹ˆλΌ 정적 배포 ν™˜κ²½(예: GitHub Pages λ“±)μ—μ„œ μ˜¬λ°”λ₯Έ λ³΄μ•ˆ μ •μ±… μˆ˜λ¦½μ„ λ°©ν•΄ν•  수 μžˆλŠ” μ•ˆν‹° νŒ¨ν„΄μž…λ‹ˆλ‹€.
**Learning:** μ •μ μœΌλ‘œ κ³ μ •λœ 인라인 μŠ€νƒ€μΌμ΄λ‚˜ μŠ€ν¬λ¦½νŠΈμ—λŠ” λ‚œμˆ˜ν™”λœ Nonce보닀 μ½˜ν…μΈ  자체의 ν•΄μ‹œ(SHA-256 λ“±)λ₯Ό μ‚¬μš©ν•˜λŠ” 것이 μ•ˆμ „ν•˜κ³  μΌκ΄€λœ λ°©μ‹μž„μ„ λ°°μ› μŠ΅λ‹ˆλ‹€.
**Prevention:** μžλ™ μƒμ„±λ˜λŠ” 정적 HTML의 μ½˜ν…μΈ  λ³΄μ•ˆ μ •μ±…(CSP)μ—λŠ” `style-src 'sha256-<HASH>'` 방식을 μ μš©ν•˜κ³ , `<style>` νƒœκ·Έμ—μ„œ λΆˆν•„μš”ν•œ `nonce` 속성을 μ œκ±°ν•˜μ—¬ λΈŒλΌμš°μ €μ˜ 무결성 검증 κΈ°λŠ₯을 적극 ν™œμš©ν•˜μ‹­μ‹œμ˜€.

## 2024-07-22 - [html4tree] μ›μžμ  파일 μ“°κΈ°(Atomic Move) 지원
**Vulnerability:** 파일이 μ“°μ—¬μ§€λŠ” λ™μ•ˆ(예: `index.html` 생성 쀑) λΆ€λΆ„μ μœΌλ‘œ μ™„μ„±λœ νŒŒμΌμ„ λ‹€λ₯Έ ν”„λ‘œμ„ΈμŠ€κ°€ 읽게 λ˜μ–΄ λ°œμƒν•  수 μžˆλŠ” 레이슀 μ»¨λ””μ…˜ 및 TOCTOU 취약점.
**Learning:** 정적 파일 생성 κ³Όμ •μ—μ„œ μž„μ‹œ νŒŒμΌμ„ μ΄λ™μ‹œν‚¬ λ•Œ λ‹¨μˆœνžˆ `REPLACE_EXISTING`만 μ‚¬μš©ν•˜λ©΄ 파일 μ‹œμŠ€ν…œμ— 따라 μ™„μ „νžˆ μ›μžμ μœΌλ‘œ 볡사/μ΄λ™λ˜μ§€ μ•Šμ„ 수 μžˆμŠ΅λ‹ˆλ‹€.
**Prevention:** `Files.move` μ‹œ `StandardCopyOption.ATOMIC_MOVE`λ₯Ό μ‚¬μš©ν•˜κ³ , ν•΄λ‹Ή μ˜΅μ…˜μ„ μ§€μ›ν•˜μ§€ μ•ŠλŠ” 파일 μ‹œμŠ€ν…œμ„ μœ„ν•΄ `AtomicMoveNotSupportedException` λ°œμƒ μ‹œ `REPLACE_EXISTING`으둜 λŒ€μ²΄ν•˜λŠ” Fallback λ‘œμ§μ„ κ΅¬ν˜„ν•˜μ—¬ μ•ˆμ „ν•œ 파일 μ—…λ°μ΄νŠΈλ₯Ό 보μž₯ν•΄μ•Ό ν•©λ‹ˆλ‹€.
Comment on lines +88 to +90
15 changes: 13 additions & 2 deletions src/main/kotlin/html4tree/main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package html4tree

import java.io.File
import java.security.MessageDigest
import java.nio.file.AtomicMoveNotSupportedException
import java.nio.file.Files
import java.nio.file.LinkOption
import java.nio.file.StandardCopyOption
Expand Down Expand Up @@ -229,12 +230,22 @@ fun process_ignore_file(curr_dir: File, dirFilesNames: Array<String>? = null): S
return files_to_exclude
}

fun write_index_file(curr_dir: File, content: String) {
fun write_index_file(
curr_dir: File,
content: String,
moveFile: (java.nio.file.Path, java.nio.file.Path) -> Unit = { source, target ->
Files.move(source, target, StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING)
}
) {
val indexPath = curr_dir.toPath().resolve("index.html")
val tempPath = Files.createTempFile(curr_dir.toPath(), ".index-", ".html")
try {
Files.write(tempPath, content.toByteArray(Charsets.UTF_8))
Files.move(tempPath, indexPath, StandardCopyOption.REPLACE_EXISTING)
try {
moveFile(tempPath, indexPath)
} catch (e: AtomicMoveNotSupportedException) {
Files.move(tempPath, indexPath, StandardCopyOption.REPLACE_EXISTING)
}
Comment on lines +244 to +248
} finally {
Files.deleteIfExists(tempPath)
}
Expand Down
13 changes: 13 additions & 0 deletions src/test/kotlin/html4tree/MainTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -705,4 +705,17 @@ class MainTest {
assertFalse(processed, "fileKey mismatch should skip directory processing")
assertFalse(listed, "fileKey mismatch should skip child listing")
}

@Test
fun testWriteIndexFileAtomicMoveFallback() {
val testFile = File(tempDir, "testWriteIndexDir")
testFile.mkdir()
Comment on lines +711 to +712

write_index_file(testFile, "content") { source, target ->
throw java.nio.file.AtomicMoveNotSupportedException(source.toString(), target.toString(), "Mocked")
}
val indexFile = File(testFile, "index.html")
assertTrue(indexFile.exists())
assertEquals("content", indexFile.readText())
}
}
Loading