잡다한 프로그래밍 :: 잡다한 프로그래밍
반응형

0. 개요

HTTP 응답 분할에 대해 알기전 CR, LF가 무엇인지 HTTP request, response가 어떤식으로 구성되어 응답 분할 문제가 발생하는지 공부한다.

1. CRLF의 정의

CR(Carrige Return: \r): 커서의 위치를 현재 줄의 맨 처음으로 보내는 기능
LF(Line Feed: \n): 커서를 다음 줄로 옮기는 기능

CR+LF: 다음줄의 제일 처음위치를 의미.

 

2. HTTP message 구조

http요청은 다음 구조처럼 이루어져 있다 이중 CRLF 공백 으로 이루어진 줄이 header와 body를 구분하는데 이러한 특성으로 인해 CRLF 취약점이 생긴다.

3. 예시

다음 예제는 외부의 입력값을 사용하여 반환되는 쿠키의 값을 설정하고 있다. 만약 공격자가 값을 Wiley Hacker \r\nHTTP/1.1 200 OK\r\n를 authorName의 값으로 설정할 경우, 다음과같은 두개의 페이지가 전달된다.

 

따라서 다음과 같이 CRLF의 여부를 체크하고 replaceAll을 이용하여 이를 제거하여 HTTP응답 분리를 방지한다.

반응형
반응형

1. CSRF의 정의

특정 웹 사이트에 대해 사용자가 인지하지 못한 상황에서 사용자의 의도와 무관하게 공격자가 의도한 행위(수정, 삭제, 등록 등) 을 요청하게 하는 공격을 말한다. 사용자로부터 받은 요청에 대해 사용자가 의도한대로 작성되고 전송된 것인지 확인하지 않을때 발생하며, 관리자인경우 관리자 권한의 게시물삭제 사용자 관리 등 임의로 공격이 가능하다

 

2. 안전한 코딩기법

입력화면 form 작성 시 Get 방식을 사용하면 URL에 노출이 되므로 POST방식을 사용하여 해당 입력을 처리하도록한다.

 

3. 예시

 

4. 추가적인 방법

CSRF Token이용하기

CSRF 토큰을 주고받으므로서 요청이 유효한지 확인할 수 있다. 예를들어 게시판 글 쓰기 페이지를 호출할 때 token을 서버에서 브라우저에게 전달하고, 게시판 글쓰기 요청이 왔을 때 토큰이 없다면 유효한 요청이 아니라고 판단하는 것 이다.

이는 Spring security를 사용하면 csrf토큰 내용이 구현되어있다. 유저 form에서 다음과 같이 csrf input을 추가해주면 된다.

<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/> 

 

CAPTCHA

다음과 같이 추가적인 인증을 하는 CAPTCHA를 이용하여 CSRF에 대비할 수 있다.

 

추가로 비밀번호 요구하기

예를들어 사용자의 회원탈퇴, 정보수정같은 중요한 업무는 비밀번호를 한번 더 요청하는것으로 CSRF에 대비할 수 있다.

반응형
반응형

1. 신뢰되지 않는 URL 주소로 자동연결의 정의

사용자로부터 입력되는 값을 외부사이트의 주소로 사용하여 자동으로 redirect 하는 경우 피싱 공격에 노출되는 취약점을 가질 수 있다.

 

2. 안전한 코딩기법

자동 연결할 외부 사이트의 URL과 도메인은 화이트 리스트로 관리하고, 사용자의 입력값을 통해 주소로 리다이렉트 시키는경우 입력값이 존재하는지 여부를 확인한다.

 

3. 예시

다음과 같은 코드가 존재할 경우에 사용자는 이 링크를 클릭함으로서 피싱사이트로 접근된다.

<a href = "http://bank.example.com/redirect?url=attacker.example.net">Click</a>

이는 이동할 수 있는 리스트를 사전에 정의해놓고 그 리스트에 포함되어있지 않으면 이동시키지 않는 방법이다.

반응형
반응형

1. 위험한 형식 파일 업로드 정의

서버측에서 실행될 수 있는 스크립트파일(asp, jsp, php 파일 등)이 업로드 가능하고, 이 파일을 공격자가 웹을 통해 직접 실행 시킬 수 있는 경우 공격자는 스크립트 파일을 업로드하고, 이 파일을 통해 시스템 내부 명령어를 실행하거나 외부와 연결하여 시스템을 제어할 수 있다.

예를들어 다음과 같은 게시판에 악성 파일을 업로드하고 서버내에서 실행시키면 서버에 영향을 줄 수 있다.

2. 안전한 코딩기법

  • 업로드하는 파일 타입과 크기를 제한하고, 업로드 디렉터리를 웹서버와 분리하여 설정한다.
  • 허용된 확장자만 업로드되도록하고, 확장자도 대소문자 구분 없이 처리하도록 한다.
  • 공격자의 웹을 통한 직접 접근을 차단한다. 또한 파일 실행 여부를 설정할 수 있는 경우, 실행 속성을 제거한다.

3. 예시

사용자가 업로드하는 파일의 유효성을 검사하지 않으면, 위험한 유형의 파일을 공격자가 업로드하거나 전송할 수 있다.

public void upload(HttpServletRequest request) throws ServletException {
    MultipartHttpServletRequest mrequest = (MultipartHttpServletRequest) request;
    String next = (String) mrequest.getFileNames().next();
        MultipartFile file =  mrequest.getFile(next);
    // MultipartFile로부터 file을 얻음
    String filename = file.getOriginalFilename();
    // upload 파일에 대한 확장자 체크하지 않음
    File uploadDir = new File("/app/webapp/data/upload/notice");
        String uploadFilePath = uploadDir.getAbsolutePath()+"/" + fileName;
}

 

다음은 업로드 파일의 크기를 제한하고, doc, hwp, pdf, xls 확장자만 저장을 허용하며, 업로드 파일의 디렉터리 위치를 다큐먼트 루트의 밖에 위치시키는 방법이다.

public void upload(HttpServletRequest request) throws ServletException {
    MultipartHttpServletRequest mrequest = (MultipartHttpServletRequest) request;
    String next = (String) mrequest.getFileNames().next();
        MultipartFile file =  mrequest.getFile(next);
    if(file == null)
      return;
      
    //업로드 파일 크기를 제한한다
    int size = file.getSize();
    if(size > MAX_FILE_SIZE) throw new ServletException("에러");
    
    // MultipartFile로 부터 file을 얻음
    String fileName = file.getOriginalFilename().toLowerCase();
    
    // 업로드 파일의 확장자를 체크한다.
    if(fileName != null)
    {
    	if(fileName.endsWith(".doc") || fileName.endsWith(".hwp") 
        || fileName.endsWith(".pdf") || fileName.endsWith(".wls"))
        {
        	파일업로드함
        }
        else throw new ServletException("에러");
    }
    
    //업로드 파일의 디렉터리 위치는 다큐먼트 루트의 밖에 위치시킨다.
    File uploadDir = new File("/app/webapp/data/upload/notice");
    String uploadFilePath = uploadDir.getAbsolutePath()+"/" + fileName;
}

 

4. 추가적인방법

  • 웹 서버 내부 디렉토리에 실행권한을 주지 않는다. 즉 서버 내부에 파일을 실행할 수 없게하여 공격으로부터 대비한다
  • 파일이름 및 확장자를 암호화(난수화) 하여 저장한다. DB에 암호화된 파일명, 원래의 파일명, 파일크기, 확장자 등 정보를 저장한다면 사용자에게 원래의 파일명으로 화면에 뿌려주되 파일명은 암호회되어있어서 사용자는 직접적으로 접근할 수 없다. DB에 원래 파일명을 적어놓으므로 복호화 과정이 필요없어서 해쉬를 사용해도 괜찮을 것 같음(추측)
반응형
반응형

0. 개요

Naming공부를 하다 Enum이 무엇인지 몰라서 정리해보는 계기가 되었다.

1. 정의

상수를 정의할 때 final static string 과 같은 방식으로 상수를 정의를한다. 하지만 이렇게 상수를 정의해서 코딩하는 경우 여러 문제가 발생함. 

따라서 이러한 문제점들을 보완하기 위해 자바 1.5버전부터 추가된 것이 바로 Enum

Enum은 열거형이라고 불리며, 서로 연관된 상수들의 집합을 의미한다.

 

2. Enum 이전의 방법들

#1) 상수 선언하여 사용하기

public class EnumExample {

    private final static int MONDAY = 1;
    private final static int TUESDAY = 2;
    private final static int WEDNESDAY = 3;
    private final static int THURSDAY = 4;
    private final static int FRIDAY = 5;
    private final static int SATURDAY = 6;
    private final static int SUNDAY = 7;

    public static void main(String[] args) {        

        int day = MONDAY;

        switch (day) {
        case MONDAY:
            System.out.println("월요일 입니다.");
            break;
        case TUESDAY:
            System.out.println("화요일 입니다.");
            break;
        case WEDNESDAY:
            System.out.println("수요일 입니다.");
            break;

            /*
             * ... 생략 ...
             */
        }
    }
}

다음과 같은 코드는 만약 Month에 대한 상수가 추가된다면 상수가 너무 많아지고, 만약 같은 이름으로 정의된 상수가 있다면 중복된 이름이라 오류가 발생한다.

 

#2) interface를 이용한 방법

interface DAY{  
    int MONDAY = 1;
    int TUESDAY = 2;
    int WEDNESDAY = 3;
    int THURSDAY = 4;
    int FRIDAY = 5;
    int SATURDAY = 6;
    int SUNDAY = 7;
}

interface MONTH{  
    int JANUARY = 1;
    int FEBRUARY = 2;
    int MARCH = 3;
    int APRIL = 4;
    int MAY =5;
    int JUNE = 6;
    int JULY = 7;
    int AUGUST = 8;
    int SEPTEMBER = 9;
    int OCTOBER = 10;
    int NOVEMBER = 11;
    int DECEMBER = 12;
}

public class EnumExample {

    public static void main(String[] args) {

        if(DAY.MONDAY == MONTH.JANUARY){ //이부분에러
            System.out.println("두 상수는 같습니다.");
        }       

        int day = DAY.MONDAY;

        switch (day) {
        case DAY.MONDAY:
            System.out.println("월요일 입니다.");
            break;
        case DAY.TUESDAY:
            System.out.println("화요일 입니다.");
            break;
        case DAY.WEDNESDAY:
            System.out.println("수요일 입니다.");
            break;

            /*
             * ... 생략 ...
             */
        }
    }
}

다음과 같이 인터페이스를 사용하게되면 이름이 같은 상수도 정의하여 사용할 수 있지만, if문을 보면 Day 의 Monday와 Month의 January부분이 같다고 인식하게되는 에러가 발생한다.

 

3. Enum의 사용이유

앞선 문제를 Enum을 사용하면 다음과 같이 해결할 수 있다. Enum을 사용하게 되면 static final의 반복이 사라져 가독성이 좋고 앞선 if문의 문제를 해결할 수 있다.

enum Day{  
    MONDAY,TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;
}

enum Month{  
    JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, 
    AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER;
}

public class EnumExample {

    public static void main(String[] args) {        

        Day day = Day.MONDAY;

        switch (day) {
        case MONDAY:
            System.out.println("월요일입니다.");
            break;
        case TUESDAY:
            System.out.println("화요일입니다.");
            break;
        case WEDNESDAY:
            System.out.println("수요일입니다.");
            break;

            /*
             * ... 생략 ...
             */
        }
    }
}

 

 

또한 다음과같이 이용할 수 있다.

enum Type {
    WALKING, RUNNING, TRACKING, HIKING
}
public class Shoes {
    public String name;
    public int size;
    public Type type;
     
    public static void main(String[] qrgs) {
        Shoes shoes = new Shoes();
         
        shoes.name = "아디다스";
        shoes.size = 270;
        shoes.type = Type.RUNNING;
         
        System.out.plintln("신발 이름 = " + shoes.name);
        System.out.plintln("신발 사이즈 = " + shoes.size);
        System.out.plintln("신발 종류 = " + shoes.type);
    }
}
반응형
반응형

1. 운영체제 명령어 삽입의 정의

다음 그림과 같이 적절한 검증절차를 거치지 않은 사용자 입력값이 운영체제 명령어의 일부 또는 전부로 구성되어 실행될 경우, 의도하지않은 시스템 명령어가 실행되어 부적절하게 권한이 변경되거나 시스템 동작 및 운영에 악영향을 미칠 수 있다.

 

2. 안전한 방법

웹 인터페이스를 통해 서버내부로 시스템 명령어를 전달시키지 않도록 구성하고, 외부에서 전달되는 값을 그대로 시스템 내부 명령어로 사용하지 않는다. 또는 외부입력에 따라 정해진 명령어를 미리 생성하여 선택하여 사용하게한다.

 

3. 예시

사용자의 입력을 검증하지않고 그대로 사용하여 cmd.exe를 사용한 rmanDB.bat 배치 명령어가 수행되는 경우 (배치파일이란 여러명령어를 한번에 실행하기위한 파일을 의미)

다음은 사용자의 입력을 통해 미리 만들어놓은 인자값을 선택하게 만든방법이다.

반응형
반응형

1. 크로스 사이트 스크립트란?

페이지에 악의적인 스크립트를 포함시켜 사용자 측에서 실행되게 유도할 수 있다. 다음 그림과 같이 악성 스크립트를 서버측에 저장하면 다른사용자는 악성스크립트가 포함된 페이지를 응답받고 정보유출이 될 수 있다.

2. 안전한 코딩기법

일반적으로 사용자가 문자열에 스크립트를 삽입하여 실행하는 것을 막기 위해 사용자가 입력한 문자열에서 <, >, &, " 같은 문자열을 replace같은 메소드를 사용하여 치환하거나, 보안성이 검증되어 있는 API를 사용하여 위험한 문자열을 제거한다.

 

3. 예시

다음은 외부 입력값을 name으로, 특별한 처리과정없이 결과 페이지 생성에 사용하고 있다. 만약 다음과 같은 악의적인 스크립트(<script> url = "http://devil.com/attack.jsp;</script> 를 공격자가 넣으면, attack.jsp가 수행되며, 희생자의 쿠키정보 유출 등의 피해를 주게 된다.

 

따라서 다음과 같이 replaceAll()메소드를 사용하여 <, >같은 스크립트 생성에 사용되는 문자열을 &lt; &gt; 같은 형태로 변경함으로써 스크립트 수행위험을 줄일 수 있다.

 

 

다음 예제의 경우 OSWASP에서 제공하는 보안 API를 사용하고 있다. 보안 API를 사용하면 특수 문자를 이용한 공격 스크립트와 같은 외부 입력 문자열을 이용한 공격을 차단할 수 있다.


4. 추가적인 방법

앞선 부분은 pdf에서 제공하는 부분으로 API와 replace를 이용한 방법은 예전 방식의 느낌이 나서 찾아보았다.

 

다음은 EL <%= %>표현이 아닌 JSTL의 c:out을 활용한 방법이다. c:out을 당연하게 사용해 왔지만 c:out이 XSS를 대비한 방법이라는것을 알았다.

 

c:out은 기본적으로 escapeXml이 true로 되어 있기 때문에  < > & ' " 문자들을 각각 &lt; &gt; &amp; &#039; &#034; 로 출력한다. 이러한 방법은 앞서 replace를 사용한 방법의 상위 방법으로, 따라서 악성 스크립트가 실행되는것을 방지한다.

<%
 String greeting = "<b>hello, world!</b>";
 request.setAttribute("greeting", greeting);
%>
<h2>escapeXml false</h2>
<c:out escapeXml="false" value="${greeting}" />
<h2>escapeXml true</h2>
<c:out escapeXml="true" value="${greeting}" />
<h2>default</h2>
<c:out value="${greeting}" />

이는 다음과 같이 false가 되어있는 부분은 태그를 인식하여 출력하고, true로 되어있는 부분은 String 그대로 출력하는것을 확인할 수 있다.

 

hello, world!

<b>hello, world!</b>

 

Vue에서의 XSS방지

vue의 기본적으로 XSS를 방지하기위해 이를 자동으로 이스케이프 한다. 즉 기본적으로 XSS에 대한 방지를 지원한다.

userProvidedString = '<script>alert("hi")</script>'
<h1>{{ userProvidedString }}</h1>

따라서 이는 다음과 같이 출력될것이다.

&lt;script&gt;alert(&quot;hi&quot;)&lt;/script&gt;

만약 html이 내부에 들어가야한다면 다음과 같이 이용할 수 있다.

<div v-html="userProvidedHtml"></div>

 

lucy-xss-servlet-filter적용

https://github.com/naver/lucy-xss-servlet-filter

 

naver/lucy-xss-servlet-filter

Contribute to naver/lucy-xss-servlet-filter development by creating an account on GitHub.

github.com

참고

반응형
반응형

1. 자원삽입이란?

외부 입력값을 검증하지 않고 시스템 자원에 대한 식별자로 사용하는 경우, 입력값 조작을 통해 시스템이 보호하는 자원에 임의로 접근하거나 수정할 수 있는 보안적 이슈

 

2. 안전한 코딩기법

외부의 입력 자원을 식별자로 사용할 경우, 적절한 필터링 및 검증을 거치거나, 사전에 정의한 리스트에서 선택하도록 만든다.

 

3. 예시

사용자가 입력 소켓 번호로 -2920값을 입력할 경우 80이 되어 포트 충돌이 일어나는 상황

...

String service = props.getProperty("Service No");
int port = Integer.parseInt(service);

if(port != 0)
	serverSocket = new ServerSocket(port + 3000);
else
	serverSocket = new ServerSocket(def + 3000);

 

다음과 같이 미리 리스트를 정해주고 사용자는 입력값을 번호로 하여 내부적으로 할당하도록 처리한다.

..

if(in != null && in.available() > 0){
	props.load(in);
    service = props.getProperty("Service No");
}

if("".equals(service)) service = "8080"

int port = Integer.parseInt(service);

switch(port)
{
	case 1:
    	port = 3001; break;
    case 2:
    	port = 3002; break;
    default:
    	port = 3000;
}

serverSocket = new ServerSocket(port);
반응형

+ Recent posts