JSP/Servlet | 클라이언트와 서버 사이의 값 전달 | 받은 데이터 이스케이프 처리


클라이언트와 서버 사이에서 데이터를 교환하는 처리를 배울 때, 함께 배워야 하는 것이 있다. 그것은 “데이터 이스케이프"에 대해서이다.

사용자로부터 전송된 값을 사용하는 경우, “사용자는 어떤 값을 보내올지 모른다"라는 것을 염두에 둘 필요가 있다. 특히 생각하지 않으면 안되는 것이 JavaScript이다. 입력 필드에 <script> 태그를 사용한 스크립트를 작성하여 전송되면 어떻게 될까? 그 텍스트를 그대로 화면에 표시하도록 처리가 되어 있는 경우, 페이지가 나타날 때 스크립트가 실행될 것이다(최근의 브라우저들은 이를 막아줘서 실행이 되지 않는 경우가 많다). 예를 들면, 게시판이나 댓글 게시물과 같은 시스템의 경우, 이러한 스크립트가 게시되어 표시되도록 되어 버리면, 거기에 다른 사람이 접근할 때마다 의도하지 않은 스크립트가 실행될 것이다.

일반적으로 XSS(크로스 사이트 스크립팅)이라는 사이트 공격은 이런 취약점을 노린 것이다. 아무튼, 여기 샘플에서 하고 있는 정도라면 문제가 발생 수 없겠지만, 데이터베이스 등의 데이터를 축적하고 이를 표시하는 시스템이 되면 이런 종류의 트러블는 피해갈 수 없을 것이다. 지금 단계에서 “어떻게 대처하면 좋을지"정도는 배워 보도록 하자.

이런 종류의 공격에 대한 대책의 기본은 “텍스트를 출력하기 전에 이스케이프 처리한다"라는 것이다. 예를 들어, HTML 태그에서 사용하는 <,>와 같은 기호를 &lt;, &gt;으로 대체하는 것만으로 그 태그는 무력화 할 수 있다. 이와 같이 특별한 기능을 가지는 기호 종류를 이스케이프 처리하는 것으로, 그 데이터에 포함되어 있는 기능을 무력화하는 것이다.

아래에 매우 간단한 예제를 보도록 하자.

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<%
String inpt = request.getParameter("input");
inpt = inpt == null ? "" : inpt;
String chk = request.getParameter("check");
chk = chk == null ? "OFF" : "ON";
String rd = request.getParameter("radio");
rd = rd == null ? "" : rd;

String str = "INPUT:" + getEscapedString(inpt) + "<br>" +
        "CHECK: " + getEscapedString(chk) + "<br>" +
        "RADIO: " + getEscapedString(rd) + "<br>";
%>
<%!
public String getEscapedString(String s){
    String str = s;
    str = str.replace("&","&amp;");
    str = str.replace("<","&lt;");
    str = str.replace(">","&gt;");
    str = str.replace("\"","&quot;");
    return str;
}
%>
<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Sample jsp</title>
    <style>
    h1 {font-size:16pt; background:#AAFFAA; padding:5px; }
    </style>
</head>
<body>
    <h1>Sample jsp page</h1>
    <p>이 페이지는 샘플입니다.</p>
    <p><%=str%></p>
    <form method="post" action="hello.jsp">
    <table>
        <tr>
            <td>입력</td>
            <td><input type="text" id="input" name="input"></td>
        </tr>
        <tr>
            <td></td>
            <td><input type="checkbox" id="c1" name="check" value="Une"><label for="c1">체크박스</label></td>
        </tr>
        <tr>
            <td></td>
            <td>
                <input type="radio" name="radio" id="r1" value="first"><label for="r1">라디오버튼1</label><br>
                <input type="radio" name="radio" id="r2" value="Second"><label for="r2">라디오버튼2</label>
            </td>
        </tr>
        <tr>
            <td></td>
            <td><input type="submit" value="송신"></td>
        </tr>
    </table>
    </form>
    </body>
</html>

여기에는 텍스트를 보낼 때에 보낸 텍스트에서 < > \ &와 같은 기호를 모두 이스케이프 처리하여 표시하고 있다. 이스케이프 처리는 getEscapedString이라는 메소드로 정의하고 있다. 텍스트를 출력할 때 쓰내는 텍스트를 getEscapedString으로 이스케이프 처리를 하여 표시하면 된다.

또한 이스케이프 처리를 할 때, 주의해야 할 것은 “텍스트 입력된 값만을 처리하면 된다라고는 생각하지 않는다"라는 점이다. 여기에서 체크 박스나 라디오 버튼의 값까지 getEscapedString으로 처리를 하고 있다. “그렇게 보내온 값은 정해져 있으니까 불필요하지?“라고 생각할 지도 모른다. 하지만 JSP는 GET이든 POST에서도 똑같이 getParameter에서 값을 얻을 수 있다. 이는 예를 들어, hello.jsp?check=hogehoge와 같이 URL을 지정하여 액세스하여 check 본래와는 다른 값을 전달될 수 있다. getMethod으로 POST만을 받아들이도록 처리를 하지 않은 경우, 그대로 그 값이 처리되어 버리는 것이다.

그래서, 프로그램 내에서 클라이언트 측에 텍스트를 출력할 때는 항상 이스케이프 처리하도록 해야 한다.