시큐어 코딩
Last updated
Last updated
[!NOTE] 안전한 SW 를 만들려면 시큐어 코딩을 꼭 익혀야 하며 이를 실무에 손쉽게 적용하기 위해서는 프레임워크 도입을 권장합니다.
OWASP 에서 1위로 선정한 위협으로 막기가 어렵지 않고 공격 당했을 경우 파급력이 크므로 꼭 고려해야 할 취약점입니다.
만약 사용자 id와 암호를 입력받아서 로그인을 처리하는 페이지가 있을 경우 SQL Injection 을 고려하지 않을 경우 다음과 같이 코딩하게 됩니다.
자바의 경우
위와 같은 코드는 클라이언트가 보낸 문자열을 검증없이 사용하므로 공격자가 password 에 ' or '1' = '1 라는 문자열을 넣으면 or 뒤의 문장이 참이므로 id와 암호를 몰라도 관리자로 로그인이 가능해져 버립니다.
이 공격을 막으려면 위와 같이 동적 쿼리를 사용하지 말고 준비된 문장(Prepared Statement)와 매개변수 바인딩(Bound Parameter) 을 사용해야 합니다.
PHP 의 경우 mysql_* 같은 직접 데이타베이스에 연결하는 함수보다는 PDO 를 사용하는 게 좋으며 Java 의 경우 JDBC 직접 사용보다는 MyBatis나 Hibernate 같은 프레임워크를 사용하는 것이 좋습니다.
PHP 라라벨의 경우 쿼리 빌더를 사용하여 아래와 같은 쿼리를 입력한 경우
다음과 같이 변환되므로 안전하게 실행됩니다.
인증이나 세션은 적절하게 보호되어야 하며 다음과 같이 관리되면 안 됩니다.
사용자 인증 정보를 해시나 암호화로 보호하지 않음
세션 ID 를 GET 파라미터로 전달하여 URL 에 노출
세션 타임 아웃이 설정되지 않았거나 너무 긴 경우
세션에 추가되는 정보가 유출 가능한 경우. 예로 관리자로 로그인했을 경우 admin=1 이 설정
위 문제를 해결하려면 HTTPS 를 적용하고 세션 데이타를 암호화 하는 게 좋습니다.
라라벨의 경우 다음과 같이 자동으로 세션 값을 암호화해서 전달합니다.
XSS 는 사용자의 입력값을 사용하여 동적인 내용을 표시하는 웹 페이지에서 외부 입력값에 대한 검증 없이 사용자에게 출력으로 내보내는 경우에 발생합니다.
즉 사용자가 글 쓰기가 가능한 게시판을 만들 경우 다음과 같이 게시글을 입력했을 때 이 글을 클릭한 사용자에게 바로 출력할 경우 자바스크립트가 실행되게 됩니다.
위와 같은 취약점을 XSS 라 하며 이를 사용하여 공격자는 악성코드를 유포하거나 사용자의 쿠키를 갈취할 수 있습니다.
사용자의 입력은 꼭 소독해서 사용해야 합니다.
PHP 는 htmlentities() 함수를 사용하여 입력 값을 소독할 수 있으며 Java 의 경우 OWASP 의 java encoder 라이브러리나 네이버의 lucy-xss-filter를 사용하면 됩니다.
얼마전 모 서점에서 주문 번호만 입력하면 다른 이의 배송 정보와 결재 정보를 그대로 볼 수 있는 취약점이 있었습니다. 1
이런 문제를 해결하려면 사용자가 직접 입력한 객체의 소유자를 검증하고 인증 여부를 확인해야 합니다.
위와 같은 코드를 app 로직마다 추가해야 하는데 실수로 빼 먹으면 보안 문제가 발생하므로 프레임워크를 도입하고 필터나 미들웨어같이 app 로직 전에 수행되는 기능을 사용하여 처리하는 게 좋습니다.
CSRF 는 인증된 사용자를 통해 공격자가 원하는 명령을 수행하게 하는 기법입니다.
공격자가 메일이나 사이트 게시글로 이미지나 링크를 전송하여 물품구매를 수행하거나 사이트 글을 변조하는 등의 작업을 수행할 수 있습니다.
CSRF 를 막기 위해서는 인증된 사용자라 하더라도 중요한 작업을 수행할 경우 다시 검증을 수행하도록 하는 방법입니다.
즉 POST/PUT/DELETE 등의 HTTP Method 수행시 FORM 등에 추측이 불가능한 임시 토큰을 삽입한 후에 서버에서 검증하면 됩니다.
프레임워크가 없이 이 공격을 막으려면 app 소스를 많이 수정해야 하므로 꼭 프레임워크 도입을 권장합니다.
라라벨의 경우 POST/PUT/DELETE HTTP Method 를 수행하면 자동으로 서버에서 CSRF 토큰을 검증하고 에러가 발생시 예외 처리하도록 동작하고 있으며 app\Http\Kernel.php 에 VerifyCsrfToken 미들웨어가 이 처리를 담당합니다.
"알려진 취약점이 있는 컴포넌트 사용(Using Components with Known Vulnerabilities)" 은 OWASP 의 2013년 Top 중 9위인 위협으로 컴포넌트, 라이브러리, 프레임워크등의 보안 취약점을 악용하여 공격에 노출되게 됩니다.
Linux 는 yum 이나 apt-get 같은 패키지 관리자 기능을 제공하므로 운영 체제나 인프라 SW의 패치가 매우 쉬워졌지만 app 에서 사용하는 library 나 컴포넌트는 변경시 영향도때문에 교체가 쉽지 않습니다.
이 취약점을 예방하기 하려면 다음과 같은 방법이 있습니다.
개발시 외부 컴포넌트는 패키지 관리자를 사용하여 관리합니다. 패키지 관리자는 사용하는 언어나 프레임워크에 따라 다르며 자바의 경우 maven, gradle, PHP 는 composer, ruby 는 bundle, python 는 pip 등이 있습니다. 패키지 관리자를 사용하면 특정 컴포넌트를 교체하기가 용이해 집니다.
내/외부 컴포넌트들의 버전 및 의존성을 식별할 수 있도록 관리합니다. 빌드된 바이너리의 버전 관리는 유의적 버전(Semantic Versioning)을 따르는 것이 좋습니다.
인터넷진흥원의 보호나라 & KrCERT나 CVE 취약점 데이타베이스 및 보안 메일링리스트등을 구독하여 최신 동향을 파악합니다.
상용 repository manager(Sonatype nexus등) 에서는 repos 에 있는 라이브러리를 스캔하여 취약점 보고서를 생성하는 기능 제공하는 경우가 있으므로 여건이 된다면 이런 제품을 사용하는 것이 좋습니다.