jsp, jstl newline(\r\n, \n) 처리 방법

태빵·2022년 4월 27일
0

java 에서 jsp 로 값을 동적으로 넘겨서 화면을 구성하는 경우 newline('\n') 에 대한 처리가 필요할 때가 있다.

일반적으로 Window 계열에서는 CRLF('\r\n') 으로 라인 분리를 하고, MAC 계열에서는 CR('\n')로 분리를 하게 된다.

다만 여기서 문제는

jsp, html 에서는 \r\n 또는 \n 으로 라인 분리가 되지 않는다.

이를 해결하기 위해 다음과 같은 방법을 사용할 수 있다.
java

@RestController
public class TestController{
    @GetMapping("/")
    public String getPage(Model model){
    	String contents = "test1\r\ntest2\r\n";
        contents = contents.replaceAll("\\r?\\n", "<br/>"));
        //\r\n 또는 \n 에 대해서 <br/> 로 변화
    	model.addAttribute("contents",contents);
        return "test";
    }
}    

jsp

...
<span>${contents}</span>
...

결과

test1
test2

다만, 한가지 문제가 있다. Xss 공격에 대해 취약하다는 것이다.
예를 들어, contents="<script>alert(document.cookie)</script>" 의 경우 해당 페이지에 접근하게 되면, cookie 가 노출되게 된다.

따라서 이를 해결하기 위해 <c:out> tag 를 사용한다.

jsp

...
<span><c:out value="${contents}"/></span>
...

결과

test1<br/>test2<br/>

오잉??? 텍스트가 의도한 대로 표기되지 않는다. cout은 내부 tag 속성을 무시하고 text 그대로 출력하기 때문에 <script> 등은 그대로 <script> 로 표기되고 <br> 도 마찬가지 이다.

그렇다면 어떻게 이것을 해결할까?
먼저 java 단의 replaceAll 구문을 없애고 jsp 단에서 처리를 해준다.
jsp

<% pageContext.setAttribute("CRLF", "\r\n"); %>
<% pageContext.setAttribute("LF", "\n"); %>
...
<span>
${fn:replace(fn:replace(fn:escapeXml(contents), CRLF, '<br/>'), LF, '<br/>')}
</span>
...

먼저 escapeXml을 통하여 xss 공격을 방어하고, 중첩으로 fn:replace 를 사용하여 두번에 걸쳐 line breaking 을 처리한다.

결과
String contents = "test1\r\ntest2\r\n";

test1
test2

String contents = "<script>alert('test');</script>";

<script>alert('test');</script>
profile
hello world

0개의 댓글