secure coding
- 개념
- 안전한 소프트웨어 개발을 위해 소스 코드 등에 존재할 수 있는 잠재적인 보안 취약점을 제거, 보안 고려해 기능을 설계 및 구현
- 필요성
- 각 기관에서의 필요성 제고
- 릴리즈 이전 SW 취약점을 50% 줄이면, 침해사고 대응 비용 75% 감소 - Gartner
- 보안 취약점의 92%는 네트워크가 아닌 애플리케이션에서 발견 - NIST
- 릴리즈 이후 오류 수정은 약 $30,000 소요, 하지만 개발 중 오류 수정은 약 $5,000면 충분 -NIST
- 릴리즈 이후 오류를 수정하고자 할 경우 설계 단계보다 비용 100배 증가
- 이러한 이유로 미국의 경우 국토안보부(DHS)를 중심으로 시큐어코딩을 포함한 SW 개발 전과정(설계, 구현, 시험 등)에 대한 보안활동 연구를 활발히 진행하고 있다.
- 국내의 경우 2009년 부터 전자정부 서비스 개발단계에서 SW 보안 약점을 진단하여 제거하는 시큐어 코딩관련 연구를 진행하면서 2012년까지 전자정부지원사업 등을 대상으로 SW 보안약점 시범진단을 수행
- 2012년 6월 부터는 행정안전부 '정보시스템 구축, 운영 지침(행안부고시 제 2012-25호)'이 개정, 고시 됨에 따라 전자정부서비스 개발시 적용토록 의무화
- 가이드라인
- OWASP
- OWASP(The Open Web Application Security Project)의 약자로 국제 웹 보안 표준 기구 의미
- 주로 웹에 관한 정보노출, 악성 파일 및 스크립트, 보안 취약점 등을 연구하는 기관으로 2004년~2013년까지 총 4회 걸쳐(2004, 2007, 2010, 2013) 10대 웹 애플리케이션의 취약점 발표
- OWASP TOP 10으로 불려지는 이 가이드는 특히 웹 애플리케이션 취약점 중에서 빈도가 많이 발생하고, 보안상 영향을 크게 줄 수 있는 점들을 주요로 다루고 있어 시큐어 코딩의 중요한 기준으로 활용되고 있다.
- CERT
- CERT(Computer Emergency Response Team)의 약자, 1988년 미국에서 발생한 해킹 사고 이후 결성된 기관
- 컴퓨터 프로그래밍 언어별로 각 시큐어 코딩 표준 가이드가 제공되어 보다 안전한 프그램을 개발할 수 있도록 하고 있다.
- CWE
- CWE(Common Weakness Enumeration)의 약자로 프로그래밍에 있어 공통적으로 나타날 수 있는 취약점들을 표준화한 가이드라인
- MISRA C
- MISRA C는 차량용 소프트웨어의 안전성을 높이기 위해 출판된 코딩 가이드라인으로 자동차 업체 뿐만 아니라 철도, 의료 등의 다양한 산업에서 적용되고 있다.
- 국내 가이드
- SW 개발 단계부터 보안약점 제거(시큐어코딩) 의무화
- 정보 시스템 구축, 운영 지침 개정안 행정예고
- 행정안전부는 사이버 공격의 주요 원인인 소프트웨어 보안약점을 개발단계부터 제거하기 위해, '소프트웨어 개발보안(시큐어 코딩)'을 의무화하는 정보시스템 구축,운영 지침 개정안을 마련하여 행정예고 한다고 밝혔다.
- 금번 개정안은 행정 기관 및 공공기관이 정보화사업을 추진함에 있어 소프트웨어 개발보안을 적용,점검하기 위한 기준과 절차 등을 규정한 것으로 주요 내용은 다음과 같다.
- 금년 12월 부터(본 지침 고시후 6개월 경과한 날부터) 행정기관 등에서 추진하는 개발비 40억원 이상 정보화사업에 소프트웨어 개발보안 적용을 의무화하고, 단계적으로 의무 대상을 확대하여 '15년에는 감리대상 전 정보화사업에 소프트웨어 개발보안을 적용한다.
다만, 상용소프트웨어는 소프트웨어 개발보안 적용대상에서 제외된다. 소프트웨어 개발사업자가 반드시 제거해야 할 보안약점은 SQL 삽입, 크로스사이트스크립트 등 43개 이다.
감리법인은 정보시스템 감리시 검사항목에 보안약점 제거여부를 반드시 포함하여야한다.
감리법인은 효과적인 보안약점 진단을 위해 진단 도구를 사용할 경우 국정원장이 인증한 보안약점 진단도구를 사용해아여야 한다.
('14.1월부터 적용)
- 사고사례
-
Ariane 5 Explosion
- 로켓의 자세를 결정하는 관성 기준 시스템(Inertial Reference System)에서 오버플로우 발생
- 수평 속도 데이터를 64bit float-point에서 16bit signed int로 변환하는 과정에서 오버플로우
- Exception -> 백업 시스템 발동 해야함 -> 제대로 보호하지 못해 Operand Error 발생
inline
함수, static
변수 사용 권함
PRE-00. 함수형의 매크로 보다는 inline함수, static변수 사용하라
- inline 함수 링크참고, inline함수의 주의점도 참고!!
- static 변수 링크 참고
- 일반 함수 Symbol이므로, Symbol 호출 오버헤드 존재
- 간단한 코드에 대한 함수 호출은 성능 상의 이슈 발생 가능성
- linker가 symbol을 중첩 에러가 날 수 있음
위험한 코드 1
- 일반 함수로 호출 시
위험한 코드 2
- 매크로 함수 호출 시, 사용된 인자에 대한 증가, 감소, 메모리 변수 접근 등 side effect 발생 가능성
#include <stdio.h>
#define SQR(x) ((x) * (x))
int main() {
int i = 2;
printf("%d\n", SQR(++i));
return 0;
}
inline
사용
1,2 해결 방법: inline함수를 사용해 해결
- gcc에서
-std=c99, -std=c11
옵션 사용, 혹은 C99, C11 사용 시에는 extern inline으로 사용
#include <stdio.h>
extern inline int sqr(int x) {
return x * x;
}
int main() {
int i = 2;
printf("%d\n", sqr(++i));
return 0;
}
위험한 코드 3
- 매크로 함수를 통해 global 변수를 ++하고 싶은데, local 변수를 증가시킨다.
3 해결방법: inline함수를 사용해 해결
- gcc에서
-std=c99, -std=c11
옵션 사용, 혹은 C99, C11 사용 시에는 extern inline으로 사용
static
으로 scope 줄임
- 객체나 함수를 현재 스코프의 외부에 노출시키지 않을 것이라면 static 으로 선언
- C99
- 한 파일 스코프 내에서 객체나 함수에 대한 식별자의 선언이 static 을 포함하고 있으면 식별자는 내부에서만 결합(사용)된다.
- 한 파일 스코프에서 객체나 함수에 대한 식별자의 선언에 static 과 같은 저장 클래스 지정자가 없으면 식별자는 외부에서 결합(사용)된다.
square 함수가 내부적(internal)으로 사용된다고 가정했을 때, 다음 코드는 위험하다.
$ gcc main.c Calc.c -o main
$ ./main
12.560000
4
square 함수를 내부 연결성(internal linkage)를 갖도록 static으로 선언한다.
매크로
매크로는 괄호 필수
PRE-01. 매크로에서는 매개 변수에 괄호 사용
위험한 코드 1
- 아래 함수형 매크로는 괄호를 사용하지 않아 문제
3 * 3 = 9 를 예상하지만... 5 가나온다.
1 해결방법
- 매크로 괄호 필수
매크로 내에서는 ( )
괄호 필수
이제 결과가 9로 나온다.
매크로 치환 영역은 괄호
PRE-02. 매크로로 치환될 영역은 반드시 괄호로 둘러싸야함
- 매크로로 치환될 영역을 괄호로 둘러 싸면 근처의 표현식으로인해 우선순위가 바뀌는 일 방지
위험한 코드 1
- 매크로 영역을 괄호로 둘러 싸지 않아 side effect 발생
하지만 8이 나온다.
매크로 괄호 기본 형태
1 해결방법
- 매크로 괄호는 최소한 이정도는 써야함
이제 16이 나온다.
typedef 사용하기
PRE-03. 타입 인코딩 시 매크로 정의 대신 타입 정의를 사용해라.
- 타입 정의는 scope 규칙이 적용되는 반면 매로 정의는 적용되지 않는다.
위험한 코드
- 아래의 코드에서 name은 포인터로 선언되었지만 tel은 포인터로 선언되어 있지 않다.
해결 방법
- typedef 사용할 것
토큰/문자열 변환은 매크로
PRE-05. 토큰들을 연결하거나 문자열 변환을 할 때 매크로 치환을 고려
매크로 연산자
#
: 연산자 다음에 있는 토큰을 문자열 화
##
: 매크로가 치환되는 과정에서 두 개의 토큰을 하나로 병합(concatencation)
#
위험한 코드
- 아래 코드는 줄 번호가 의도한대로 출력되지 않는다.
해결 방법
- 매크로 인자를 치환한 다음에 문자열로 만들려면 두 단계의 매크로를 사용해야한다.
include guard
PRE-06. 헤더 파일에 항상 include guard
복수 구문 매크로는 do-while
PRE-10. 복수 구문 매크로를 do-while
루프로 감싸기
- 여러 실행문을 그룹으로 만들어 연속적으로 실행하는 경우, 구문상 루프로 묶어야만 나중에 매크로가
if
처럼 한 개의 실행문이나 중괄호로 묶인 실행 단위를 처리하는 부분에서 사용될 때 안전하게 동작한다.
위험한 코드 1
- 다음은 복수 구문으로 정의된 함수형 매크로를 사용할 경우, 의도하지 않은 결과를 초래한다.
1 해결방법
- 매크로 구문을 do-while로 감싼다.
매크로에 ++, 메모리 변수 접근, 함수 호출 X
PRE-31. 절대 불안전한 매크로를 할당, 증가, 감소, 메모리 변수 접근, 함수 호출과 함께 사용 마라
- 함수형 매크로에서 사용된 argument에 대해 증가 또는 감소 등의 연산은 side effect 발생
위험한 코드 1
- 의도치 않은 결과 초래
- 결과: 80....
1-1. 해결방법
- 매크로문에 증감문 XX
- 결과: 27!
1-2. 해결방법
- 함수이름에 __UNSAFE 붙여 프로그래머에게 경각심!!
1-3. 해결방법
- inline 함수