내 웹사이트도 안전할까? 개발자가 알아야 할 “반사형 XSS”
들어가며
웹사이트를 개발하다 보면 검색창이나 게시판, 로그인 페이지처럼 사용자가 직접 값을 입력하는 기능을 정말 많이 만들게 됩니다.
처음 개발할 때는 이런 생각을 하기 쉽습니다.
“사용자가 입력한 값을 받아서 검색 결과에 보여주면 되는 거 아닌가?”
저도 처음에는 크게 다르지 않았습니다.
그런데 어느 순간부터 사용자가 입력한 값을 화면에 다시 보여주는 부분을 유심히 확인하게 됐습니다.
바로 여기에서 웹 보안 문제 중 하나인 반사형 XSS(Reflected XSS)가 발생할 수 있기 때문입니다.
특히 검색어, URL 파라미터, 에러 메시지처럼 사용자가 전달한 값이 페이지에 그대로 출력되는 구조라면 한 번쯤 확인해볼 필요가 있습니다.
반사형 XSS란?
XSS는 Cross-Site Scripting(크로스 사이트 스크립팅)의 약자입니다.
쉽게 말하면 공격자가 웹 페이지에 의도하지 않은 스크립트가 실행될 수 있는 값을 전달하고, 웹 애플리케이션이 이를 제대로 처리하지 않은 상태로 다시 브라우저에 출력하면서 문제가 발생하는 방식입니다.
그중에서도 반사형 XSS는 이름 그대로 사용자의 입력값이 서버를 거쳐 다시 응답에 포함되어 브라우저에서 처리되는 형태입니다.
대표적인 흐름은 상당히 단순합니다.
사용자 입력 → 서버 전달 → 서버 응답에 입력값 포함 → 브라우저에서 출력
문제는 서버가 사용자의 입력값을 단순한 문자로 처리하지 않고 HTML이나 JavaScript 코드로 해석될 수 있는 형태로 출력할 때 발생합니다.
검색 기능에서도 발생할 수 있다
반사형 XSS를 설명할 때 게시판이나 댓글만 생각하는 경우가 있는데, 실제로는 검색 기능에서도 주의해야 합니다.
예를 들어 검색 페이지가 다음과 같은 구조라고 생각해보겠습니다.
/search?keyword=검색어
사용자가 축구를 검색하면 화면에 다음처럼 표시할 수 있습니다.
검색 결과: 축구
여기까지는 아무런 문제가 없어 보입니다.
그런데 서버에서 keyword 값을 검증하거나 안전하게 인코딩하지 않은 채 HTML에 그대로 삽입한다면 문제가 될 수 있습니다.
개발할 때는 단순히 검색어를 다시 보여주는 기능이라고 생각했지만, 보안 관점에서는 “사용자가 입력한 값을 신뢰해서 화면에 출력하고 있다”는 것이 핵심적인 문제입니다.
왜 반사형 XSS가 위험할까?
반사형 XSS의 위험성은 사용자가 입력한 값이 단순한 텍스트가 아니라 브라우저에서 실행 가능한 코드로 해석될 수 있다는 데 있습니다.
취약한 웹 페이지에서 공격자가 악의적인 입력값이 포함된 URL을 만들어 다른 사용자에게 전달한다고 생각해보겠습니다.
사용자가 해당 링크를 클릭하면 서버는 요청을 처리하고, 공격자가 넣어둔 값이 포함된 페이지를 다시 반환할 수 있습니다.
만약 해당 값이 안전하게 처리되지 않았다면 브라우저가 이를 HTML이나 스크립트로 해석할 가능성이 있습니다.
이 때문에 XSS는 단순한 화면 깨짐 문제가 아닙니다.
웹 애플리케이션의 구조와 인증 방식에 따라 사용자 정보 노출이나 다른 보안 문제로 이어질 가능성이 있기 때문에 반드시 방어해야 하는 취약점입니다.
개발하면서 가장 먼저 확인해야 하는 부분
반사형 XSS를 점검할 때 저는 “사용자가 입력한 값이 어디로 들어가서 어디에 출력되는가?”를 먼저 보는 것이 중요하다고 생각합니다.
특히 다음과 같은 값을 확인해볼 만합니다.
- URL Query String
- Path Parameter
- 검색어
- 로그인 실패 메시지
- 게시판 입력값
- 에러 메시지
- HTTP Header에서 전달되는 값
- 사용자가 입력한 이름이나 닉네임
예를 들어 서버에서 다음과 같은 값을 받았다고 가정해보겠습니다.
keyword
그리고 이 값을 별도의 검증 없이 HTML에 삽입한다면 문제가 발생할 가능성이 있습니다.
중요한 것은 사용자가 입력한 값은 기본적으로 신뢰하지 않는다는 원칙입니다.
내가 만든 서비스의 사용자라고 해서 입력값까지 안전하다고 볼 수는 없기 때문입니다.
가장 기본적인 방어 방법은 출력값 인코딩
XSS 방어에서 가장 중요한 개념 중 하나가 출력 시점의 인코딩(Output Encoding)입니다.
사용자가 입력한 문자열을 HTML 코드가 아니라 단순한 텍스트로 브라우저가 인식하도록 처리하는 것입니다.
예를 들어 사용자가 <, >, ", ', & 같은 특수문자를 입력했을 때 이를 적절하게 HTML 엔티티 등으로 변환해서 출력하면 브라우저가 해당 값을 HTML 태그나 코드로 해석하지 않고 문자로 표시하도록 만들 수 있습니다.
개념적으로 보면 다음과 같은 차이가 있습니다.
사용자 입력
↓
서버 처리
↓
HTML에 그대로 삽입 ← 위험
보다는
사용자 입력
↓
서버 처리
↓
출력 컨텍스트에 맞는 인코딩
↓
HTML에 안전하게 출력
과 같은 구조가 되어야 합니다.
단순히 입력값을 지우는 것으로 해결하면 안 된다
XSS를 처음 접하면 특수문자나 특정 문자열을 찾아서 삭제하면 되지 않을까 생각할 수 있습니다.
하지만 이런 방식만으로 XSS를 완벽하게 막기는 어렵습니다.
왜냐하면 입력값이 출력되는 위치와 문맥에 따라 필요한 방어 방법이 달라질 수 있기 때문입니다.
HTML 본문에 출력하는 경우와 HTML 속성에 출력하는 경우, JavaScript 코드 내부에 출력하는 경우는 각각 고려해야 할 부분이 다릅니다.
따라서 단순한 문자열 치환이나 특정 태그 삭제에 의존하기보다는 출력되는 컨텍스트에 맞는 안전한 인코딩과 프레임워크의 기본 보안 기능을 사용하는 것이 훨씬 중요합니다.
프론트엔드에서도 조심해야 한다
XSS 방어는 서버만의 문제라고 생각하기 쉽습니다.
하지만 최근 웹 애플리케이션은 JavaScript를 많이 사용하기 때문에 프론트엔드 코드도 함께 확인해야 합니다.
특히 사용자 입력값을 DOM에 직접 삽입하는 코드를 작성할 때 주의해야 합니다.
예를 들어 단순한 텍스트를 화면에 표시하는 용도라면 HTML을 해석하는 방식보다 텍스트로 삽입하는 안전한 API나 프레임워크의 기본 바인딩 기능을 사용하는 것이 좋습니다.
반대로 HTML 문자열을 직접 조작하거나 동적으로 삽입하는 코드가 있다면 해당 부분은 별도로 검토할 필요가 있습니다.
Content Security Policy도 함께 고려할 수 있다
XSS 방어를 조금 더 강화하고 싶다면 CSP(Content Security Policy)도 고려할 수 있습니다.
CSP는 브라우저가 어떤 종류의 리소스를 어디에서 불러오고 실행할 수 있는지를 제한하는 보안 정책입니다.
출력값 인코딩을 제대로 하는 것이 가장 기본적인 방어라면 CSP는 추가적인 방어 계층으로 생각할 수 있습니다.
다만 CSP를 적용했다고 해서 XSS 취약점 자체를 방치해도 된다는 의미는 아닙니다.
가장 먼저 해야 할 일은 애플리케이션 코드에서 사용자 입력값을 안전하게 처리하고 출력하는 것입니다.
반사형 XSS를 확인할 때의 체크리스트
개발 중인 웹사이트가 있다면 다음 항목부터 확인해보는 것도 좋습니다.
1. 사용자가 입력할 수 있는 값을 찾는다.
검색어, URL 파라미터, 게시판 입력값 등을 확인합니다.
2. 입력값이 서버에서 어디로 전달되는지 확인한다.
Controller, API, Service 등의 처리 과정을 따라가 보면 됩니다.
3. 입력값이 응답에 다시 포함되는지 확인한다.
검색 결과나 에러 메시지처럼 입력값이 다시 화면에 표시되는 부분을 찾습니다.
4. HTML로 직접 삽입되는 부분이 있는지 확인한다.
특히 사용자 입력을 HTML 문자열로 조립하는 코드는 주의해야 합니다.
5. 출력 컨텍스트에 맞는 인코딩이 적용됐는지 확인한다.
단순히 입력값을 삭제하는 방식보다 적절한 출력 인코딩을 사용하는 것이 중요합니다.
6. 보안 헤더와 CSP 적용 여부도 확인한다.
추가적인 방어 계층이 필요한 서비스라면 함께 검토합니다.
결국 중요한 건 “사용자 입력을 믿지 않는 것”
반사형 XSS를 직접 찾아보면서 가장 기본적인 원칙을 다시 생각하게 됐습니다.
바로 사용자가 입력한 데이터는 절대 기본적으로 신뢰하면 안 된다는 것입니다.
검색어 하나, URL의 파라미터 하나, 에러 메시지에 표시되는 문자열 하나도 개발자가 아무 생각 없이 화면에 출력하면 보안 취약점으로 이어질 수 있습니다.
특히 개발 단계에서는 정상적인 사용자의 입력만 생각하기 쉽습니다.
하지만 실제 서비스에서는 예상하지 못한 입력도 들어올 수 있습니다.
그래서 입력값을 받는 순간부터 검증하고, 필요한 경우 정규화하고, 무엇보다 출력되는 위치에 맞게 안전하게 처리하는 과정이 필요합니다.
마무리
반사형 XSS는 개념 자체는 어렵지 않습니다.
문제는 실제 개발 과정에서 너무 자연스럽게 만들어지는 코드에서 발생한다는 점입니다.
검색어를 받아서 검색 결과에 보여주고, 사용자가 입력한 값을 에러 메시지에 표시하고, URL 파라미터를 화면에 다시 보여주는 것처럼 아주 평범한 기능에서도 문제가 생길 수 있습니다.
결국 핵심은 하나입니다.
사용자가 입력한 값을 그대로 믿고 브라우저에 출력하지 않는 것.
그리고 XSS 방어를 단순히 특정 문자열을 삭제하는 문제로 접근하기보다 출력 컨텍스트에 맞는 인코딩, 안전한 DOM 처리, 프레임워크의 기본 보안 기능, CSP 같은 추가 방어 계층을 함께 고려하는 것이 중요합니다.
웹사이트를 개발하고 있다면 검색 기능부터 한 번 살펴보는 것도 좋습니다.
생각보다 많은 서비스에서 검색어를 그대로 다시 보여주고 있기 때문입니다.
“그냥 검색어 하나 출력하는 건데 뭐가 문제겠어?”
처음에는 저도 그렇게 생각했습니다.
그런데 웹 보안에서는 바로 그런 작은 부분부터 확인해야 했습니다.
홍TV



![Eclipse에서 갑자기 "[m2e] Lifecycle Mapping" 오류? Maven 프로젝트가 빨간 줄 뜨는 이유 4 Eclipse에서 갑자기 [m2e] Lifecycle Mapping 오류? Maven 프로젝트가 빨간 줄 뜨는 진짜 이유](https://hongtv.co.kr/wp-content/uploads/2026/09/62edeb0f-aaf8-42cc-af31-1a91e54bc187-300x200.png)
댓글 0
첫 댓글을 남겨보세요.