Share
## https://sploitus.com/exploit?id=B38D80B7-A75E-532F-A0D7-84FA50BFF413
# Lucy XSS Filter for Spring Boot

> ๋„ค์ด๋ฒ„ Lucy XSS Filter๋ฅผ ์‚ฌ์šฉํ•œ ๊ฐ•๋ ฅํ•œ XSS ๊ณต๊ฒฉ ๋ฐฉ์–ด ์†”๋ฃจ์…˜

Spring Boot ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์ฆ‰์‹œ ์ ์šฉ ๊ฐ€๋Šฅํ•œ XSS ํ•„ํ„ฐ๋ง ๋ชจ๋“ˆ์ž…๋‹ˆ๋‹ค. GET, POST, PUT, DELETE, PATCH ๋“ฑ ๋ชจ๋“  HTTP ๋ฉ”์„œ๋“œ์˜ ํŒŒ๋ผ๋ฏธํ„ฐ์™€ JSON body๋ฅผ ์ž๋™์œผ๋กœ ํ•„ํ„ฐ๋งํ•ฉ๋‹ˆ๋‹ค.

## ์ฃผ์š” ๊ธฐ๋Šฅ

โœ… **๋ชจ๋“  HTTP ๋ฉ”์„œ๋“œ ์ง€์›**
- GET, POST, PUT, DELETE, PATCH ๋“ฑ ๋ชจ๋“  ๋ฉ”์„œ๋“œ์— XSS ํ•„ํ„ฐ๋ง ์ ์šฉ
- URL ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ, Form ๋ฐ์ดํ„ฐ, JSON Request Body ๋ชจ๋‘ ์ง€์›

โœ… **HTML ์—”ํ‹ฐํ‹ฐ ๋ณ€ํ™˜**
- ์œ„ํ—˜ํ•œ ๋ฌธ์ž๋ฅผ HTML ์—”ํ‹ฐํ‹ฐ๋กœ ๋ณ€ํ™˜: `` โ†’ `>`
- ๋ฐ์ดํ„ฐ ์†์‹ค ์—†์ด ์•ˆ์ „ํ•˜๊ฒŒ ๋ณด์กด

โœ… **์Šค๋งˆํŠธ ํ•„ํ„ฐ๋ง**
- ํŒŒ์ผ ์—…๋กœ๋“œ(multipart/form-data)๋Š” ์ž๋™ ์ œ์™ธ
- ์ด์ค‘ ์น˜ํ™˜ ๋ฐฉ์ง€ ๋กœ์ง ๋‚ด์žฅ

โœ… **๊ฒ€์ฆ๋œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ**
- ๋„ค์ด๋ฒ„์—์„œ ๊ฐœ๋ฐœํ•œ Lucy XSS Filter ์‚ฌ์šฉ
- ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ ๊ฒ€์ฆ๋œ ์•ˆ์ •์„ฑ

## ๊ธฐ์ˆ  ์Šคํƒ

- Spring Boot 3.3.2+
- OpenJDK 21
- Gradle 8.5
- Lucy XSS Servlet Filter 2.0.1

## ๋น ๋ฅธ ์‹œ์ž‘

### 1. ํ”„๋กœ์ ํŠธ์— ํŒŒ์ผ ๋ณต์‚ฌ

๋‹ค์Œ ํŒŒ์ผ๋“ค์„ ๋‹น์‹ ์˜ Spring Boot ํ”„๋กœ์ ํŠธ์— ๋ณต์‚ฌํ•˜์„ธ์š”:

```
src/main/java/com/lg/common/xss/
โ”œโ”€โ”€ config/
โ”‚   โ”œโ”€โ”€ FilterConfig.java              # Filter ๋“ฑ๋ก ์„ค์ •
โ”‚   โ””โ”€โ”€ XssRequestBodyAdvice.java      # JSON body ํ•„ํ„ฐ๋ง
โ”œโ”€โ”€ filter/
โ”‚   โ”œโ”€โ”€ XssEscapeUtil.java             # HTML ์—”ํ‹ฐํ‹ฐ ๋ณ€ํ™˜ ์œ ํ‹ธ
โ”‚   โ”œโ”€โ”€ XssProtectionFilter.java       # XSS ๋ฐฉ์–ด Filter
โ”‚   โ””โ”€โ”€ XssRequestWrapper.java         # Request Wrapper
โ””โ”€โ”€ src/main/resources/
    โ””โ”€โ”€ lucy-xss-superset.xml          # Lucy XSS ์„ค์ • ํŒŒ์ผ
```

### 2. ์˜์กด์„ฑ ์ถ”๊ฐ€

`build.gradle`์— Lucy XSS ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ•˜์„ธ์š”:

```gradle
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'com.navercorp.lucy:lucy-xss-servlet:2.0.1'
}

// ์ปดํŒŒ์ผ๋Ÿฌ ์˜ต์…˜ ์ถ”๊ฐ€ (๋งค๊ฐœ๋ณ€์ˆ˜ ์ด๋ฆ„ ๋ณด์กด)
tasks.withType(JavaCompile).configureEach {
    options.compilerArgs alert('xss')' -> '<script>alert('xss')</script>'
```

## ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ

```
lucy_filter/
โ”œโ”€โ”€ src/main/java/com/lg/common/xss/
โ”‚   โ”œโ”€โ”€ XssFilterApplication.java              # ๋ฉ”์ธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ (ํ…Œ์ŠคํŠธ์šฉ)
โ”‚   โ”œโ”€โ”€ config/
โ”‚   โ”‚   โ”œโ”€โ”€ FilterConfig.java                  # โœจ Filter ๋“ฑ๋ก ์„ค์ •
โ”‚   โ”‚   โ””โ”€โ”€ XssRequestBodyAdvice.java          # โœจ JSON body ํ•„ํ„ฐ๋ง
โ”‚   โ”œโ”€โ”€ filter/
โ”‚   โ”‚   โ”œโ”€โ”€ XssEscapeUtil.java                 # โœจ HTML ์—”ํ‹ฐํ‹ฐ ๋ณ€ํ™˜ ์œ ํ‹ธ
โ”‚   โ”‚   โ”œโ”€โ”€ XssProtectionFilter.java           # โœจ XSS ๋ฐฉ์–ด Filter
โ”‚   โ”‚   โ””โ”€โ”€ XssRequestWrapper.java             # โœจ Request Wrapper
โ”‚   โ””โ”€โ”€ controller/
โ”‚       โ””โ”€โ”€ TestController.java                # ํ…Œ์ŠคํŠธ์šฉ Controller
โ”œโ”€โ”€ src/main/resources/
โ”‚   โ”œโ”€โ”€ application.properties                 # ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„ค์ •
โ”‚   โ””โ”€โ”€ lucy-xss-superset.xml                  # โœจ Lucy XSS Filter ์„ค์ •
โ”œโ”€โ”€ build.gradle                               # Gradle ๋นŒ๋“œ ํŒŒ์ผ
โ””โ”€โ”€ test-xss.ps1                               # PowerShell ํ…Œ์ŠคํŠธ ์Šคํฌ๋ฆฝํŠธ

โœจ = ํ•„์ˆ˜ ํŒŒ์ผ (๋‹ค๋ฅธ ํ”„๋กœ์ ํŠธ์— ๋ณต์‚ฌํ•ด์•ผ ํ•จ)
```

## ์•„ํ‚คํ…์ฒ˜

### ํ•„ํ„ฐ๋ง ํ๋ฆ„

```
HTTP Request
    โ†“
XssProtectionFilter (Servlet Filter)
    โ”œโ”€โ†’ multipart/form-data? โ†’ Skip (ํŒŒ์ผ ์—…๋กœ๋“œ)
    โ”œโ”€โ†’ Already filtered? โ†’ Skip (์ด์ค‘ ์น˜ํ™˜ ๋ฐฉ์ง€)
    โ””โ”€โ†’ XssRequestWrapper
            โ”œโ”€โ†’ URL ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ ํ•„ํ„ฐ๋ง
            โ””โ”€โ†’ Form ๋ฐ์ดํ„ฐ ํ•„ํ„ฐ๋ง
    โ†“
XssRequestBodyAdvice (RequestBodyAdvice)
    โ””โ”€โ†’ JSON Request Body ํ•„ํ„ฐ๋ง
    โ†“
Controller
    โ†“
Response (ํ•„ํ„ฐ๋ง๋œ ๋ฐ์ดํ„ฐ)
```

### ์ฃผ์š” ์ปดํฌ๋„ŒํŠธ

| ์ปดํฌ๋„ŒํŠธ | ์—ญํ•  | ํ•„ํ„ฐ๋ง ๋Œ€์ƒ |
|---------|------|------------|
| **XssProtectionFilter** | Servlet Filter๋กœ ๋ชจ๋“  ์š”์ฒญ์„ ๊ฐ€๋กœ์ฑ” | - |
| **XssRequestWrapper** | Request Wrapper๋กœ ํŒŒ๋ผ๋ฏธํ„ฐ ํ•„ํ„ฐ๋ง | URL ์ฟผ๋ฆฌ, Form ๋ฐ์ดํ„ฐ |
| **XssRequestBodyAdvice** | RequestBodyAdvice๋กœ JSON body ํ•„ํ„ฐ๋ง | JSON Request Body |
| **XssEscapeUtil** | HTML ์—”ํ‹ฐํ‹ฐ ๋ณ€ํ™˜ ์œ ํ‹ธ | ๋ชจ๋“  String ๊ฐ’ |

## ์‚ฌ์šฉ ์˜ˆ์‹œ

### GET ์š”์ฒญ (URL ํŒŒ๋ผ๋ฏธํ„ฐ)

**์š”์ฒญ:**
```bash
curl "http://localhost:8080/api/user?name=alert('xss')"
```

**ํ•„ํ„ฐ๋ง ๊ฒฐ๊ณผ:**
```json
{
  "name": "<script>alert('xss')</script>"
}
```

### POST ์š”์ฒญ (JSON)

**์š”์ฒญ:**
```bash
curl -X POST http://localhost:8080/api/user \
  -H "Content-Type: application/json" \
  -d '{"name":"alert(\"xss\")","email":"test@test.com"}'
```

**ํ•„ํ„ฐ๋ง ๊ฒฐ๊ณผ:**
```json
{
  "name": "<script>alert("xss")</script>",
  "email": "test@test.com"
}
```

### POST ์š”์ฒญ (Form Data)

**์š”์ฒญ:**
```bash
curl -X POST http://localhost:8080/api/user \
  -d "name=" \
  -d "email=test@test.com"
```

**ํ•„ํ„ฐ๋ง ๊ฒฐ๊ณผ:**
```json
{
  "name": "<img src=x onerror=alert(1)>",
  "email": "test@test.com"
}
```

## ์„ค์ • ์ปค์Šคํ„ฐ๋งˆ์ด์ง•

### 1. ํŠน์ • URL ์ œ์™ธํ•˜๊ธฐ

`FilterConfig.java`๋ฅผ ์ˆ˜์ •ํ•˜์—ฌ ํŠน์ • URL์„ ํ•„ํ„ฐ๋ง์—์„œ ์ œ์™ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

```java
@Bean
public FilterRegistrationBean xssFilterRegistration() {
    FilterRegistrationBean registrationBean = new FilterRegistrationBean<>();
    registrationBean.setFilter(xssProtectionFilter);
    registrationBean.addUrlPatterns("/*");

    // ํŠน์ • URL ์ œ์™ธ
    registrationBean.addInitParameter("excludeUrls", "/api/public/*,/health");

    registrationBean.setOrder(1);
    registrationBean.setName("xssProtectionFilter");
    return registrationBean;
}
```

### 2. ํ—ˆ์šฉํ•  HTML ํƒœ๊ทธ ์„ค์ •

`lucy-xss-superset.xml`์„ ์ˆ˜์ •ํ•˜์—ฌ ์•ˆ์ „ํ•œ HTML ํƒœ๊ทธ๋ฅผ ํ—ˆ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

```xml



    
    
        
            
                
                
            
        
        
        
        
        
            
                
                
            
        
    

```

### 3. ๋กœ๊น… ๋ ˆ๋ฒจ ์กฐ์ •

`application.properties`์—์„œ ๋กœ๊น… ๋ ˆ๋ฒจ์„ ์กฐ์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

```properties
# XSS ํ•„ํ„ฐ ๋กœ๊น… (DEBUG๋กœ ์„ค์ • ์‹œ ๋ชจ๋“  ํ•„ํ„ฐ๋ง ๋‚ด์—ญ ์ถœ๋ ฅ)
logging.level.com.lg.common.xss=INFO

# ํ•„ํ„ฐ๋ง ์ „ํ›„ ๊ฐ’์„ ํ™•์ธํ•˜๋ ค๋ฉด DEBUG๋กœ ๋ณ€๊ฒฝ
logging.level.com.lg.common.xss=DEBUG
```

## ํ…Œ์ŠคํŠธ

### Windows PowerShell

ํ”„๋กœ์ ํŠธ์— ํฌํ•จ๋œ `test-xss.ps1` ์Šคํฌ๋ฆฝํŠธ๋กœ ๋ชจ๋“  HTTP ๋ฉ”์„œ๋“œ๋ฅผ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

```powershell
.\test-xss.ps1
```

### ๊ฐœ๋ณ„ ํ…Œ์ŠคํŠธ

```powershell
# GET ํ…Œ์ŠคํŠธ
curl.exe "http://localhost:8080/api/test?name=alert('xss')&message=Hello"

# POST JSON ํ…Œ์ŠคํŠธ
curl.exe -X POST http://localhost:8080/api/test -H "Content-Type: application/json" -d "{\"name\":\"alert('xss')\",\"message\":\"Hello\"}"

# POST Form ํ…Œ์ŠคํŠธ
curl.exe -X POST http://localhost:8080/api/test/form -d "name=alert('xss')" -d "message=Hello"

# PUT ํ…Œ์ŠคํŠธ
curl.exe -X PUT http://localhost:8080/api/test/1 -H "Content-Type: application/json" -d "{\"title\":\"\",\"content\":\"Test\"}"

# DELETE ํ…Œ์ŠคํŠธ
curl.exe -X DELETE "http://localhost:8080/api/test/1?reason=alert('xss')"

# PATCH ํ…Œ์ŠคํŠธ
curl.exe -X PATCH http://localhost:8080/api/test/1 -H "Content-Type: application/json" -d "{\"status\":\"\"}"
```

## ์‹คํ–‰ ๋ฐฉ๋ฒ• (ํ…Œ์ŠคํŠธ ํ”„๋กœ์ ํŠธ)

### 1. Gradle ๋นŒ๋“œ

```bash
./gradlew clean build
```

### 2. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹คํ–‰

```bash
./gradlew bootRun
```

๋˜๋Š”

```bash
java -jar build/libs/lucy_filter-0.0.1-SNAPSHOT.jar
```

### 3. ์ ‘์† ํ™•์ธ

- ๊ธฐ๋ณธ ํฌํŠธ: `http://localhost:8080`
- ํ—ฌ์Šค ์ฒดํฌ: `http://localhost:8080/api/test/health`

## ์ฃผ์š” ํŠน์ง• ์ƒ์„ธ ์„ค๋ช…

### 1. ์ด์ค‘ ์น˜ํ™˜ ๋ฐฉ์ง€

`XssRequestWrapper`์—์„œ `XSS_FILTERED_ATTRIBUTE` ์†์„ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ด๋ฏธ ํ•„ํ„ฐ๋ง๋œ ์š”์ฒญ์ธ์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค:

```java
private static final String XSS_FILTERED_ATTRIBUTE = "XSS_FILTERED";

public XssRequestWrapper(HttpServletRequest request) {
    super(request);
    // ์ด์ค‘ ์น˜ํ™˜ ๋ฐฉ์ง€๋ฅผ ์œ„ํ•œ ํ”Œ๋ž˜๊ทธ ์„ค์ •
    request.setAttribute(XSS_FILTERED_ATTRIBUTE, true);
}

public static boolean isAlreadyFiltered(HttpServletRequest request) {
    return request.getAttribute(XSS_FILTERED_ATTRIBUTE) != null;
}
```

### 2. ํŒŒ์ผ ์—…๋กœ๋“œ ์ œ์™ธ

`Content-Type`์ด `multipart/form-data`์ธ ๊ฒฝ์šฐ ํ•„ํ„ฐ๋ง์„ ๊ฑด๋„ˆ๋œ๋‹ˆ๋‹ค:

```java
private boolean isMultipartRequest(HttpServletRequest request) {
    String contentType = request.getContentType();
    if (!StringUtils.hasText(contentType)) {
        return false;
    }
    return contentType.toLowerCase().startsWith(MULTIPART_FORM_DATA);
}
```

### 3. JSON Body ํ•„ํ„ฐ๋ง

`RequestBodyAdvice`๋ฅผ ๊ตฌํ˜„ํ•˜์—ฌ JSON Request Body์˜ ๋ชจ๋“  String ํ•„๋“œ๋ฅผ ํ•„ํ„ฐ๋งํ•ฉ๋‹ˆ๋‹ค:

```java
@ControllerAdvice
public class XssRequestBodyAdvice extends RequestBodyAdviceAdapter {

    @Override
    public Object afterBodyRead(Object body, HttpInputMessage inputMessage,
                               MethodParameter parameter, Type targetType,
                               Class> converterType) {

        if (body instanceof Map) {
            filterMap((Map) body);
        } else {
            filterObject(body);
        }
        return body;
    }
}
```

## ๋กœ๊ทธ ํ™•์ธ

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹คํ–‰ ์‹œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋กœ๊ทธ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

```
2026-01-23 14:30:00 - XSS Protection Filter initialized successfully
2026-01-23 14:30:00 - XSS Filter test: 'alert('xss')' -> '&lt;script&gt;alert(&#39;xss&#39;)&lt;/script&gt;'
2026-01-23 14:30:15 - Applying XSS filter to GET request: /api/test
2026-01-23 14:30:15 - XSS filtered [param: name] 'alert('xss')' -> '&lt;script&gt;alert(&#39;xss&#39;)&lt;/script&gt;'
2026-01-23 14:30:20 - Applying XSS filter to POST request: /api/test
2026-01-23 14:30:20 - XSS filtered [JSON field: name] 'alert('xss')' -> '&lt;script&gt;alert(&#39;xss&#39;)&lt;/script&gt;'
2026-01-23 14:30:25 - Skipping XSS filter for multipart request: POST /api/test/upload
```

## ์„ฑ๋Šฅ ๊ณ ๋ ค์‚ฌํ•ญ

### ํ•„ํ„ฐ๋ง ์˜ค๋ฒ„ํ—ค๋“œ

- **URL ํŒŒ๋ผ๋ฏธํ„ฐ/Form ๋ฐ์ดํ„ฐ**: ๋งค์šฐ ๋‚ฎ์Œ (< 1ms)
- **JSON Body**: ๋‚ฎ์Œ (1-5ms, ๋ฐ์ดํ„ฐ ํฌ๊ธฐ์— ๋”ฐ๋ผ ๋‹ค๋ฆ„)
- **๋Œ€์šฉ๋Ÿ‰ ์š”์ฒญ**: JSON body๊ฐ€ ํฐ ๊ฒฝ์šฐ ํ•„ํ„ฐ๋ง ์‹œ๊ฐ„ ์ฆ๊ฐ€ ๊ฐ€๋Šฅ

### ์ตœ์ ํ™” ํŒ

1. **ํŠน์ • URL ์ œ์™ธ**: ์„ฑ๋Šฅ์ด ์ค‘์š”ํ•œ API๋Š” ํ•„ํ„ฐ๋ง์—์„œ ์ œ์™ธ
2. **๋กœ๊น… ๋ ˆ๋ฒจ ์กฐ์ •**: ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ๋Š” INFO ๋ ˆ๋ฒจ ์‚ฌ์šฉ
3. **ํ•„ํ„ฐ ์ˆœ์„œ**: `FilterConfig`์—์„œ `setOrder(1)`๋กœ ๊ฐ€์žฅ ๋จผ์ € ์‹คํ–‰๋˜๋„๋ก ์„ค์ •

## ์ฃผ์˜์‚ฌํ•ญ

1. **์„ฑ๋Šฅ**: ๋ชจ๋“  ์š”์ฒญ์— ํ•„ํ„ฐ๋ง์ด ์ ์šฉ๋˜๋ฏ€๋กœ ๋Œ€์šฉ๋Ÿ‰ ํŠธ๋ž˜ํ”ฝ ํ™˜๊ฒฝ์—์„œ๋Š” ์„ฑ๋Šฅ ํ…Œ์ŠคํŠธ ํ•„์š”
2. **ํ—ˆ์šฉ ํƒœ๊ทธ ์„ค์ •**: ๋น„์ฆˆ๋‹ˆ์Šค ์š”๊ตฌ์‚ฌํ•ญ์— ๋งž๊ฒŒ `lucy-xss-superset.xml` ์ˆ˜์ • ํ•„์š”
3. **JSON ์‘๋‹ต**: ํ•„ํ„ฐ๋ง๋œ ๋ฐ์ดํ„ฐ๋Š” HTML ์—”ํ‹ฐํ‹ฐ๋กœ ๋ณ€ํ™˜๋˜์–ด ๋ฐ˜ํ™˜๋จ
4. **๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค**: ํ•„ํ„ฐ๋ง๋œ ๋ฐ์ดํ„ฐ๊ฐ€ ๊ทธ๋Œ€๋กœ ์ €์žฅ๋˜๋ฏ€๋กœ, ์ €์žฅ ์ „ ๋””์ฝ”๋”ฉ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ ๋ณ„๋„ ์ฒ˜๋ฆฌ ํ•„์š”

## FAQ

### Q1. ์ด๋ฏธ ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ์—๋„ ์ ์šฉ๋˜๋‚˜์š”?
์•„๋‹ˆ์š”. XSS ํ•„ํ„ฐ๋Š” HTTP ์š”์ฒญ ์‹œ์ ์—๋งŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฏธ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ๋Š” ๋ณ„๋„๋กœ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

### Q2. React/Vue ๊ฐ™์€ ํ”„๋ก ํŠธ์—”๋“œ ํ”„๋ ˆ์ž„์›Œํฌ์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•ด๋„ ๋˜๋‚˜์š”?
๋„ค, ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ํ”„๋ก ํŠธ์—”๋“œ ํ”„๋ ˆ์ž„์›Œํฌ์˜ XSS ๋ฐฉ์–ด์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค์ธต ๋ฐฉ์–ด๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

### Q3. HTML ์—”ํ‹ฐํ‹ฐ๋ฅผ ์›๋ณธ์œผ๋กœ ๋˜๋Œ๋ฆฌ๋ ค๋ฉด?
Spring์˜ `HtmlUtils.htmlUnescape()` ๋˜๋Š” Apache Commons์˜ `StringEscapeUtils.unescapeHtml4()`๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.

### Q4. ํŠน์ • ํ•„๋“œ๋งŒ ํ•„ํ„ฐ๋งํ•˜๊ฑฐ๋‚˜ ์ œ์™ธํ•  ์ˆ˜ ์žˆ๋‚˜์š”?
`XssRequestBodyAdvice`๋ฅผ ์ˆ˜์ •ํ•˜์—ฌ ํŠน์ • ํ•„๋“œ๋ฅผ ์ œ์™ธํ•˜๊ฑฐ๋‚˜, ์–ด๋…ธํ…Œ์ด์…˜ ๊ธฐ๋ฐ˜ ํ•„ํ„ฐ๋ง์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

### Q5. REST API๊ฐ€ ์•„๋‹Œ ์ผ๋ฐ˜ MVC์—์„œ๋„ ์ž‘๋™ํ•˜๋‚˜์š”?
๋„ค, Servlet Filter ๊ธฐ๋ฐ˜์ด๋ฏ€๋กœ Spring MVC, Thymeleaf ๋“ฑ ๋ชจ๋“  Spring ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

## ๊ธฐ์—ฌ

์ด ํ”„๋กœ์ ํŠธ๋Š” ์˜คํ”ˆ์†Œ์Šค์ž…๋‹ˆ๋‹ค. ๋ฒ„๊ทธ ๋ฆฌํฌํŠธ, ๊ธฐ๋Šฅ ์ œ์•ˆ, Pull Request๋ฅผ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค.

## ๋ผ์ด์„ ์Šค

์ด ํ”„๋กœ์ ํŠธ๋Š” ํ•™์Šต ๋ฐ ์ฐธ๊ณ ์šฉ์œผ๋กœ ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค. ์ž์œ ๋กญ๊ฒŒ ์‚ฌ์šฉํ•˜๊ณ  ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

## ์ฐธ๊ณ  ์ž๋ฃŒ

- [๋„ค์ด๋ฒ„ Lucy XSS Filter ๊ณต์‹ ๋ฌธ์„œ](https://github.com/naver/lucy-xss-filter)
- [OWASP XSS Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html)
- [Spring Security XSS Protection](https://docs.spring.io/spring-security/reference/features/exploits/headers.html#headers-xss-protection)

---

**Made with โค๏ธ for secure Spring Boot applications**