JAVA/JSP

JSP 강의평가 웹 사이트 - 기초 XSS 시큐어 코딩

꿀표 2020. 5. 11. 15:05

XSS는 특정사용자가 다른 사용자와 통신하는 과정에서 발생할 수 있는 해킹 방법.

 

해결방안 : 자바스크립트를 실행할 수 있는 문장을 모두 치환.

 

EvaluationDAO.java - write() 함수 수정

package evaluation;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;

import util.DatabaseUtil;

public class EvaluationDAO {

	public int write(EvaluationDTO evaluationDTO) {
		String SQL = "INSERT INTO EVALUATION VALUES (NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0)"; // EvaluationID는 auto increament 설정이 되있기 때문에 NULL값을 넣어주면 차례대로 증가함
																									
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try {
			conn = DatabaseUtil.getConnection();
			pstmt = conn.prepareStatement(SQL);
			pstmt.setString(1, evaluationDTO.getUserID().replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\r\n", "<br>"));
			pstmt.setString(2, evaluationDTO.getLectureName().replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\r\n", "<br>"));
			pstmt.setString(3, evaluationDTO.getProfessorName().replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\r\n", "<br>"));
			pstmt.setInt(4, evaluationDTO.getLectureYear());
			pstmt.setString(5, evaluationDTO.getSemesterDivide().replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\r\n", "<br>"));
			pstmt.setString(6, evaluationDTO.getLectureDivede().replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\r\n", "<br>"));
			pstmt.setString(7, evaluationDTO.getEvaluationTitle().replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\r\n", "<br>"));
			pstmt.setString(8, evaluationDTO.getEvaluationContent().replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\r\n", "<br>"));
			pstmt.setString(9, evaluationDTO.getTotalScore().replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\r\n", "<br>"));
			pstmt.setString(10, evaluationDTO.getCreditScore().replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\r\n", "<br>"));
			pstmt.setString(11, evaluationDTO.getComfortableScore().replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\r\n", "<br>"));
			pstmt.setString(12, evaluationDTO.getLectureScore().replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\r\n", "<br>"));
			return pstmt.executeUpdate();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (conn != null)
					conn.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
			try {
				if (pstmt != null)
					pstmt.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
			try {
				if (rs != null)
					rs.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return -1;
	}

	public ArrayList<EvaluationDTO> getList (String lectureDivede, String searchType, String search, int pageNumber) {
    	   if(lectureDivede.equals("전체")) {
    		  lectureDivede = "";
    	   }
			ArrayList<EvaluationDTO> evaluationList = null;
			String SQL = "";
			Connection conn = null;
			PreparedStatement pstmt = null;
			ResultSet rs = null;
    		  try {		
    			  if(searchType.equals("최신순")) {
    				 SQL = "SELECT * FROM EVALUATION WHERE lectureDivede Like ? AND CONCAT(lectureName, professorName, evaluationTitle, evaluationContent) LIKE " +
    			            "? ORDER BY evaluationID DESC LIMIT " + pageNumber * 5 + ", " + pageNumber * 5 + 6;       
    			  } else if (searchType.equals("추천순")) {
    				  SQL = "SELECT * FROM EVALUATION WHERE lectureDivede Like ? AND CONCAT(lectureName, professorName, evaluationTitle, evaluationContent) LIKE " +
    			            "? ORDER BY likeCount DESC LIMIT " + pageNumber * 5 + ", " + pageNumber * 5 + 6;
    			  }
    			  conn = DatabaseUtil.getConnection(); 
    			  pstmt = conn.prepareStatement(SQL); 
    			  pstmt.setString(1, "%" + lectureDivede + "%");
    			  pstmt.setString(2, "%" + search + "%");
    			  rs = pstmt.executeQuery();
    			  evaluationList = new ArrayList<EvaluationDTO>();
    			  while(rs.next()) {
    				 EvaluationDTO evaluation = new EvaluationDTO(
    						 rs.getInt(1),
    						 rs.getString(2),
    						 rs.getString(3),
    						 rs.getString(4),
    						 rs.getInt(5),
    						 rs.getString(6),
    						 rs.getString(7),
    						 rs.getString(8),
    						 rs.getString(9),
    						 rs.getString(10),
    						 rs.getString(11),
    						 rs.getString(12),
    						 rs.getString(13),
    						 rs.getInt(14)
    					);
    				    evaluationList.add(evaluation);
    			  }
    		  } catch (Exception e) {
    			   e.printStackTrace();
    		  } finally {
    			try {if(conn != null) conn.close();} catch (Exception e) {e.printStackTrace();}
    			try {if(pstmt != null) pstmt.close();} catch (Exception e) {e.printStackTrace();}
    			try {if(rs != null) rs.close();} catch (Exception e) {e.printStackTrace();}
    		 }
    		  return evaluationList;
       }
	// 특정한 강의평가 글에 좋아요를 누르는 함수
	   public int like(String evaluationID) {
		   String SQL = "UPDATE EVALUATION SET likeCount = likeCount + 1 WHERE evaluationID = ?";	
			  Connection conn = null; 
			  PreparedStatement pstmt = null;
			  ResultSet rs = null; 
			  try {		  
				  conn = DatabaseUtil.getConnection(); 
				  pstmt = conn.prepareStatement(SQL);  
				  pstmt.setInt(1, Integer.parseInt(evaluationID));
			      return pstmt.executeUpdate();
			      } catch (Exception e) {
				   e.printStackTrace();
			  } finally { 
				try {if(conn != null) conn.close();} catch (Exception e) {e.printStackTrace();}
				try {if(pstmt != null) pstmt.close();} catch (Exception e) {e.printStackTrace();}
				try {if(rs != null) rs.close();} catch (Exception e) {e.printStackTrace();}
			 }
			  return -1; // 데이터베이스 오류
	   }
	   // 특정한 강의평가 글을 삭제하는 함수
	   public int delete(String evaluationID) {
		   String SQL = "DELETE FROM EVALUATION WHERE evaluationID = ?";	
			  Connection conn = null; 
			  PreparedStatement pstmt = null;
			  ResultSet rs = null; 
			  try {		  
				  conn = DatabaseUtil.getConnection(); 
				  pstmt = conn.prepareStatement(SQL); 
				  pstmt.setInt(1, Integer.parseInt(evaluationID));
			      return pstmt.executeUpdate();
			      } catch (Exception e) {
				   e.printStackTrace();
			  } finally { 
				try {if(conn != null) conn.close();} catch (Exception e) {e.printStackTrace();}
				try {if(pstmt != null) pstmt.close();} catch (Exception e) {e.printStackTrace();}
				try {if(rs != null) rs.close();} catch (Exception e) {e.printStackTrace();}
			 }
			  return -1; // 데이터베이스 오류
	   }
	   // 글을 작성한 사용자의 아이디를 받아오는 함수
	   public String getUserID(String evaluationID) {
		   String SQL = "SELECT userID FROM EVALUATION WHERE evaluationID = ?";	
			  Connection conn = null; 
			  PreparedStatement pstmt = null; 
			  ResultSet rs = null;
			  try {		  
				  conn = DatabaseUtil.getConnection(); 
				  pstmt = conn.prepareStatement(SQL); 
				  pstmt.setInt(1, Integer.parseInt(evaluationID));
				  rs = pstmt.executeQuery();
				  if(rs.next()) {
					  return rs.getString(1);
				  }
			  } catch (Exception e) {
				   e.printStackTrace();
			  } finally { 
				try {if(conn != null) conn.close();} catch (Exception e) {e.printStackTrace();}
				try {if(pstmt != null) pstmt.close();} catch (Exception e) {e.printStackTrace();}
				try {if(rs != null) rs.close();} catch (Exception e) {e.printStackTrace();}
			 }
			  return null; // 존재하지 않는 글
	   }
}

함수를 수정해주는 게시글이 등록될 때 모든 꺾쇠가 치환되어서 자바스크립트를

삽입하기가 어려워진다. 다른 여러 라이브러리가 많지간 위 처럼 간단히 설정만

해주어도 XSS 공격이 까다로워진다.