ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [CodeIgniter] 6. 놓치기 쉬운 보안
    Web/CodeIgniter 2015. 8. 24. 15:40

    6.1 SQL 삽입 공격(SQL Injection Attack)

     SQL 삽입 공격을 이용한 여러 가지 사례가 있지만 하나의 예를 들어 CodeIgniter에서 어떻게 막을 수 있는지 살펴 보도록 하겠습니다.


     다음과 같이 user 테이블이 있다고 가정합니다.



      id 

      user_id 

      password 

      1 

      advisor 

      1234 




     SQL 삽입 공격에 대해 취약한 사이트에 아이디 advisor' #, 비밀번호 2222로 로그인합니다.



     * 로그인 체크 쿼리

      SELECT * FROM user WHERE id = '$id' AND passwd = '$passwd';


     *SQL 삽입 공격에 의한 변조된 쿼리

      SELECT * FROM user WHERE id = 'advisor';


      

     변조된 쿼리를 보면 쿼리 중간에 #이 들어가 있습니다. 


     MySQL 에서 #은 주석처리의 의미입니다. 그래서 AND 뒤쪽 부분의 조건은 실행되지 않습니다. 결국 비밀번호를 몰라도 사이트에 로그인이 됩니다.


     CodeIgniter에서 SQL 삽입 공격을 막을 수 있는 방법에 대해 알아보겠습니다.


     



     $sql = "SELECT * FROM user WHERE id = '".$this->db->escape_str($id)." ' AND passwd = '".$this->db->escape_str($passwd)." ' ";


     $sql = "SELECT * FROM user WHERE id = ? AND passwd = ?";

     $this->db->query($sql, array($id, $passwd);

     

     $this->db->where(array('id => $this->input->post('id', TRUE), 'passwd' => $this->input->post('passwd', TRUE)));

     $this->db->get('user');




     첫 번째 방법은 $this->db->escape_str() 함수를 이용해 '(작은 따옴표)를 처리합니다.


     두 번째 방법은 CodeIgniter의 SQL 바인딩을 이용해 처리할 수 있습니다.


     세 번째 방법은 $this->input->post() 함수를 이용하는 방법입니다. CodeIgniter에서는 $_POST 형태로 폼 데이터를 받는 것이 아니라 $this->input->post() 함수를 이용합니다. 폼 데이터를 받을 때 예제처럼 두 번째 파라미터에 TRUE를 주면 SQL 삽입 공격 뿐 아니라 XSS에 대한 처리도 한꺼번에 처리합니다. 


     

     마지막 방법보다 더 간단하고 강력한 설정이 있습니다. 바로 config.php에 다음과 같이 설정하는 것입니다.



     * bbs/application/config/config.php


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    /*
    |--------------------------------------------------------------------------
    | Global XSS Filtering
    |--------------------------------------------------------------------------
    |
    | Determines whether the XSS filter is always active when GET, POST or
    | COOKIE data is encountered
    |
    */
    // $config['global_xss_filtering'] = FALSE;
    $config['global_xss_filtering'] = TRUE;
    cs



     

     위의 FALSE 값을 TRUE로 바꾸면 두 번째 파라미터 없이 $this->input->post('변수명')으로만 사용해도 자동으로 보안 처리를 해줍니다.








    6.2 XSS

     XSS는 cross-Site Scripting의 약어로 사이트간 스크립팅 또는 크로스 사이트 스크립팅이라 합니다.


     해커가 웹 페이지에 악성 스크립트를 삽입할 수 있는 취약점입니다. 이 취약점을 이용해 다른 사람의 쿠키나 세션 정보를 가로챌 수 있어 해커가 그 사용자의 관리 페이지에 접근 할 수 있습니다.


     게시판에 <script> alert('XSS!!');</script>라고 올리고 글을 봤을 때 경고창으로  XSS!!라고 뜬다면 XSS에 대비되지 않은 게시판입니다.


     4장에서 만든 게시판을 통해 실험해보겠습니다.



     게시글에 스크립트를 삽입하는 글을 올리겠습니다.







      확인 결과 [removed]로 대체 되었습니다.








     


     위와 같이 필터링이 되는 이유는 컨트롤러의 $this->input->post('변수명', TRUE)가 나옵니다. 두 번째 파라미터가 TRUE이면 POST 전송받은 변수의 값을 자동으로 XSS가 필터링해줍니다.











    6.3 CSRF

     CSRF(Cross-Site Request Forgery)는 크로스 사이트 요청 위조의 약어이며, 사이트의 인증된 사용자가 자신의 의지와는 무관하게 공격자가 의도한 행위를 특정 사이트에 요청합니다.


     이를 막기 위해서 서버의 상태를 변경하는 요청은 GET을 사용하지 않고 POST 전송의 경우에도 hidden 필드에 임의의 값을 전달하고 컨트롤러에서 그 키 값이 맞는 지 확인해야 합니다.


     CodeIgniter에서는 다음과 같은 방법으로 CSRF 공격을 막을 수 있습니다.



     * bbs/application/config/config.php


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     
    /*
    |--------------------------------------------------------------------------
    | Cross Site Request Forgery
    |--------------------------------------------------------------------------
    | Enables a CSRF cookie token to be set. When set to TRUE, token will be
    | checked on a submitted form. If you are accepting user data, it is strongly
    | recommended CSRF protection be enabled.
    |
    | 'csrf_token_name' = The token name
    | 'csrf_cookie_name' = The cookie name
    | 'csrf_expire' = The number in seconds the token should expire.
    */
    // $config['csrf_protection'] = FALSE;
    $config['csrf_protection'] = TRUE;
    $config['csrf_token_name'] = 'csrf_test_name';
    $config['csrf_cookie_name'] = 'csrf_cookie_name';
    $config['csrf_expire'] = 7200;
     
    cs



     Line 14번째를 TRUE로 변경합니다. 


     그리고 폼 전송 부분의 <form> 선언 부분을 form helper의 form_open() 함수로 바꿔주면 CSRF 방지를 위한 hidden 필드를 자동으로 삽입해줍니다. 컨트롤러에서의 체크 부분은 코어에서 자동으로 처리합니다.

     








     컨트롤러에서 폼 헬퍼를 로딩합니다.



     * board.php


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
     
    <?php
    if (!defined('BASEPATH'))
        exit('No direct script access allowed');
    /**
     *  게시판 메인 컨트롤러
     */
     
    class Board extends CI_Controller {
     
        function __construct() {
            parent::__construct();
            $this -> load -> database();
            $this -> load -> model('board_m');
            $this -> load -> helper(array('url''date'));
            $this -> load -> helper('form');
        }
     
     
        ........
     
     
     
    }
     
    cs




      * write_v.php


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
     
    <article id="board_area">
        <header>
            <h1></h1>
        </header>
        <!-- <form class="form-horizontal" method="post" action="" id="write_action"> -->
        <?php
            $attributes = array('class' => 'form-horizontal''id' => 'write_action');
            echo form_open('board/write/ci_board'$attributes);
       ?>
            <fieldset>
                <legend>
                    게시물 쓰기
                </legend>
                <div class="control-group">
                    <label class="control-label" for="input01">제목</label>
                    <div class="controls">
                        <input type="text" class="input-xlarge" id="input01" name="subject"
                            value="<?php echo set_value('subject'); ?>">
                        <p class="help-block">
                            게시물의 제목을 써주세요.
                        </p>
                    </div>
                    <label class="control-label" for="input02">내용</label>
                    <div class="controls">
                        <textarea class="input-xlarge" id="input02" name="contents" rows="5"><?php echo set_value('contents');?></textarea>
                        <p class="help-block">
                            게시물의 내용을 써주세요.
                        </p>
                    </div>
     
                    <div class="controls">
                        <p class="help-block"><?php echo validation_errors();?></p>
                    </div>
     
                    <div class="form-actions">
                        <button type="submit" class="btn btn-primary" id="write_btn">
                            작성
                        </button>
                        <button class="btn" onclick="document.location.reload()">
                            취소
                        </button>
                    </div>
                </div>
            </fieldset>
        </form>
    </article>
     
    cs



     기존의 폼 태그는 주석처리 후, 추가해야할 속성 값을 배열로 작성해서 form_open() 함수의 두 번째 파라미터로 전달합니다.





    * 이 포스트는 서적 '만들면서 배우는 CodeIgniter 프레임워크'를 참고하여 작성하였습니다


    댓글

Designed by Tistory.