안녕하세요! <script>alert('해킹 성공!');</script>
라는 내용을 입력합니다.
만약 서버가 이 입력을 아무런 처리 없이 그대로 저장하면, 다른 사용자가 이 댓글을 볼 때 브라우저는 <script>
태그를 그대로 실행하여 '해킹 성공!'이라는 경고창을 띄우게 됩니다.
(실제로는 쿠키 탈취, 개인정보 전송 등 훨씬 위험한 동작을 수행합니다.)<
문자는 <
로, >
문자는 >
로 변환(이스케이프)하여, 브라우저가 스크립트로 해석하지 못하게 만드는 것입니다.
대부분의 최신 템플릿 엔진(Thymeleaf, React 등)은 기본적으로 이 기능을 제공합니다.
또한, 쿠키에 HttpOnly
속성을 설정하여 스크립트가 쿠키에 접근하는 것을 막는 것도 좋은 방어 전략입니다.my-bank.com
에 로그인하여 정상적인 쿠키를 발급받은 상태입니다.evil.com
에 접속합니다.evil.com
에는 <img src="https://my-bank.com/transfer?to=hacker&amount=10000">
와 같은 코드가 숨겨져 있습니다.my-bank.com
으로 요청을 보내는데, 이때 SameSite
속성을 Strict
나 Lax
로 설정하여 다른 출처의 요청에 쿠키가 전송되지 않도록 막는 것도 매우 효과적인 방어법입니다.String username = request.getParameter("username");
String sql = "SELECT * FROM users WHERE username = '" + username + "'";
username
입력값으로 admin' OR '1'='1
을 입력하면, 최종 SQL은 아래와 같이 변질됩니다.
SELECT * FROM users WHERE username = 'admin' OR '1'='1'
'1'='1'
은 항상 참이므로, 이 쿼리는 모든 사용자의 정보를 반환하게 되어 인증을 우회하게 됩니다.?
와 같은 플레이스홀더로 비워둔 채로 SQL 쿼리의 '틀'을 먼저 데이터베이스에 보내고, 사용자의 입력값은 나중에 별도의 '데이터'로 전달하는 방식입니다.
이 경우, 데이터베이스는 사용자의 입력을 가장 큰 차이는공격의 대상과 신뢰의 주체입니다.XSS는 악성 스크립트를 사이트에 주입하여, 해당 사이트를 신뢰하는다른 사용자의 브라우저를 공격하는 것입니다. 즉, 사용자의 '사이트에 대한 신뢰'를 악용합니다. 반면,CSRF는 사용자가 특정 사이트에 로그인된 상태를 이용하여, 그 사용자의 권한으로사이트를 공격하는 것입니다. 즉, 사이트의 '사용자 브라우저에 대한 신뢰(쿠키)'를 악용합니다. XSS는 사용자 정보 탈취가 주 목적이라면, CSRF는 사용자 모르게 특정 행위를 시키는 것이 주 목적입니다.
가장 효과적인 방법은Prepared Statement(매개변수화된 쿼리)를 사용하는 것입니다. 그 이유는, 사용자의 입력값을 SQL 쿼리의 일부로 직접 합치는 것이 아니라, 쿼리의 '틀'과 사용자의 '데이터'를 분리하여 데이터베이스에 전달하기 때문입니다. 데이터베이스는 전달받은 '데이터'를 절대로 실행 가능한 코드로 해석하지 않고 순수한 값으로만 처리하므로, 악의적인 SQL 구문이 주입되어 쿼리가 변질될 가능성을 원천적으로 차단할 수 있습니다.