[ Java ] 부적절한 인가
포스트
취소

[ Java ] 부적절한 인가

취약한 코드


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
package com.openeg.secolab.test.controller;

import java.io.File;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.servlet.ModelAndView;

public class BoardTestController {
	@Autowired
	private BoardService service;

	@PostMapping(value = "/board/delete")
	public ModelAndView userDeleteProc(ModelAndView mav, HttpServletRequest request, HttpSession session) {
		String action = request.getParameter("action");

		if (action != null && action.equals("delete")) {

			int idx = Integer.parseInt(request.getParameter("idx"));
			BoardModel board = service.getOneArticle(idx);

			List<BoardCommentModel> commentList = service.getCommentList(idx);
			if (commentList.size() > 0) {
				mav.addObject("errMsg", "댓글이 존재하여 삭제할 수 없습니다.");
				mav.addObject("idx", idx);
				mav.setViewName("redirect:view");
			} else {
				// 첨부파일의 존재 여부를 확인하여 파일까지 삭제합니다. 
				if (board.getFileName() != null) {
					String uploadPath = request.getContextPath() + "/uploadFiles/";
					File removeFile = new File(uploadPath + board.getFileName());
					removeFile.delete();
				}
				service.deleteArticle(idx);
				// 게시글 목록 페이지를 반환합니다. 
				mav.setViewName("redirect:list");
			}
		}
		return mav;
	}
}

class BoardService {

	@Autowired 
	BoardDao dao;

	public BoardModel getOneArticle(int idx) {
		// DB에서 글 번호가 idx인 글을 조회하는 메소드입니다.
		return dao.selectArticle(idx);
	}

	public List<BoardCommentModel> getCommentList(int idx) {
		//  DB에서 글 번호가 idx인 글에 등록된 댓글을 조회하는 메소드입니다.
		return dao.selectCommentList(idx);
	}

	public void deleteArticle(int idx) {
		// 코드 생략 - DB에서 글 번호가 idx인 글을 삭제하는 메소드입니다.
		dao.deleteArticle(idx);
	}
}

class BoardModel {
	private int bno_db;
	private String writer_db, title_db, content_db, writeDate_db, fileName_db, savedFileName_db, fileName;

	public BoardModel(int bno_db, String writer_db, String title_db, String content_db, 
			String writeDate_db, String fileName_db, String savedFileName_db) {
	}
	
	// 코드 생략 - getter, setter 메소드가 생략되었습니다. 
	public String getFileName() { return fileName; }
	public void setFileName(String fileName) { this.fileName = fileName; }
}

class BoardCommentModel {
	private int cno;
	private String commentWriter, commentContent, commetWriteDate;
} 



취약점 분석


1
service.deleteArticle(idx);

해당 부분에서 요청을 하는 사용자의 delete 작업 권한 확인 없이 글 삭제를 수행하고 있다. 프로그램이 모든 실행가능한 경로에 대해서 접근제어를 검사하지 않거나 불완전하게 검사하는 경우, 공격자는 접근 가능한 실행경로를 통해 정보를 유출 또는 조작 할 수 있는 보안 취약점이 존재한다.


사용자 정보에서 해당 사용자가 작업의 권한이 있는지 확인한 뒤 작업을 수행하여 취약점을 방지할 수 있다.



안전한 코드


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package kr.co.openeg.lab.test.controller;

import java.io.File;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.SecurityProperties.User;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

import kr.co.openeg.lab.test.model.BoardModel;
import kr.co.openeg.lab.test.service.BoardService;

public class SecureBoardTestController {

	@Autowired
	private BoardService service;

	@PostMapping(value = "/board/delete")
	public ModelAndView userDeleteProc(ModelAndView mav, HttpServletRequest request, HttpServletResponse response,
			HttpSession session) {
		String action = request.getParameter("action");
		String userId = (String) session.getAttribute("userId");
		// 요청으로부터 작성자 아이디를 가져옵니다. 
		String writerId = request.getParameter("writerId");

		/* 사용자 id와 작성자 id가 일치하는지 여부를 확인할 수 있는 메소드*/
		if (action != null && action.equals("delete") && userId.equals(writerId)) {
			int idx = Integer.parseInt(request.getParameter("idx"));
			BoardModel board = service.getOneArticle(idx);

			List<BoardCommentModel> commentList = service.getCommentList(idx);
			if (commentList.size() > 0) {
				mav.addObject("errMsg", "댓글이 존재하여 삭제할 수 없습니다.");
				mav.addObject("idx", idx);
				mav.setViewName("redirect:view");
			} else {
				// 첨부파일의 존재 여부를 확인하여 파일까지 삭제합니다. 
				if (board.getFileName() != null) {
					String uploadPath = request.getContextPath() + "/uploadFiles/";
					File removeFile = new File(uploadPath + board.getFileName());
					removeFile.delete();
				}
				service.deleteArticle(idx);
				// 게시글 목록 페이지를 반환합니다. 
				mav.setViewName("redirect:list");
			}
		} else {
			mav.addObject("errMsg", "삭제 권한이 없습니다.");
			mav.addObject("idx", idx);
			mav.setViewName("redirect:view");
		}
		return mav;
	}
}

class BoardService {

	@Autowired 
	BoardDao dao;

	public BoardModel getOneArticle(int idx) {
		// DB에서 글 번호가 idx인 글을 조회하는 메소드입니다.
		return dao.selectArticle(idx);
	}

	public List<BoardCommentModel> getCommentList(int idx) {
		//  DB에서 글 번호가 idx인 글에 등록된 댓글을 조회하는 메소드입니다.
		return dao.selectCommentList(idx);
	}

	public void deleteArticle(int idx) {
		// DB에서 글 번호가 idx인 글을 삭제하는 메소드입니다.
		dao.deleteArticle(idx);
	}
}

class BoardModel {
	private int bno_db;
	private String writer_db, title_db, content_db, writeDate_db, fileName_db, savedFileName_db, fileName;

	public BoardModel(int bno_db, String writer_db, String title_db, String content_db, 
			String writeDate_db, String fileName_db, String savedFileName_db) {
	}
	
	// 코드 생략 - getter, setter 메소드가 생략되었습니다. 
	public String getFileName() { return fileName; }
	public void setFileName(String fileName) { this.fileName = fileName; }
}

class BoardCommentModel {
	private int cno;
	private String commentWriter, commentContent, commetWriteDate;
}