강좌게시판

제목 CodeIgniter 보안강화
글쓴이 tpae 작성시각 2012/01/16 18:54:03
댓글 : 11 추천 : 6 스크랩 : 0 조회수 : 48528   RSS
안녕하세요 ^^

최근에 제가 운영하는 사이트에서 보안 문제로 말썽이 많았습니다. 

CodeIgniter 개발자분들은 한번씩은 꼭 생각해 주셔야 하는데요, 보안이 약한경우: 개인정보 유출이나 (SQL Injection), 악성코드 투입 (XSS), 세션 하이재킹 (MITM Attack), 등등...

CodeIgniter 2.1.0에서 보안쪽으로 많이 좋아졋는데요, 만약 1.7 쓰시는 분들은 업그레이드 하시는게 좋을듯 합니다.

CodeIgniter 해킹 당하는법은 여러가지 인데요, 제일 중요한것들은: SQL Injection, XSS, 하고 Session Hijacking 입니다.

1. SQL Injection - 데이터베이스 해킹

요즘들어서 뉴스에 많이 나옵니다. 미국 해커그룹 "ANONYMOUS"가 자주 사용하는 해킹 방법인데요, SQL Injection을 사용해 데이터를 빼오거나, 파괴할수 있습니다.

예를 들자면:
function getBlogById($id) {
    $sql = "SELECT * FROM blogs WHERE id=$id;";
    $query = $this->db->query($sql);
    return $query->result();
}
만약 제가 id 대신, "' '; DROP TABLE blogs;' 이런 코드를 사용한다면, 결과적으로:
SELECT * FROM blogs WHERE id=$id

SELECT * FROM blogs WHERE id=''; DROP TABLE blogs; 
이런 query가 실행됀다고 생각하시면 됍니다. example이 조금 간단한데요 ㅡㅡ;; 예를 들자면 이렇습니다. 여기에 조금더 자세하게 나오네요:  http://blog.naver.com/ubera5?Redirect=Log&logNo=10118490999 

해결법:

1. ActiveRecord를 사용하기.

CodeIgniter에서 ActiveRecord에선 저절로 Sql Injection 보호가 처리됍니다. 하지만, ActiveRecord를 사용하실수 없을 경우, $this->db->escape을 사용하시면 됍니다.

2. $this->db->escape($data);

사용법: 
function getBlogById($id) {
    $sql = "SELECT * FROM blogs WHERE id='".$this->db->escape($id)."';";
    $query = $this->db->query($sql);
    return $query->result();
}
이걸 사용하시면 악성 코드를 String으로 바꿔서 넣습니다. 예를 들자면, ' /' 로 바꾸는거죠. 그럼 간단한 보안처리가 됍니다.

3. $this->db->query($sql, array());

CodeIgniter에서 사용할수 있는, Parameterized 옵션도 있습니다. 이걸 사용하셔도 괜찬은데요, 사용법을 볼까요?
function getBlogById($id) {
    $sql = "SELECT * FROM blogs WHERE id='?';";
    $query = $this->db->query($sql, array($id));
    return $query->result();
}
이렇게 하시면, ? 물음표가 저절로 $id로 바뀝니다.

2. XSS Attack - 악성 코드 투입

XSS란, "Cross Site Scripting" 이란 것인데요, 쉽게 말하자면... 해커가 정보를 남길때, 그냥 정보만 남기는게 아니라, 악성 Javascript나, ActiveX 스크립트를 남길수 있다는거죠. 그렇게 됀다면, 다음 유져가 들어왔을때, 공격에 당하는것 입니다.

누구나 한번쯤은 공격을 당하셧을겁니다. 가장 흔하게 사용돼는 방법이니까요.

예를 들자면, 그냥 HTML Form Input에 스크립트를 넣으면 됍니다.
<script> //악성코드 투입.. </script>
그럼 그게 데이터베이스에 저장이 돼고, 다른 유져가 불러올때, 실행이 됀다는거죠. 한국에서 Internet Explorer 많이 쓰는데요, 이런 문제로 심각합니다.

해결법:

1. config.php에서 설정하기.

application/config/config.php 에서 $config['global_xss_filtering'] 있는데요, 이걸 TRUE 하시면 됍니다. 그리고 꼭!! $_POST 대신, $this->input->post()를 사용하세요.
$config['global_xss_filtering'] = TRUE;
하지만, Ajax Post 사용하시는분들은, 문제점이 있을겁니다. 만약 Ajax Post 사용하신다면, 이걸 사용하시 마세요.

2. $this->security->xss_clean($data);

먼저 $this->load->library('security')를 해주셔야 사용할수 있는데요, autoload 해주셔도 괜찮습니다.
function addBlog($content) {
    $insert_content = $this->security->xss_clean($content);
    $query = $this->db->insert('blog', $insert_content);
}
이렇게 하시면 안전합니다. ^^

3. Session Hijacking - 세션 보안

Session Hijacking은 주로 보기 드문데요, 하지만 이걸로 사용해서 큰 문제를 이르킬수 있습니다.

만약에 유져가 사이트에 가입이 돼있는 상태인데, 해커가 Session을 훔칠수 있다고 생각하시면 됍니다. Session을 훔친다는것은, 그 유져가 로그인 상태를 말하는데요, 그 유져에 정보들을 빼오거나 변경할수 있죠.

하는 방법은.. Cookie를 훔치는건데요, XSS 사용해서 Cookie를 빼온다음, 그 안에 Session ID를 도용해서, 브라우져 Cookie를 만든 다음 Session ID를 바꾸면 끝입니다.

다른 방법도 있습니다. 하지만, 제가 말했듯이 보기 드문데요. 만약 중요한 유저 정보를 가지고 계신분들은 한번 생각해보시는게 좋을듯 합니다.

CodeIgniter에선 Session Hijacking에 대한 보안이 잘돼어 있습니다.

해결법: 

1. config.php에서 설정하기.

여기에서 고칠것들이 여러가지 있습니다. 중요한건 sess_match_useragent 하고 sess_match_ip 인데요, 이것들은 둘다 TRUE로 바꿔주시면 좋습니다.

useragent란, 브라우져, OS등을 말하는데요, 하지만 쉽게 바꿀수 있는건데요, sess_match_ip 해주시면, IP는 바꾸기 힘드니까, 둘다 하시면 안전합니다.

물론.. sess_expiration을 낮추는게 보안적으로 좋습니다.
$config['sess_expiration'] = 7200;
$config['sess_match_ip'] = TRUE;
$config['sess_match_useragent'] = TRUE;
2. CSRF Protection

CSRF란, "Cross-site request forgery" 라고 하는데요, 이걸 이용해서 Session을 훔칠수 있습니다. CodeIgniter에서 이것도 보안이 돼는데요, application/config/config.php에서
$config['csrf_protection'] = TRUE;
이렇게 새팅 해주시면 괜찮습니다.

질문들은 댓글로 남겨주세요~ 감사합니다~
태그 SQL Injection,Session Hijacking,XSS,보안
 다음글 Codeigniter Ajax 사용법 (8)
 이전글 개별 개발환경 셋팅하기 (4)

댓글

세콩 / 2012/01/16 19:30:58 / 추천 0
좋은정보 감사합니닷~~ (_ _) 꾸벅~
한대승(불의회상) / 2012/01/17 17:47:40 / 추천 0
좋은 정보 감사 합니다. ^^

이 많은 것들을 일일이 구현해서 쓴다면 어휴.... ==3
생각만 해도 끔찍하네요.
milosz / 2012/01/17 19:50:35 / 추천 0
 좋은 정보 감사합니다 ^^
tpae / 2012/01/17 20:10:09 / 추천 0
네.. 많은 정보들인데요.. 제가 안하고 있다가 정말로 고생했거든요.. 제 생각엔 필수라고 생각합니다.
변종원(웅파) / 2012/01/17 20:36:59 / 추천 0
전 하나 빼고 적용해서 씁니다. (깔때기~~~~~~)
이현석 / 2012/01/18 01:43:18 / 추천 0
추천을 안할 수 없는 글이로군요!
DJ구스 / 2012/01/18 09:55:59 / 추천 0
제가 보다가 좀 이상한 부분이 있어서요..

우선 
1. config.php에서 설정하기.

application/config/config.php 에서 $config['global_xss_filtering'] 있는데요, 이걸 TRUE 하시면 됍니다. 그리고 꼭!! $_POST 대신, $this->input->post()를 사용하세요.
1.http://codeigniter-kr.org/include/syntaxhighlighter/styles/wrapping.png) !important; background-attachment: initial !important; background-origin: initial !important; background-clip: initial !important; background-color: initial !important; float: none !important; vertical-align: baseline !important; position: static !important; left: auto !important; top: auto !important; right: auto !important; bottom: auto !important; height: auto !important; width: auto !important; line-height: 1.1em !important; font-size: 1em !important; display: block !important; text-indent: -1.5em !important; background-position: 0px 1.1em !important; background-repeat: no-repeat no-repeat !important; ">$config['global_xss_filtering'] = TRUE;
하지만, Ajax Post 사용하시는분들은, 문제점이 있을겁니다. 만약 Ajax Post 사용하신다면, 이걸 사용하시 마세요 

이부분은 상관이 없구요.. 제가 등록한 config.php 처럼..
$config['csrf_protection'] = TRUE;
이 부분이 AJAX 관련 별도 작업을 해주셔야 합니다.

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

폼을 생성해서 post값을 넘겨줄때 CSRF못하도록 토큰을 생성해서 비교하여 처리 하는 부분을 AJAX로 하게 될 경우 별로도 생성을 해줘야 하거든요.. CI한사포 검색하시면 나올 것입니다. 내용이 바뀐거 같아 등록합니다.^^; 
아닌가? 제가 잘못 알고 있나요? 음..다시 봐야겠다

/*
|--------------------------------------------------------------------------
| Global XSS Filtering
|--------------------------------------------------------------------------
|
| Determines whether the XSS filter is always active when GET, POST or
| COOKIE data is encountered
|
*/
$config['global_xss_filtering'] = TRUE;

/*
|--------------------------------------------------------------------------
| 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_token_name'] = 'ARU_CSRF_R2D2';
$config['csrf_cookie_name'] = 'ARU_csrf_code';
$config['csrf_expire'] = 7200;
 
tpae / 2012/01/18 14:38:33 / 추천 0
 DJ구스님 말이 맞는데요,

AJAX POST 사용하면 대부분 JSON으로 POST하는데요.  global_xss_filtering 사용하시면 JSON에다가 escape string을 추가 한다는거죠. CI 버그라고 보시면 됍니다. 


tpae / 2012/01/18 14:40:48 / 추천 0
 그리고 CSRF에서 ajax post할순 없습니다. 하지만, CI Form을 사용하지 안을경우, CSRF 체크 안하는걸로 알고 있습니다. 그래서 따로 하고 안하고 할필요는 없다고 생각합니다.
DJ구스 / 2012/01/18 22:59:03 / 추천 0
 AJAX POST 사용하면 대부분 JSON으로 POST하는데요.  global_xss_filtering 사용하시면 JSON에다가 escape string을 추가 한다는거죠. CI 버그라고 보시면 됍니다. 


이부분 고민 하고 있었는데..ㅋㅋㅋ

고맙습니다. 또하나 배워갑니다.

kirrie / 2012/06/19 16:56:26 / 추천 0
 그런데 php의 mysql_ 함수들은 하나의 세션에 쿼리 두개를 보낼 수 없습니다.
즉,  SELECT FROM blogs WHERE id=''DROP TABLE blogs; 이 쿼리를 그대로 보내면 에러가 납니다.
mysqli_ 함수에서는 두개를 보낼 수 있었던 것으로 기억합니다.