Post

Java HTTP 응답 분할 코딩 기법

1. 정의

HTTP 요청에 들어 있는 인자값이 HTTP 응답 헤더에 포함되어 사용자에게 다시 전달 될 때 입력값에 CR(Carriage Return)이나 LF(Line Feed)와 같은 개행문자가 존재하면 HTTP 응답이 2개 이상으로 분리될 수 있다. 이 경우 공격자는 개행문자를 이용하여 첫 번째 응답을 종료시키고 두 번째 응답에 악의적인 코드를 주입하여 XSS 및 캐시 훼손(cache poisoning) 공격 등을 수행할 수 있다.

http-response-splitting

2. 안전한 코딩 기법

  • 외부에서 입력된 인자값을 사용하여 HTTP 응답 헤더 (Set Cookie 등)에 포함할 경우 CR, LF 등이 제거하거나 적절한 인코딩 기법을 사용하여 변환한다.

  • 외부에서 입력 된 인자값을 적절한 필터링 코드를 통해 검증하여, 오작동을 일으킬 소지가 있는 문자들을 제거한 후 코드에 사용한다.

3. 예제

다음의 예제는 외부의 입력값을 사용하여 반환되는 쿠키의 값을 설정하고 있다. 그런데, 공격자가 Wiley Hacker\r\nHTTP/1.1 200 OK\r\n를 authorName의 값으로 설정할 경우, 다음의 예와 같이 의도하지 않은 두 개의 페이지가 전달된다. 또한 두 번째 응답 페이지는 공격자가 마음대로 수정할 수 있다.

1
HTTP/1.1 200 OK...Set-Cookie: author=Wiley Hacker HTTP/1.1 200 OK ...
  • 안전하지 않은 코드의 예
1
2
3
4
5
6
7
8
9
throws IOException, ServletException {
    response.setContentType("text/html");
    String author = request.getParameter("authorName");
    Cookie cookie = new Cookie("replidedAuthor", author);
    cookie.setMaxAge(1000);
    response.addCookie(cookie);
    RequestDispatcher frd = request.getRequestDispatcher("cookieTest.jsp");
    frd.forward(request, response);
}

외부에서 입력되는 값에 대하여 널 여부를 체크하고, replaceAll을 이용하여 개행문자 \r, \n을 제거하여 헤더 값이 나누어지는 것을 방지한다.

  • 안전한 코드의 예
1
2
3
4
5
6
7
8
9
10
11
12
throws IOException, ServletException {
    response.setContentType("text/html");
    String author = request.getParameter("authorName");
    if (author == null || "".equals(author)) return;
    String filtered_author = author.replaceAll("\r", "").replaceAll("\n", "");
    Cookie cookie = new Cookie("replidedAuthor", filtered_author);
    cookie.setMaxAge(1000);
    cookie.setSecure(true);
    response.addCookie(cookie);
    RequestDispatcher frd = request.getRequestDispatcher("cookieTest.jsp");
    frd.forward(request, response);
}

[출처 및 참고]

This post is licensed under CC BY 4.0 by the author.