ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [보안] 웹 애플리케이션에 대한 대표적인 공격 수법 / 대책
    우아한 테크코스/테크코스 2020. 2. 21. 22:57
    반응형

    SQL 인젝션(SQL Injection)

     웹 폼 등의 입력 인터페이스를 이용해 DB에서 발행되는 SQL을 개발자가 의도하지 않은 형태로 변경해 정보를 부정 취득하거나 수정하는 방법

     이 공격 수법을 이용하면 부정 로그인뿐 아니라 DB에 대해 임의의 SQL을 싫애해 악의적인 사용자 계정을 만들거나 원래 취득할 수 없는 정보를 화면에 표시하게 할 수 있음(그러자면 DB 테이블 구성을 파악해야 하지만, 공격자는 화면에 표시되는 SQL의 실행 에러를 실마리로 내부 구조를 추측할 수도 있음)

     제삼자의 부정 로그인이나 열람 권한이 없는 정보에 대한 접근, DB의 부정 수정 또는 삭제같은 공격을 허용하며, 그 결과 개인정보의 유출/업무 정지/혼란 같은 문제로 발전

     무서운 점은 인터넷을 경유해 전 세계 어디에서도 공격할 수 있다는 점과 피해자가 정보 유출을 깨닫기 어렵다는 점. 공격을 받았다는 사실을 깨닫지 못하면 발견 시기가 늦어져 피해가 확대됨. SQL 인젝션 전용 공격 툴도 있는데, 이것을 이용하면 비전문가도 쉽게 공격이 가능함

    구조

    만약 로그인 판정 로직이 SQL의 결과로1건 이상의 레코드가 존재할 경우 로그인 성공으로 판단하는 방식이라면? 로그인 성공

    // SQL 조립 프로그램
    "select * from USER where USER_NAME=" + userName + " and PASSWORD=" + password +""
    
    // 로그인 화면 - SQL 인젝션 시도
    ID : cracker
    PW : aaa' or '1'='1
    
    // 조립된 SQL
    select * from USER where USER_NAME='cracker' and PASSWORD='aaa' or '1'='1'

    SQL 인젝션을 막기 위한 방법 1) 입력값의 확인

     가장 효과적인 방법

     예) 패스워드 입력에 대해 반각 영문과 숫자만 허용하면 SQL인젝션에서 이용하는 "'"(어포스트로피)의 입력을 방지할 수 있음, 아니면 아래처럼 엄격하게 확인할 수도 있음

    /* 상품 코드 입력 확인 조건의 예 */
    상품 코드: JAMIE-95
     <조건>  - 최초의 다섯 문자는 대문자 알파벳
            - 여섯 번째 문자는 하이픈
            - 일곱 번째부터 여덟 번째 문자는 숫자

     대부분의 프레젠테이션 프레임워크(예, 스트러츠)는 이런 입력 확인을 자동으로 실행하는 유효성 검사(Validation) 기능을 제공하므로, 손쉽게 SQL 인젝션을 막을 수 있음

    SQL 인젝션을 막기 위한 방법 2) 준비된 문장(Prepared Statement)의 이용

     문자열의 연결로 SQL을 조립하는 것이 아니라 WHERE 절 등 조건에 따라 변화하는 부분을 플레이스홀더로 등록한 SQL을 미리 준비해 놓았다가 나중에 매개변수를 할당(바인드)하는 방법

    String userName : (아이디);
    String password : (비밀번호);
    Connection conn = (DB 연결 객체);
    
    // 준비된 문장 준비
    PreparedStatement st = conn.prepareStatement(
        "select * from USER where USER_NAME=? PASSWORD=?"); // ? = 플레이스홀더
        
    st.setString(1, userName); // 첫 번째 플레이스홀더에 아이디를 넣음
    st.setString(2, password); // 두 번째 플레이스홀더에 비밀번호를 넣음
    
    // SQL의 실행
    ResultSet rs = st.executeQuery();

     준비된 문장은 시간이 걸리는 SQL의 구조나 조건의 해석을 미리 끝내 놓고 플레이스홀더 부분을 나중에 바꿔 넣을 수 있게 만든 것, 데이터베이스 연결의 성능을 향상시키기 위한 구조

     문자열 결합과 다른 점은 SQL의 해석을 먼저 실행하기 때문에 나중에 조건의 추가 등 구조 변경을 할 수 없다는 것 = SQL 인젝션 방지에 도움을 줌

     O/R 매핑 프레임워크(예, 아이바티스)는 대개 내부에서 준비된 문장을 이용하므로 O/R 매핑 프레임워크를 이용하는 것도 SQL 인젝션의 방지로 이어짐

    크로스 사이트 스크립팅(XSS; Cross Site Scripting))

     HTML 안에 악의적인 작동을 하는 자바 스크립트(JavaScript)를 심는 공격 수법, 자바스크립트 인젝션이라고도 함

     자바스크립트는 웹 사이트에서 웹 브라우저로 반환되는 응답(HTML) 안에 심어 넣을 수 있으며, 심어 넣은 스크립트를 웹 브라우저에서 실행할 수 있음. 여기서, 악의적인 스크립트가 실행되면 쿠키의 도난이나 페이지의 수정 등이 가능함

     > 크로스 사이트 스크립팅은 부정 로그인이나 개인 정보의 유출 같은 문제로 이어짐

     XSS(크로스 사이트 스크립팅)에 이용되는 것은 폼에 입력된 문자열을 그대로 HTML로 출력하는 사이트

     자신이 폼에 입력한 스크립트가 자신의 브라우저에서 실행될 뿐이면 그다지 문제가 되지 않음, 하지만 이런 취약점이 있는 사이트가 악의적인 공격자에게 발견되면 그 사이트가 공격의 발판으로 이용 됨, 즉 공범이 되고 말아버림

     예) 공격자가 준비한 사이트에 취약 사이트로 이동하는 링크를 준비하고, GET 요청을 이용해 취약 사이트로 자바스크립트를 전달하게 함. 해당 링크를 클릭하면 자바스크립트가 취약 사이트를 경유해 피해자의 브라우저로 전송되어 실행되고, 공격자가 준비한 악의적인 스크립트가 실행되면 그 스크립트는 피해자의 브라우저가 저장하고 있는 쿠키의 내용을 훔치거나 세션 하이재킹 등의 피해를 일으킴

    구조

    // 로그인 화면
    ID : Jamie
    PW : jamie
    
    // 로그인 이후 화면 - 폼에 입력된 문자열을 그대로 HTML으로 출력
    Jamie님, 안녕하세요?
    
    // 로그인 화면 - XSS 시도하기(본인 컴이라 문제 없음)
    ID : <script>alert('This is XSS');</script>
    PW : jamie
    
    // 요청은 예를 들어 아래와 같이 넘어감(단, 인코딩이 되어서 넘어감 유의)
    http://jamie95.tistory.com/login.php?userId=<script>alert(This is XSS)</script>&pwd=jamie
    
    // 악의적인 공격자 사이트
    이 _링크_(위의XSS시도URL)를 눌러보세요!
    
    // 누른 사람(피해자)의 화면 : 로그인 화면으로 전환되면서, XSS Alert이 띄워짐
    "This is XSS"

    크로스 사이트 스크립팅(XSS)를 막기 위한 방법 - 새너타이징(Sanitizing)

     HTML에서 문자열을 출력할 때 새너타이징(Sanitizing)이라는 처리를 하는 것이 효과적

     새너타이징(의미 : 소독한다) : HTML에 심으면 HTML의 원래 구조를 바꾸거나 파괴하는 문자열을 제거하거나, 해롭지 않은 문자열로 변환하는 과정을 의미

    /* 새너타이징을 통한 특수 문자의 치환 */
    <script>alert('xss')</script>
    
    // 새너타이징
    &lt;script&gt;alert(&apos;XSS;&apos;)&lt;/script&gt;

     새너타이징을 해서 얻은 문자열은 HTML에 출력했을 때 처음에 입력한 문자열과 동일한 결과를 얻을 수 있음

     새너타이징은 출력 대상에 따라 치환 대상이 되는 문자가 달라짐, HTML이라면 <, >, &, "," 같은 문자가 치환 대상, SQL에서는 ' , --(주석) 같은 문자가 치환 대상이 되므로 출력 대상에 맞춰 처리해야 함

     위와 같은 처리를 실행 환경이나 프레임워크에서 제공하는 경우도 있으므로, 그런 기능들을 이용하면 편리함(예-PHP의 htmlspecialchars 함수 : 인수에 지정한 문자열 가운데 HTML의 특수 문자열을 문자 참조로 치환 / 스트러츠 : bean:write 태그로 문자열을 출력할 때 같은 처리를 할 수 있음 / 그 외 프레젠테이션 레이어를 다루는 다른 프레임워크 중에도 같은 기능을 갖추고 있는 것이 많으니 새로운 프레임워크를 이용할 때는 한 번쯤 살펴보기)

     주의점! 새너타이징 시점. 새너타이징과 입력 확인은 비슷한 효과를 낳기 때문에, 입력 확인을 생략하고 프레임워크 등이 제공하는 자동 새너타이징 기능에 맡기는 사례도 볼 수 있지만, 기본적으로는 입력 확인을 통해 시스템이 받아야 할 문자열을 추려놓고 출력시 출력 대상에 맞춰 새너타이징을 하는 것이 좋음

    세션 하이재킹(Session Hijacking)

     클라이언트와 서버가 주고받는 세션 ID를 제삼자가 훔침으로써 웹 사이트의 사용자를 가장해 서비스를 이용하는 공격. 세션을 강탈하기 때문에 세션 하이재킹이라고 함

     웹 애플리케이션에서 사용되는 HTTP는 상태를 보존할 수 없는 무상태 프로토콜이기 때문에, 로그인 상태나 장바구니 내용 등 상태를 보존하려면 세션이라는 기술이 필요

     하지만 세션의 실체는 쿠키나 GET 요청을 사용해 전송되는 세션 ID라고 하는 문자열에 불과함. 웹 애플리케이션이 '지금 시스템을 사용하는 사람이 JAMIE다'라는 것을 인식하기 위한 정보는 세션 ID뿐임. 사용하고 있는 세션 ID가 제삼자에게 알려지면 그 사람은 그 세션 ID를 이용해 JAMIE를 가장할 수 있음

     세션 ID를 도둑맞으면 공격자에게 JAMIE의 개인 정보가 유출되거나 JAMIE의 명의로 물건을 사는 등의 피해가 발생함

    구조

    {{웹 브라우저}}  (1) 쿠키나 GET 요청으로    {{애플리케이션 서버}}
                  전달되는 세션 ID : 2136               (2) 세션ID 2136 -> Jamie
     JAMIE     <----------------------->        ^
                             |                  |
                             V                  |    (5) 세션ID 2136 -> Jamie
                 (3) XSS, 네트워크 도청 등으로       |        (공격자의 접속과 진짜 Jamie의 접속 구분 불가)
                     세션 ID를 부정 취득     -------' 
                        {{ 공격자 }}        (4) 훔친 세션 ID로 접속
                                 

    세션 하이재킹을 방지하는 방법 - 가능하다면 전부 실행하는 것이 바람직

     1. 크로스 사이트 스크립팅(XSS) 대책

     2. 통신 경로의 암호화

     3. 세션 타임아웃 값의 변경

     4. 세션 ID의 랜덤화

    세션 하이제킹을 방지하는 방법 1. 크로스 사이트 스크립팅 대책(XSS)

     가장 자주 이용되는 세션 하이재킹 수단은 크로스 사이트 스크립팅, 따라서 크로스 사이트 스크립팅에 대한 취약성을 없애는 것은 세션 하이재킹에 대한 대책도 됨

    세션 하이제킹을 방지하는 방법 2. 통신 경로의 암호화

     인터넷을 지나가는 통신은 특수 장비나 소프트웨어를 이용하면 네트워크 도청이 가능함

     암호화되지 않은 통신 경로를 지나가는 세션 ID는 제삼자에게 도둑맞을 가능성이 있음 > 방지하려면 통신로를 SSL(Secure Socket Layer)로 암호화해야 함(최소한 인터넷상을 지나가는 세션 ID를 탈취당할 가능성이 사라짐)

    세션 하이제킹을 방지하는 방법 3. 세션 타임아웃 값의 변경

     세션 정보는 명시적으로 파기되지 않는 한 타임아웃이 발생할 때까지 서버에 계속 보존

     웹 애플리케이션의 사용자가 로그아웃을 깜빡하면 세션 타임아웃이 발생하기 전까지 세션 ID가 계속 유효한 상태로 남기 때문에 어떤 방법으로 세션 ID를 도둑맞았을 경우 피해를 입기 쉬움

     중요한 정보를 취급하는 웹 애플리케이션은 세션 타임아웃 시간을 짧게 설정해 만에 하나 세션 ID를 탈취당하더라도 악용될 위험성을 낮출 수 있음

     하지만, 너무 짧은 경우 웹 애플리케이션의 요청을 잠시 멈추기만 해도 세션이 무효화되어 재 로그인이 필요할 수 있음. > 사용성이 너무 나빠짐

     안전성과 조작성의 균형을 고려할 필요가 있음

    세션 하이제킹을 방지하는 방법 4. 세션 ID의 랜덤화

     자릿수가 매우 크지만, 단순한 숫자라서 순서대로 발행할 경우(1, 2, 3, 4 ...) 쉽게 추측할 수 있음

     충분히 큰 자릿수의 숫자 중 무작위 선택을 함으로써 공격자가 적당한 숫자를 선택해 세션 ID를 운좋게 맞히는 일이 없게 할 필요가 있음

     세션은 언어 처리계나 애플리케이션 서버를 통해 구현되므로, 이것들을 이용하는 한 개발자가 세션에 신경을 쓸 필요는 거의 없음. 하지만, 적어도 충분히 큰 자릿수의 숫자 중 무작위로 세션 ID를 선택하기 때문에 세션의 안전성이 보장된다는 점은 알아둬야 함

    크로스 사이트 요청 위조(CSRF; Cross Site Request Forgery)

     공격자가 날조한 폼에서 강제적으로 정보를 제출함으로써, 게시판에 의도하지 않은 글을 쓰거나 강제로 물건을 사게하는 공격

     폼 제출의 실체는 HTTP 요청에 불과하며, 표시된 폼의 HTML을 해석하여 어떤 매개변수를 송신하는지 알면 외부에서도 폼을 제출시킬 수 있음. 아래의 구조 예처럼 공격 대상의 게시판에 글을 쓰는 자바스크립트를 담은 후 HTML을 준비하고 onLoad 속성을 이용해 HTML을 읽는 동시에 자바 스크립트가 실행되게 만들고, 사이트나 이메일 등으로 피해자를 유인해 HTML을 읽게하면 피해자도 모르는 사이에 게시판에 글이 작성됨. 공격자는 자신의 손을 더럽히지 않고 피해자를 이용해 게시판을 공격할 수 있음

     무서운 점은 로그인이 필요한 사이트더라도 피해자가 이미 로그인을 했다면, 공격자가 ID와 PW를 모르더라도 공격할 수 있다는 점. 일반적으로는 세션 ID를 저장한 쿠키를 웹 브라우저에 송신하는 방법으로 로그인 상태를 관리하고, 쿠키를 받은 웹 브라우저는 그 쿠키가 무효화될 때 까지 같은 웹 사이트에 쿠키를 계속 보냄. 즉, 기 로그인이 된 상태의 웹 브라우저는 CSRF를 통해 폼을 제출할 때도 쿠키를 보내기 때문에 공격자가 의도한 폼 제출이 성공하는 것

    구조

    /* 크로스 사이트 요청 위조의 구조 */
    
    // 공격자 사이트
    이 _링크_(공격용 HTML으로 유인)를 클릭하십시오.
    
    // 공격자가 준비한 공격용 HTML
    <body onLoad="document.attackform.submit();">
    <for name="attackform" method="post" action="http:/jamie95.tistory.com/write.php">
        <input type="hidden" name="title" value="CSRF 공격">
        <input type="hidden" name="message" value="이 게시판은 공격받았음">
    </form>
    
    // 피해자가 해당 버튼을 누르면 강제로 글이 써짐
    안녕하세요                     <- 원래 쓴 글
      반갑습니다. Jamie입니다.
    CSRF 공격                    <- 강제로 같이 써진 글
      이 게시판은 공격받았습니다.

    CSRF(크로스 사이트 요청 위조)를 방지하는 방법. 자신의 서버에서 생성한 올바른 폼인지 확인

     CSRF가 성공하는 원인은 정규 웹 서버가 만들지 않은 폼에서 제출할 수 있기 때문이고, 그렇기 때문에 방지하기 위해서는 자신의 서버에서 생성한 올바른 폼인지 확인해야 함

     일회용 토큰을 발급하여, hidden 매개변수로 심어 폼을 만들어주고, 폼 제출시 해당 일회용 토큰값을 받아서 검증하는 방식으로 올바른 토큰일 경우에만 전송된 내용을 받아들여, CSRF 공격을 받아도 올바른 일회용 토큰을 가지고 있지 않은 내용을 부정한 것으로 간주해 배제하는 방법

     {{웹브라우저}}                      > 사용자 입력 폼 <
    1) 폼을 표시하기           <input type="hidden" name="token" value="ja2mi84e">
      위한 요청 발행      3) 생성한 토큰을 hidden                         |
               |       매개변수로 심어 넣은 폼을 돌려줌                    V
               |        ^                           4) 제출, 일회성 토큰도 같이 전송됨
               V        |                                          |
          {{애플리케이션 서버}}                                         V
           2) 일회용 토큰을 생성해 기억                   5) 받은 일회용 토큰을 조회해,
              (....)   사용 종료                       자신이 생성한 것이라면 폼 제출을 받아들임
              ja2mi84e 사용 중                               (....)   사용 종료
                                                            ja2mi84e 사용 종료
    hidden 태그 : 정확히는 type 속성이 hidden인 input 요소지만, 개발 현장에서는 hidden 태그라고도 부름
     텍스트 박스처럼 문자열을 입력시키는 것이 아니라, HTML상에 몰래 출력해두고 그것을 제출할 때 GET이나 POST 매개변수로 보내는 방법
     HTTP의 무상태 성질을 보완하려는 목적으로 요청 전후에 서버상의 어떤 상태를 주고받는데 이용

    강제 브라우징(Forceful Browsing)

     웹 브라우저의 주소창에 URL을 직접 입력하는 방법으로 본래 표시되면 안되는 화면이 나오게 하는 공격

     즉, 권한이 없거나 정상적인 프로세스가 아닌 접근을 하는 경우를 일컫음

    구조

     아래의 예에서 블로그 수정화면은, 로그인 후 권한이 있으면 자동으로 넘어가는 화면인데 공격자가 해당 URL을 알아내거나 유추 또는 즐겨찾기에 저장하여 직접 호출해버리는 경우

    <!-- URL과 화면의 대응(예) -->
    https://jamie95.tistory.com/        블로그 화면
    https://jamie95.tistory.com/setting 블로그 수정 화면 <!-- 로그인을 후 권한이 있으면 넘어가는 화면 -->

    강제 브라우징을 방지할 대책

     어떤 화면에 접속하든 반드시 로그인 상태를 확인하고 로그인 상태가 아니라면 로그인 화면을 경유하게 하는 등의 대책

     대책 예) 자바 스크립트를 이용해 웹 브라우저의 주소창이 표시되지 않게 함으로 URL의 확인이나 직접 입력을 불가능하게 만드는 애플리케이션.

    > 단, 자바스크립트는 웹 브라우저의 설정에 따라 비활성화되는 경우도 있으므로 많은 사람이 이용하는 웹 애플리케이션이 취할 대책으로는 적절하지 않음

    > 하지만 기업 내에서 특정인이 사용하는 웹 애플리케이션의 경우 보안 정책에 따라 브라우저의 설정을 통일할 수 있으므로 이런 대책도 효과적일 수는 있지만, 어디까지나 보조적인 수단

    유의할 점) 웹 서버 인덱스 표시

     웹 서버의 설정에 따라서 기본 설정된 HTML(예, index.html)이 존재하지 않으면 해당 디렉터리의 파일 목록을 표시하는 경우도 있는데, 웹 애플리케이션으로서는 시스템을 구성하는 파일이 그대로 노출되고, 여기서 또 다른 파일이 강제 브라우징될 가능성도 있기 때문에 보안상 위험함

     인덱스 표시 기능이 활성화되어있는지 여부는 디렉터리명으로 직접 접근해보면 금방 확인할 수 있음, 만약 인덱스 페이지가 보인다면 즉시 웹 서버나 애플리케이션 서버의 설정을 바꿔야 함

     > Apache Httpd의 경우엔 Indexes라는 설정이 활성화되어있다면 인덱스 표시가 활성화됨

    Index Of /jamie/jamie_1
    
             Name            Last modified     Size  Descriptions
    --------------------------------------------------------------
    [ ] Parent Directory                        -
    [ ] jamie.php          22-Feb-2020 10:30    2K
    [ ] jamie.html         22-Feb-2020 10:30    600
    [ ] jamie_name.php     22-Feb-2020 10:30    682
    [ ] jamie_age.php      22-Feb-2020 10:30    1.2K
    --------------------------------------------------------------

    디렉터리 접근 공격(Directory Traversal)

     요청으로 전달된 문자열을 사용해 시스템 내의 파일을 표시하는 애플리케이션에서는 디렉터리 접근 공격에 대한 취약성을 조심해야 함

    구조

    # 디렉터리 접근 공격에 취약성이 있는 PHP 코드
    ## GET 요청으로 전달된 filename이라는 매개변수를 파일명으로 취급하고
    ## 그 내용을 php의 readfile 함수로 읽어들여 표시함
    <?php
        $filename = $_GET['filename'];
        readfile("/var/www/".$filename);
    ?>
    
    # 정상 호출
    http://~/view.php?filename=test.html
    /var/www/test.html 호출
    
    # 디렉터리 접근 공격
    http://~/view.php?filename=../../etc/passwd
    /var/www/../../etc/passwd 호출
    > /etc/passwd : UNIX 시스템의 운영체제 계정 정보 기록된 파일 열람 가능

    디렉터리 접근 공격을 방지하기 위한 완벽하지 않은 방법 - 확장자 지정 (보완하기 : 새너타이징 & 접근권한)

     확장자 지정

    - 시스템에서 반드시 확장자를 붙이게 만듦

    # 확장자를 지정해 파일을 읽어들이는 코드
    <?php
      $filename = $_GET['filename'];
      readfile("/var/www/".$filename.".html");
    ?>
    
    # 정상 호출
    http://~/view.php?filename=test
    /var/www/test.html 호출
    
    # 디렉터리 접근 공격 - 실패
    http://~/view.php?filename=../../etc/passwd
    /var/www/../../etc/passwd.html 호출 - 파일 없음
    
    # 디렉터리 접근 공격 - 성공 - 널바이트 공격
    http://~/view.php?filename=../../etc/passwd\0
    /var/www/../../etc/passwd\0.html 호출 = \0부터 무시됨
    > /etc/passwd : UNIX 시스템의 운영체제 계정 정보 기록된 파일 열람 가능

    - 단, \0같은 매개변수로 해당 방법을 무효화 할 수 있음

    \0 : 대부분의 프로그래밍 언어에서 \0은 문자열의 끝을 나타냄, 그 이후의 문자열을 무시하는 효과
    일반적으로 널바이트(Null Byte)라고 부르는 공격을 할 때 사용 - (예) '../../etc/passwd\0'

     보완하기

     - 새너타이징 : /나 \ 등 파일명에는 사용되지 않는 문자를 삭제하는 것이 효과적

     - 파일 접근 권한 조정 : 만에 하나의 상황에 대비해 웹 애플리케이션을 실행하는 각 사용자가 자신과 관련된 파일 외에는 열람할 수 없도록 파일 시스템의 접근 권한을 적절히 설정

     

    디렉터리 접근 공격을 방지하기 위한 완벽한 방법 - 사용자가 입력한 매개 변수를 파일명으로 사용하지 않기

     가장 효과적인 대책은 가능한 사용자가 입력한 매개변수를 파일명으로 사용하지 않도록 설계하는 것

     

    반응형

    댓글

Designed by Tistory.