본문 바로가기
블로그 이미지

방문해 주셔서 감사합니다! 항상 행복하세요!

  
   - 문의사항은 메일 또는 댓글로 언제든 연락주세요.
   - "해줘","답 내놔" 같은 질문은 답변드리지 않습니다.
   - 메일주소 : lts06069@naver.com


웹 취약점(Web vulnerability)

10. 악성 콘텐츠(CS)

야근없는 행복한 삶을 위해 ~
by 마샤와 곰 2021. 12. 2.

웹 환경에서 파일을 업로드 하는 경우에 해당 파일유효성 검증을 따로 하지 않는 경우, 악성콘텐츠가 삽입된 페이지에 접속한 사용자는 악성코드 유포 사이트가 자동으로 호출되어 악성코드에 감염될 수 있는 취약점을 의미 합니다.

악성콘텐츠는 SQL 인젝션, Cross Site Scripting, 파일 업로드를 통한 페이지 위변조 기법 등을 통해 삽입이 가능하면서 서버 내부의 자원 탈취 및 변조, 클라이언트 브라우저에게의 악성코드 삽입 등이 가능하므로 해당 취약점은 반드시 조치가 되어야 합니다.

 

 

#방법1

취약점에 대한 첫번째 조치로는 브라우저에서 허용된 파일 확장자만 업로드 할 수 있도록 제한을 두는 것 입니다.

일반적으로 file테그에 change옵션을 통하여 파일 확장자를 제한 합니다.

아래 코드는 간단하게 Jquery로 구현된 input type file 테그에 대한 제한을 주는 코드 입니다.

$('#파일테그').change(function(){
    const files = $(this)[0].files
	const fileType = files[0]['type']
	const validImageTypes = ['image/gif', 'image/jpeg', 'image/png', 'image/jpg']
	if (!validImageTypes.includes(fileType)) {
		alert('이미지만 등록 가능 합니다.')
		$(this).val(null)
		return
	}
})

브라우저에서의 파일 확장자 확인만으로도 기본적인 보안조치를 할 수 있습니다.

그러므로 파일 제한에 대한 기능은 1차로 브라우저에서 하는 것을 잊지 말아야 합니다.

 

#방법2

그러나 이러한 브라우저의 유효성 검증을 우회하여 파일을 업로드 할 수 있으므로 결과적으로는 파일을 받는 서버에서의 파일 확장자 체크가 필수 입니다.

확장자를 위변조한 파일에 대비하여 파일 자체가 지니고 있는 Mime타입을 확인 해 준다면 훨씬 더 강력한 검증이 이루어 질 수 있겠습니다.

아래 코드는 Java에서 파일 확장자를 확인하기 위한 샘플 클래스 입니다.

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

import org.apache.tika.Tika;  //아파치 Tika 라이브러리 입니다(Maven에서 받을 수 있습니다)
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;

/****
 * 파일 유효성을 담당하는 비지니스 성격의 클래스 입니다. <br>
 * FileValidator 메소드와 removeSystemTmpFile 메소드를 지원합니다.
 * */
public interface FileValidator {
    
    public static final Logger logg = LoggerFactory.getLogger(FileValidator.class);
    
    //허용되는 파일 확장자 모음 입니다.
    public static final String[] OK_FILE_TYPE = {".txt",".csv",".xls",".xlsx",".hwp",".png",".jpg",".jpeg",".gif",".pdf",".zip",".xml",".html",".7z", ".rar", ".alz", ".tar", ".tgz", ".gz", ".enc"};
    
    public static final String[] MIME_TYPE = {"javascript","json","msword","pdf","excel","powerpoint","spreadsheetml","wordprocessingml","sheet","document","xml","zip","image","audio","mpeg","text","outlook","works","compressed","compress","haansofthwp","hancom","haansofthml", "haansofthwt"};
    
    
    /***
     * 파일 유효성을 검사하는 메소드 입니다. <br>
     * 위 확장자에 포함되지 않으면 멀티파트 객체의 파일을 전부 제거 합니다.<br>
     * 반환은 논리값 입니다.  
     * **/
    default public boolean Validator(MultipartFile[] attachFiles) {
        if(attachFiles == null || attachFiles.length == 0) return true;
        
        Tika tika = new Tika();

        boolean isInsertOk = true;
        for(MultipartFile attachFile : attachFiles) {
            boolean result = false;
            String nuls = attachFile.getOriginalFilename();
            //#1. 확장자로 금지파일 항목을 조사 합니다.
            if(!nuls.equals("")) {  //첨부파일이 존재한 경우 입니다.
                String ext = nuls.substring(nuls.lastIndexOf("."), nuls.length()).toLowerCase();
                for(String CK : OK_FILE_TYPE){
                    if(ext.equals(CK)){
                        result = true;
                        break;
                    }
                }                    
            } else {  //첨부파일에 아무것도 없는 빈 객체로 들어온 경우를 의미 합니다.
                result = true;
                break;
            }
            
            if(!result) {  //금지된 파일이 온 경우라면,
                removeSystemTmpFile(attachFile);
                isInsertOk = false;
            }
            
            result = false;
            
            //#2. 마임타입으로 한번 더 파일을 조사 합니다.
            try {
                String detectedType = tika.detect(attachFile.getBytes());
                if(detectedType != null) detectedType = detectedType.toLowerCase();
                for(String check : MIME_TYPE){
                    if(detectedType.indexOf(check) > -1){
                        result = true;
                        break;
                    }                    
                }
            } catch (IOException e) {
                logg.error("file detect failed ",e);
            }
            
            if(!result) {  //금지된 파일이 온 경우라면,
                removeSystemTmpFile(attachFile);
                isInsertOk = false;
            }
                
        }
        
        if(!isInsertOk) {  //반복문을 통해서 금지된 파일로 걸린적이 있다면 파일 전부를 소거해버립니다. 뭘 담았을지 모르니까요.
            for(MultipartFile attachFile : attachFiles) {
                removeSystemTmpFile(attachFile);
            }
        }
        return isInsertOk;
    }
    
    /**
     * 멀티파트로 넘어온 스트림을 파일로 변환한 뒤에 해당 파일을 제거 해 줍니다.
     * **/
    default public void removeSystemTmpFile(MultipartFile targetFile){
        File convFile = new File(targetFile.getOriginalFilename());
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(convFile);
            fos.write(targetFile.getBytes());       
        } catch (IOException e) {
            
        } finally {
            try { if(fos != null) fos.close();
            } catch (IOException e) { ; }
        }
        if(convFile.isFile()){
            convFile.delete();
            convFile = null;                        
        }
    }
}

 

 

이상으로 표준취약점중 1가지인 악성 콘텐츠(CS)에 대해서 간단하게 살펴보았습니다.

궁금한점 또는 틀린 부분은 언제든 연락주세요! 👻

 

반응형
* 위 에니메이션은 Html의 캔버스(canvas)기반으로 동작하는 기능 입니다. Html 캔버스 튜토리얼 도 한번 살펴보세요~ :)
* 직접 만든 Html 캔버스 애니메이션 도 한번 살펴보세요~ :)

댓글