Study/AWS 취약점 진단

취약점 점검 (2)

bento 2023. 12. 30. 23:02

WEB

 

1. 

  취약 여부 항목 중요도 항목 코드
약한 문자열 강도 취약 BF

 

취약점 설명

웹 사이트에서 취약한 패스워드로 회원 가입이 가능할 경우, 공격자는 추측 및 주변 정보를 수집하여 작성한 사전 파일로 대입을 시도하여 사용자 계정을 탈취할 수 있는 취약점

 

보안 위협

해당 취약점 존재 시 유추가 용이한 계정 및 패스워드의 사용으로 인한 사용자 권한 탈취 위험 존재

 

점검

점검 이후 test 계정 삭제

 

조치

- 취약한 계정 및 패스워드를 삭제

- 회원 가입 시 패스워드 규정 설정 추가

  • 패스워드 규정 설정
<script>
    $('#pass').blur(function() {
        var password = $(this).val();
        var passwordRegex = /^(?=.*[A-Za-z])(?=.*\d)(?=.*[$@$!%*#?&])[A-Za-z\d$@$!%*#?&]{8,}$/;

        if (password.length !== 0) {
            if (passwordRegex.test(password)) {
            } else {
                alert("비밀번호는 영문자/숫자/특수문자 조합으로 8자리 이상이어야 합니다.");
            }
        } else {
            alert("비밀번호를 입력하세요.");
            $('#pass').focus();
        }
    });
</script>

 

기존의 코드

  • user/join.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<html>
<head>
    <title>회원 가입</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="style.css">
    <!-- CSS -->
    <link rel="stylesheet" type="text/css" href="../css/user/join.css">
    <link rel="stylesheet" href="../css/bootstrap.min.4.6.2.css">
    <link rel="stylesheet" href="../css/bootstrap.min.5.1.3.css">
    <!-- JS -->
    <script src="../js/jquery.slim.min.js"></script>
    <script src="../js/popper.min.js"></script>
    <script src="../js/bootstrap.bundle.min.js"></script>
    <script src="../js/jquery-3.1.1.min.js"></script>
</head>
<body>
    <div class="form-signin">
        <form method="post" action="joinAction.jsp">
            <h1 class="mb-4 fw-normal">Signup</h1>
            <div class="mb-3 row g-3 align-items-center justify-content-between">
                <div class="col-auto">
                    <label for="id" class="col-form-label">* 아이디</label>
                </div>
                <div class="col-sm-9 form-input justify-content-between">
                    <input type="text" class="col-sm-8 form-control border-dark" name="userId" id="id" maxlength="15">
                    <button type="button" class="btn btn-outline-dark" id="checkId">중복확인</button>
                </div>
            </div>
            <div class="row g-3 mb-3 align-items-center justify-content-between">
                <div class="col-auto">
                    <label for="pass" class="col-form-label">* 비밀번호</label>
                </div>
                <div class="col-sm-9">
                    <input type="password" class="form-control border-dark" name="userPassword" id="pass">
                </div>
            </div>
            <div class="row g-3 mb-3 align-items-center justify-content-between">
                <div class="col-auto">
                    <label for="name" class="col-form-label">* 이름</label>
                </div>
                <div class="col-sm-9">
                    <input type="text" class="form-control border-dark" name="userName" id="name">
                </div>
            </div>
            <div class="row g-3 mb-3 align-items-center justify-content-between">
                <label for="phone" class="col-auto col-form-label">* 휴대폰</label>
                <div class="col-sm-9">
                    <input type="text" class="form-control border-dark" name="userPhone" id="phone">
                </div>
            </div>
            <div class="row g-3 mb-3 align-items-center justify-content-between">
                <label for="email" class="col-auto col-form-label">* 이메일</label>
                <div class="col-sm-9">
                    <input type="text" class="form-control border-dark" name="userEmail" id="email">
                </div>
            </div>
            <div class="row g-3 mb-3 align-items-center justify-content-between">
                <label for="age" class="col-auto col-form-label">* 나이</label>
                <div class="col-sm-9">
                    <input type="number" class="form-control border-dark" name="userAge" id="age">
                </div>
            </div>
            <div class="row g-3 mb-3 align-items-center justify-content-between">
                <label for="address" class="col-auto col-form-label">주소</label>
                <div class="col-sm-9">
                    <input type="text" class="form-control border-dark" name="userAddress" id="address">
                </div>
            </div>
            <p class="p">* 표시 항목은 필수 입력 항목입니다.</p>
            <div class="form-group">
                <button type="submit" class="btn btn-dark w-100 btn-lg">회원가입</button>
            </div>
            <p class="small fw-bold mt-2 pt-1 mb-0">
                이미 계정이 있으십니까?
                <a href="login.jsp" class="link-danger">로그인</a>
            </p>
        </form>
    </div>
    <script>
    $('#checkId').click(function() {
        if ($('#id').val().length !== 0) {
            $.ajax({
                type: "POST",
                url: "checkIdAction.jsp",
                data: {
                    userId: $('#id').val()
                },
                success: function(result) {
                    if (result.trim() == 0) {
                        alert("사용 가능한 아이디입니다.");
                    } else if (result.trim() == 1) {
                        alert("이미 사용중인 아이디입니다.");
                    } else {
                        alert("오류가 발생하였습니다.");
                    }
                }
            });
        } else {
            alert("아이디를 입력하세요.");
            $('#id').focus();
        }
    });
    </script>
</body>
</html>

 

공격 방지 코드의 예

  • user/join.jsp
<!-- 스크립트에 추가한 부분 -->
<script>
    $('#pass').blur(function() {
        var password = $(this).val();
        var passwordRegex = /^(?=.*[A-Za-z])(?=.*\d)(?=.*[$@$!%*#?&])[A-Za-z\d$@$!%*#?&]{8,}$/;

        if (password.length !== 0) {
            if (passwordRegex.test(password)) {
                // 유효한 비밀번호인 경우 아무 동작도 하지 않음
            } else {
                alert("비밀번호는 영문자/숫자/특수문자 조합으로 8자리 이상이어야 합니다.");
            }
        } else {
            alert("비밀번호를 입력하세요.");
            $('#pass').focus();
        }
    });
</script>

 


2. 

  취약 여부 항목 중요도 항목 코드
불충분한 인가 취약 IN

 

취약점 설명

접근제어가 필요한 중요 페이지의 통제수단이 미흡하여 비인가자의 접근이 가능

 

보안 위협

접근제어가 필요한 중요 페이지의 통제수단이 미흡한 경우, 비인가자가 URL 파라미터 값 변경 등의 방법으로 중요 페이지에 접근하여 민감한 정보 열람 및 변조 가능

 

점검

  • profile 페이지에 접근은 가능하나, updateAction은 불가능
    • 현재 세션의 userid와 게시글 userid를 비교하고 있음
    String userId = (String) session.getAttribute("userId");
    

 

조치

  • url 변경을 통해 접근하지 못하게 추가적 조치가 필요
<%
    String strReferer = request.getHeader("referer"); //이전 URL 가져오기

    if(strReferer == null){
        PrintWriter script = response.getWriter();
        script.println("<script>");
        script.println("alert('정상적인 경로를 통해 다시 접근해 주세요.');");
        script.println("location.href='../board/main.jsp'");
        script.println("</script>");
        script.close();
        return;
    }
%>

 

 

공격 방지 코드의 예

  • 변경 board/edit.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ page import="board.boardDTO" %>
<%@ page import="board.boardDAO" %>
<%@ include file="../layout/header.jsp" %>

<html>
<head>
    <title>게시글 수정</title>
    <link rel="stylesheet" type="text/css" href="../css/board/edit.css">
    <link href="https://cdn.quilljs.com/1.3.6/quill.snow.css" rel="stylesheet">
    <script src="https://cdn.quilljs.com/1.3.6/quill.js"></script>
</head>
<body>
    <%
        request.setCharacterEncoding("UTF-8");
        int boardId = Integer.parseInt(request.getParameter("id"));

        if (userId == null) {
            response.sendRedirect("../user/login.jsp");
            return;
        }

        boardDAO boardDao = new boardDAO();
        boardDTO boardDto = boardDao.detailView(boardId);
    %>
    <div class="forms">
        <form method="POST" action="editAction.jsp?id=<%=boardDto.getboardId()%>">
            <div class="mb-3">
                <input class="form-control border-dark" type="text" placeholder="제목을 입력하세요" max-length="50" name="boardTitle" value="<%=boardDto.getboardTitle()%>">
            </div>
            <div id="toolbar" class="border-dark">
                <select class="ql-size">
                    <option value="small"></option>
                    <option selected></option>
                    <option value="large"></option>
                    <option value="huge"></option>
                </select>
                <button class="ql-bold"></button>
                <button class="ql-italic"></button>
                <button class="ql-underline"></button>
                <button class="ql-strike"></button>
                <select class="ql-color"></select>
                <select class="ql-background"></select>
                <button class="ql-list" value="ordered"></button>
                <button class="ql-list" value="bullet"></button>
                <select class="ql-align"></select>
            </div>
            <div id="editor" class="editor border-dark">
                 <%=boardDto.getboardContent()%>
            </div>
            <input type="hidden" name="boardContent" id="content">
            <div class="file-button justify-content-between" style="display: flex;">
                <div class="mt-3">
                    <input class="form-control border-dark" type="file" id="formFile" name="boardFile">
                </div>
                <button type="submit" class="btn btn-dark mt-3">수정</button>
            </div>
        </form>
    </div>
    <script>
        var quill = new Quill('#editor', {
            theme: 'snow',
            modules: {
                toolbar: '#toolbar'
            },
        });

        document.querySelector('form').addEventListener('submit', function () {
            document.getElementById('content').value = quill.root.innerHTML;
        });
    </script>
</body>
</html>
  • 변경 board/editAction.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ page import="board.boardDTO" %>
<%@ page import="board.boardDAO" %>
<%@ page import="java.io.PrintWriter" %>
<%
    request.setCharacterEncoding("UTF-8");

    String userId = (String) session.getAttribute("userId");
    String boardIdStr = request.getParameter("id");
    int boardId;
    String boardTitle = request.getParameter("boardTitle");
    String boardContent = request.getParameter("boardContent");
    String strReferer = request.getHeader("referer"); //이전 URL 가져오기

    if(strReferer == null){
        PrintWriter script = response.getWriter();
        script.println("<script>");
        script.println("alert('정상적인 경로를 통해 다시 접근해 주세요.');");
        script.println("location.href='../board/main.jsp'");
        script.println("</script>");
        script.close();
        return;
    }
    if (boardTitle.isEmpty()) {
        PrintWriter script = response.getWriter();
        script.println("<script>");
        script.println("alert('제목을 작성해주세요.')");
        script.println("history.back();");
        script.println("</script>");
        script.close();
        return;
    }
    if (boardContent.isEmpty()) {
        PrintWriter script = response.getWriter();
        script.println("<script>");
        script.println("alert('내용을 작성해주세요.')");
        script.println("history.back();");
        script.println("</script>");
        script.close();
        return;
    }
    if (userId == null || boardIdStr == null || boardTitle == null || boardContent == null) {
        PrintWriter script = response.getWriter();
        script.println("<script>");
        script.println("alert('오류가 발생하였습니다.')");
        script.println("history.back();");
        script.println("</script>");
        script.close();
        return;
    } else {
        boardId = Integer.parseInt(boardIdStr);
    }

    boardDAO boardDao = new boardDAO();
    int result = boardDao.update(boardId, userId, boardTitle, boardContent);

    if (result == 1) {
        PrintWriter script = response.getWriter();
        script.println("<script>");
        script.println("alert('글을 수정하였습니다.');");
        script.println("location.href='view.jsp?id=" + boardId + "'");
        script.println("</script>");
        script.close();
    } else {
        PrintWriter script = response.getWriter();
        script.println("<script>");
        script.println("alert('수정에 실패하였습니다.');");
        script.println("history.back();");
        script.println("</script>");
        script.close();
    }
%>

 

728x90