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