회사 레거시 시스템은 백엔드가 스프링 프레임워크이고 프론트엔드가 JSP인 전통적인 웹 애플리케이션 구성이다.

  • 스프링 프레임워크: 자바 기반의 백엔드 개발을 위한 프레임워크로 데이터베이스와 상호작용한다
  • JSP: 서버 측에서 동적으로 HTML과 CSS를 렌더링하고 JavaScript를 사용하여 클라이언트 측 논리를 구현하는 웹프로그래밍 언어다

이번 문의는 매년 모의해킹 점검을 하는 프로젝트 팀으로부터 온 연락이었다.

해당 시스템 모의해킹 점검 결과 게시판 페이지에서 취약점이 발견되었습니다. 개선 가능여부 회신 주시면 감사하겠습니다.

취약점 보고서가 첨부된 메일을 확인한 결과 두 가지가 지적사항으로 나왔다.

1. XSS 공격

XSS(Cross-Site Scripting)란 웹 애플리케이션에서 입력값 검증 없이 사용자가 입력한 스크립트를 다른 사용자에게 전송하는 공격이다. XSS 공격을 성공하면, 공격자는 웹사이트에 접속한 다른 사용자들의 쿠키 정보, 세션 정보 등을 탈취할 수 있으며, 웹사이트를 조작할 수도 있다.

게시판 글작성 페이지에서는 제목란이나 내용란, 즉 <input/> 태그 안에 텍스트를 입력할 수 있는 곳에서 스크립트 코드를 작성하여 XSS 공격을 시도할 수 있었다.

공격시도

<scripts>alert('HI');</scripts>

그런 이유로 '등록' 버튼을 눌러 POST 통신을 시도할 때 서버쪽에서 XSS 공격을 방지하기 위한 로직을 아래와 같이 추가했다.

취약점 보완코드

public static String checkXss(String input) {
    if (input == null || input.trim().isEmpty()) {
        return "";
    }
    String output = input;
    output = output.replaceAll("<", "&lt;");
    output = output.replaceAll(">", "&gt;");
    output = output.replaceAll("\\(", "&#40;");
    output = output.replaceAll("\\)", "&#41;");
    output = output.replaceAll("'", "&#39;");
    output = output.replaceAll("eval\\((.*)\\)", "");
    output = output.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\"");
    return output;
}
@RequestMapping(value = "/uploadPost", method = RequestMethod.POST)
public String uploadPost(HttpServletRequest request, Model model) {
    String title = checkXss(request.getParameter("title"));
    String content = checkXss(request.getParameter("content"));
    Post post = new Post(title, content);
    postService.uploadPost(post);
    return "redirect:/postList";
}

위 코드에서는 사용자가 입력한 title과 content를 checkXss() 함수를 통해 검증한다. 입력문자열에서 HTML 코드로 인식되는 특수문자들을 일반 문자열로 치환하는 것이다. 이렇게 하면 스크립트 태그를 넣어 글을 등록해도 스크립트가 작동되지 않는다.

2. 허가되지 않은 접근

게시판 페이지는 특정 코드(ex: 부서코드)를 가진 사용자만 글을 작성하도록 제한했으나 기존 코드에선 JSP의 Javascript 영역에서 부서코드를 검증하고 있었다. 클라이언트에서 요청파라미터 조작이 가능해 허가되지 않은 접근이 가능한 상황이었다.

공격시도

http://localhost:8080/writePost?departmentCode=1

그래서 다음과 같이 부서코드 체크를 서버에서 처리하고 글쓰기 버튼이 포함된 html 코드를 리턴시 반환하도록 처리했다.

취약점 보완코드

//BE
// 글쓰기 버튼이 포함된 HTML 코드를 생성하는 메서드
private String createPostButtonHtml(int departmentCode) {
    if (departmentCode == 1 || departmentCode == 2) {
        return "<a href='/writePost'>글쓰기</a>";
    } else {
        return "";
    }
}

// 글 목록 페이지를 렌더링하는 메서드
@RequestMapping(value = "/postList", method = RequestMethod.GET)
public String postList(HttpServletRequest request, Model model) {
    HttpSession session = request.getSession();
    User user = (User) session.getAttribute("user");
    int departmentCode = user.getDepartmentCode();
    String postButtonHtml = createPostButtonHtml(departmentCode);
    model.addAttribute("postButtonHtml", postButtonHtml);
    // ...
    return "postList";
}
/*FE*/
<c:out value="${postButtonHtml}" />

위에서 제시한 개선된 코드는 요청 파라미터로 부서코드를 조작하여 글쓰기 버튼에 접근하는 공격을 시도하더라도, 서버 측에서는 사용자 정보를 가져와서 해당 사용자가 글쓰기 권한이 있는 부서인지 검증하기 때문에 권한이 없는 사용자에게 글쓰기 버튼은 페이지에 렌더링 되지 않는다.

3. 이것이 100% 해답은 아니다

취약점을 위와 같이 처리한 후 프로젝트 팀 검토를 통과했지만, 나는 널리 알려진 방어 체계 하나를 구축한 것 뿐인 것 같았다. 보안이라는 카테고리가 생소하여 궁금증을 GPT 선생님에게 물어보았다.

보안 취약점 상세파악 (ChatGPT)

언어별 보안 취약점

  • Java는 메모리 관리, 인증, 권한 관리 등에 대한 기능이 내장되어 있으며, 보안 취약점이 존재할 경우에도 다양한 보안 패치가 제공되기 때문에, 상대적으로 안전한 언어입니다. 또한, Java는 실행환경에 의존하기 때문에, 사용자가 특정 버전의 Java 버전을 사용하지 않는 이상, 악성코드가 실행될 가능성이 낮습니다.

  • 반면, JavaScript는 웹 브라우저에서 동작하기 때문에, 사용자의 브라우저 환경에 따라 실행 결과가 달라지며, 취약점이 발생하기 쉽습니다. 또한, JavaScript는 사용자의 입력값을 받아 처리하기 때문에, Cross-site scripting(XSS) 공격에 취약할 수 있습니다.

엔드포인트별 보안 취약점

  • FE는 사용자와 상호작용하는 부분을 담당하므로, Cross-Site Scripting(XSS) 공격이나 쿠키 조작(Cookie Manipulation) 등의 보안 취약점이 발생할 수 있습니다. 또한, FE에서는 보안 취약점을 발생시킬 수 있는 다양한 라이브러리가 존재하기 때문에, 라이브러리 사용에 대한 주의가 필요합니다.

  • 반면, BE는 사용자의 요청을 받아 처리하고, 데이터를 처리하는 부분을 담당하기 때문에, SQL Injection, CSRF(Cross-Site Request Forgery) 공격 등의 보안 취약점이 발생할 수 있습니다. 또한, BE는 다양한 기능을 제공하기 때문에, 라이브러리와 프레임워크 등의 취약점도 존재할 수 있습니다.

결국 모든 면에서 보안 취약점은 존재한다는 어쩌면 너무도 당연한 답변이 돌아왔다. 해커가 매우 다양한 공격 기술을 사용한다면 보안 취약점은 언제든지 발생할 가능성이 있다는 것이다. 이에 대응하기 위해 모의해킹이 매년 있는 것이고 말이다. GPT 선생님의 멋진 표현을 끝으로 포스팅을 마무리한다.

보안은 완벽한 보호 수단이 존재하지 않는 무한한 경쟁의 대상입니다.

profile
late bloomer

0개의 댓글