|
| 1 | +--- |
| 2 | +title: "[Security] Secure Coding(7-2) - XSS 진단 및 대응" |
| 3 | + |
| 4 | +categories: [Security, Secure Coding] |
| 5 | +tags: |
| 6 | + - [Security, Cyberattacks, 보안, 시큐어 코딩, XSS, Cross site scripting] |
| 7 | +toc: true |
| 8 | +toc_sticky: true |
| 9 | + |
| 10 | +date: 2025-10-15 |
| 11 | +last_modified_at: 2025-10-15 |
| 12 | +--- |
| 13 | +>🔒 시큐어 코딩 수업 정리 |
| 14 | +
|
| 15 | +## XSS |
| 16 | +📚**<span style="color: #008000">XSS</span>**: 검증되지 않은 외부 입력 값을 웹 응답에 그대로 반영하여 **악의적 스크립트가 실행**되는 취약점 |
| 17 | +→ 사용자 브라우저에서 악성 코드가 동작해, 쿠키· 세션 등 민감 정보 탈취 가능 |
| 18 | + |
| 19 | +**발생 원인** |
| 20 | +* 외부에서 입력된 사용자 입력 값을 검증하지 않고 그대로 응답에 반영 |
| 21 | +* DB에 저장된 데이터를 읽어서 출력할 때 DB에서 읽어온 값을 검증하지 않고 출력 값으로 사용 |
| 22 | +* 자바스크립트로 DOM구조를 조작하여 페이지를 변경하는 경우 변경되는 내용을 검증하지 않고 브라우저에 표시하는 경우 |
| 23 | + |
| 24 | +### XSS 공격 흐름 |
| 25 | + |
| 26 | + |
| 27 | + |
| 28 | +### XSS 3가지 유형 |
| 29 | + |
| 30 | +#### 🔄 Reflected XSS (반사형) |
| 31 | +* 사용자 입력이 **즉시 반영**되어 페이지에 표시 |
| 32 | +* 검색창, URL 파라미터 등을 통해 스크립트가 반사되어 실행 |
| 33 | +* 일회성 공격 |
| 34 | + |
| 35 | +#### 💾 Stored XSS (저장형) |
| 36 | +* 게시판, 댓글, 프로필 등 DB에 악성 스크립트가 저장되어 **다수 사용자에게 전파** |
| 37 | +* 지속적인 공격 |
| 38 | + |
| 39 | +#### 🌐 DOM-based XSS |
| 40 | +* 클라이언트 측 스크립트(DOM 조작)에서 발생 |
| 41 | +* `location.hash`, `location.search` 등 브라우저 객체를 통한 동적 스크립트 삽입 |
| 42 | +* 서버 로그에 기록되지 않음 → 탐지가 어려움 |
| 43 | + |
| 44 | +### XSS 공격 피해 |
| 45 | +1. **세션 쿠키 탈취** |
| 46 | +* 자동 로그인, 권한 정보 등 노출 |
| 47 | + |
| 48 | +2. **사용자 계정·개인정보 유출** |
| 49 | +* 이메일, 전화번호, 주소 등 민감 정보 수집 |
| 50 | +* 폼에 입력한 비밀번호나 카드 정보 탈취 |
| 51 | + |
| 52 | +3. **브라우저 무단 제어** |
| 53 | +* 임의 스크립트 실행 → 가짜 폼 표시 |
| 54 | +* 피싱 페이지로 이동 |
| 55 | +* 내부 네트워크 스캔 등 |
| 56 | + |
| 57 | +4. **기업 이미지 타격** |
| 58 | +* 웹사이트 변조로 신뢰도 하락 |
| 59 | +* 고객 정보 유출로 인한 법적 문제 |
| 60 | + |
| 61 | +--- |
| 62 | + |
| 63 | +## XSS 취약점 진단 |
| 64 | + |
| 65 | +### Reflected XSS |
| 66 | +* 사용자가 요청한 값을 **서버에서 검증하지 않고 응답으로 사용하는 경우** 발생 |
| 67 | + |
| 68 | + |
| 69 | + |
| 70 | + |
| 71 | + |
| 72 | +### Stored XSS |
| 73 | +* 공격자가 서버에 저장한 스크립트를 사용자가 열람하는 경우 스크립트가 다운로드 되어 사용자의 브라우저에서 실행 |
| 74 | + |
| 75 | + |
| 76 | + |
| 77 | + |
| 78 | + |
| 79 | +### DOM 기반 XSS |
| 80 | +* 자바스크립트로 DOM 객체 정보를 사용하여 Document에 write를 수행하는 경우 스크립트가 사용자의 브라우저에서 실행 |
| 81 | + |
| 82 | + |
| 83 | + |
| 84 | + |
| 85 | + |
| 86 | +--- |
| 87 | + |
| 88 | +## XSS 취약점 방어 |
| 89 | + |
| 90 | +### 입출력 값 검증 및 필터링 |
| 91 | +* **제한적인 입력 값 허용** |
| 92 | + * 클라이언트 프로그램과 서버 애플리케이션에서 [HTTP 헤더, 쿠키, 쿼리 스트링, 폼 필드, 히든 필드] 등의 모든 인자들에 대해 허용된 유형의 데이터만을 받아들이도록 **정규식을 이용하여 제한된 입력 값을 받아서 처리** |
| 93 | +* **제한적인 출력 값 허용** |
| 94 | + * 입력 값이나 DB에서 조회한 결과 값을 응답으로 내보내기전에 `XssFilter`를 적용하여 동적으로 스크립트가 실행될 수 있는 요소들은 HTML인코딩을 적용하여 출력 |
| 95 | + |
| 96 | + |
| 97 | +> 필터링 또는 변환되어야 하는 특수문자들 |
| 98 | +
|
| 99 | + |
| 100 | +> 차단되어야 하는 태그들 |
| 101 | +
|
| 102 | +--- |
| 103 | + |
| 104 | +### HTML 엔티티 이스케이프 처리 |
| 105 | +📚**<span style="color: #008000">HTML 엔티티 이스케이프(Entity Escape)</span>**: HTML 문서에서 특수 문자가 브라우저에 의해 태그나 코드로 해석되지 않도록, **해당 문자를 엔티티 코드(예: `<` → `<`)로 변환하는 기법** |
| 106 | + |
| 107 | +✅**XSS 공격 방어 방법** |
| 108 | +* 사용자 입력에 포함된 `<script>` 태그 등 악의적인 스크립트가 실행되지 않도록 보호 |
| 109 | +* 서버와 클라이언트 모두에서 출력 전에 반드시 이스케이프 처리 필요 |
| 110 | + * **동적 콘텐츠 출력 시** (특히 사용자 입력을 직접 HTML에 삽입하는 경우) |
| 111 | + |
| 112 | +* **❌취약한 코드 예시** |
| 113 | + |
| 114 | +```javascript |
| 115 | +// 사용자 입력을 가져와서 그대로 innerHTML에 할당 (취약) |
| 116 | +var userInput = getUserInput(); |
| 117 | +document.getElementById("content").innerHTML = userInput; |
| 118 | +``` |
| 119 | + |
| 120 | +* **공격 시나리오** |
| 121 | + * 사용자가 `<script>alert('XSS');</script>`와 같은 입력을 전달하면, **해당 스크립트가 실행**되어 공격자가 쿠키 탈취, 세션 하이재킹 등 다양한 공격을 수행할 수 있음 |
| 122 | + |
| 123 | +* ✅**안전한 코드 예시** |
| 124 | +* 방법 1: **사용자 입력 이스케이프 함수 적용** |
| 125 | + |
| 126 | +```javascript |
| 127 | +//사용자 입력을 HTML 엔티티로 변환하는 함수를 사용하여 안전하게 출력 |
| 128 | +function escapeHtml(text) { |
| 129 | +return text.replace(/&/g, "&") |
| 130 | + .replace(/</g, "<") |
| 131 | + .replace(/>/g, ">") |
| 132 | + .replace(/"/g, """) |
| 133 | + .replace(/'/g, "'"); |
| 134 | +} |
| 135 | + |
| 136 | +var userInput = getUserInput(); // 예: "<script>alert('XSS');</script>" |
| 137 | +var safeInput = escapeHtml(userInput); |
| 138 | +document.getElementById("content").innerHTML = safeInput; |
| 139 | +``` |
| 140 | + |
| 141 | +* 방법 2: **textContent 속성 사용** |
| 142 | + |
| 143 | +```javascript |
| 144 | +//DOM에 텍스트만 삽입하여 브라우저가 HTML로 해석하지 않도록 함 |
| 145 | +var userInput = getUserInput(); // 사용자 입력 |
| 146 | +document.getElementById("content").textContent = userInput; |
| 147 | +``` |
| 148 | + |
| 149 | +--- |
| 150 | + |
| 151 | +### Spring Web MVC에서 입출력 필터링 |
| 152 | + |
| 153 | + |
| 154 | + |
| 155 | +--- |
| 156 | + |
| 157 | +### CSP(Content-Security-Policy) 적용 |
| 158 | +* **HTTP 응답 헤더 CSP를 통해 설정함** |
| 159 | + |
| 160 | +✅**XSS 공격 방어 효과** |
| 161 | +* **인라인 스크립트 차단** |
| 162 | + * 기본적으로 'unsafe-inline' 없이 **스크립트 실행을 제한**하여, 악의적으로 삽입된 인라인 코드가 실행되지 않도록 함 |
| 163 | + |
| 164 | +* **신뢰하는 스크립트만 허용** |
| 165 | + * 신뢰할 수 있는 도메인에서 제공하는 스크립트만 로드하게 하여, **외부 공격자의 스크립트 주입 차단** |
| 166 | + |
| 167 | +* **동적 코드 실행 방지** |
| 168 | + * `eval()`이나 `new Function()` 같은 동적 코드 실행을 제한할 수 있음 |
| 169 | + |
| 170 | +* XSS 방어와 CSP의 연계 |
| 171 | + * CSP는 XSS 취약점이 존재하더라도, 악의적 스크립트 실행을 실질적으로 차단하여 추가적인 방어층을 제공 |
| 172 | + |
| 173 | + |
| 174 | +> 예시: 웹 서버별 CSP 헤더 설정 |
0 commit comments