사이버보안 이슈의 체계적인 관리를 위해, 가장 기본이 되어야 하는 것 중 하나는 개발자가 소프트웨어를 개발하는 시점부터 보안코딩 규칙을 준수하는 것입니다. 해커들이 시스템을 장악하고, 파괴할 수 있는 버퍼 오버플로우, 구조 및 유효성 문제, 채널 및 경로 오류, 인증 오류 및 사용자 인터페이스 오류 등 취약점을 사전에 방지할 수 있는 보안 코딩 관련 규칙에는 ISO/SAE 21434 표준 또는 Automotive SPICE® for Cybersecurity에서 언급하고 있는 CWE, CERT-C/C++와 MISRA C:2012 (Amendment 1)등이 있습니다. (그 외, CVE, NVD, OWASP, DISA STIG, etc.)
1. 코딩 규칙 종류
1.1 CWE
CWE(Common Weakness Enumeration)는 비영리단체 MITER Corporation에서 관리하고 있는 ‘공통 취약점 목록’ 표준으로, 하드웨어/소프트웨어의 설계, 구현 또는 아키텍처에 존재하는 결함, 오류 및 버그 등 취약점에 대한 정보를 기술하고 있습니다. (C언어 외 C++, Java 포함합니다.) 소프트웨어 개발팀에게 결함의 원인을 제거하는데 필요한 지식을 제공하고 있으며, 표준화된 용어를 제공하여 보안 전문가들과 개발자들이 소프트웨어 및 하드웨어에 존재하는 취약점에 대해 원활한 논의와 소통을 할 수 있는 공통적 언어의 역할을 하고 있습니다.
CWE에서 선정되는 항목들은 소프트웨어 설계자나 개발자들은 초기에 소스 코드상의 취약점을 제거하고, 테스터는 취약점을 검출, 분석함으로써 코드 상의 공통된 실수를 제거하여 소프트웨어 보안 성능을 발전시킬 수 있도록 지원하고 있습니다.
1.2 CERT C
CERT C 표준은 소프트웨어의 Safety, Reliability 및 Security를 개선하기 위한 코딩 가이드 라인으로 Carnegie Mellon University에서 운영하는 연구 개발 센터인 SEI(Software Engineering Institute) 협회에서 유지 관리하는 국제 코딩 표준입니다. 일반적으로 C 프로그래밍언어의 규칙에 대한 설명 및 위험평가를 제공하고 있습니다. 보안코딩 전문가들에 의해 작성되는 최신 규칙 및 권고안에 대한 가이드라인은 보안코딩 표준 홈페이지(https://zrr.kr/wBUj)에 지속적으로 업데이트되고 게시되고 있습니다. (C++, Java, Android for Perl 언어를 위한 별도 표준이 있습니다.)
CERT C 표준 검증을 통해 발견된 취약점은 비교적 사소한 결함일 수도 있습니다. 이러한 결함이 실제 소프트웨어의 성능이나 결과에 영향을 미치지 않는다 할지라도, 해커들에게는 공격 수단이 될 수 있습니다. CERT C 표준에서는 이로 인한 보안 피해가 발생하지 않도록 사소한 결함까지도 제거하도록 각 규칙별로 심각도(Severity), 침해 발생 가능성(Likelihood), 사후처리 비용(Remediation Cost)에 대해 위험평가 기준을 제공함으로써 개발자에게 보안 대응을 위한 명확한 우선순위와 레벨을 권고하고 있습니다.
1.3 MISRA C
MISRA C는 차량용 소프트웨어의 안전성, 호환성 및 신뢰성을 높이기 위해 소프트웨어 개발자가 언어의 이슈나 결함을 이해하고, 이를 사전에 방지하여 안전한 시스템을 개발하기 위한 목적으로 1998년 개발된 코딩 가이드라인으로, 현재는 자동차 산업 분야 뿐만 아니라 철도, 의료 등 다양한 산업에서 적용되고 있습니다. 첫번째 버전(MISRA-C:1998)을 업데이트하여 142개의 규칙을 갖춘 MISRA-C:2004를 발행하고, 2013년 3월 세번째 버전인 MISRA-C:2012를 발표하였습니다. (별도로 C++ 언어에 대한 가이드라인으로는 MISRA C++가 있습니다.)
MISRA C는 개발자가 불확실성을 제거하고, 개발 시 빠르게 피드백을 제공하여 시간을 절약하고, 코드 리뷰 시 문제를 완화할 수 있는 준수/비준수 코드 예제도 함께 포함하여 가이드라인을 제시하여 참고할 수 있습니다. 특히 2016년에 발행된 MISRA C:2012 (Amendment 1)에서는 소프트웨어의 보안성을 높이기 위한 몇 가지 새로운 보안 규칙들을 추가하여 143개의 규칙과 16개의 지침으로 구성되어 있습니다.
2. 보안코딩 규칙 정의
보안과 관련된 코딩 규칙은 4.1장에서 소개한 코딩 규칙들을 참고해서 전처리기, 변수 혹은 함수의 선언 및 초기화, 정수/부동소수점 및 문자열, 표현식, 배열, 메모리관리, 입출력, 환경변수, 신호, 병렬 프로그래밍 및 보안/암호화 키 사용에 대한 규칙에 대해 정의할 수 있습니다.
먼저, 컴파일러가 개발자의 의도와 다르게 해석할 수 있는 전처리기 관련 규칙으로 문자열 결합을 통한 문자 이름 생성을 금지하고(CERT-C:PRE30-C), 불안전한 매크로에 변환 인자 전달을 피해야 하며(CERT-C:PRE31-C), 매크로를 호출할 경우 전처리기 지시자를 활용한 인수를 전달하지 하면 안된다(CERT-C:PRE32-C)라는 규칙들을 참고하여 보안코딩 가이드라인을 정의할 수 있습니다.
그리고, 스택 영역에 저장되는 지역변수는 함수 반환 시 유효하지 않는 주소를 반환하는 오류가 발생할 수 있기 때문에, 의도치 않는 소프트웨어의 동작을 방지하기 위해 스택 메모리 주소의 반환 및 전달을 금지해야(CERT-C:DCL30-C, CWE-562) 하는 규칙을 아래 표의 준수코드와 같이 정의할 수 있습니다. 그 외 함수 내부와 외부 변수를 같은 이름으로 선언하는 것을 금지해야(CERT-C:DCL36-C) 하고, switch문의 default case 누락을 금지(CWE-478)하는 규칙을 추가 정의할 수 있습니다.
[스택 메모리 주소의 반환 및 전달을 금지하는 보안코딩 규칙 예시]
개발자가 C언어의 형 변환, 연산 우선순위 및 연산 오버플로우의 잘못된 이해로 예기치 않은 행동이 발생한다면, 불충분한 메모리를 할당하거나 취약점을 노출할 수 있는 정수변환 규칙에 주의(CERT-C:INT02-C)하여, 부호 없는 정수 연산 시 래핑(Wrapping)이 발생하지 않도록(CERT-C:INT30-C) 고려해야 합니다. 정수형 변환 시 값이 손실되지 않고(CERT-C:INT31-C), 부호 있는 정수 연산 시 오버플로우가 발생하지 않도록 보장해야(CERT-C:INT32-C) 하는 규칙을 정의할 수 있습니다.
[부호없는 정수 연산 시 래핑 발생하지 않도록 보장하는 뺄셈연산 보안코딩 규칙 예시]
소프트웨어가 초기화되지 않은 메모리의 변수나 배열의 메모리를 참조하고 값을 사용할 경우 개발자가 의도하지 않은 오류가 발생할 수 있기 때문에, 초기화되지 않은 메모리에 접근하거나, 읽기를 금지해야(CERT-C:EXP33-C, CWE-123) 합니다. 그리고, 소프트웨어의 비정상적인 종료 및 다양한 취약점을 유발할 수 있는 널 포인터(Null pointer)는 역참조하지 않아야(CERT-C:EXP34-C, CWE-690) 하는 규칙을 정의할 수 있습니다.
배열 혹은 포인터 메모리 버퍼 값에 접근하는 경우 잘못된 인덱스를 사용한다면 유효 범위를 초과할 수 있기 때문에, 배열이나 포인터 인덱스가 유효범위에 있음을 보장(CERT-C:ARR30-C, CWE-122)해야 합니다. 그리고 연산 오류 및 버퍼 오버플로우를 유발할 수 있는 포인터 산술연산 수행시 피연산자값이 포인터가 지시하는 객체 타입에 맞게 자동으로 변환되는 것을 고려해야 덧셈/뺄셈 연산을 금지(CERT-C:ARR39-C, CWE-468)해야 하는 규칙을 정의할 수 있습니다.
[배열이나 포인터 인덱스가 유효범위에 있음을 보장하는 보안코딩 규칙 예시]
소프트웨어 품질과 관련하여 형식지정자(%n)를 이용하여 문자열이나 특정 메모리 위치를 변경할 수 있는 사용자 입력을 배제해야(CERT-C:FIO30-c, CWE-134) 하는 데이터의 입출력에 대한 보안 규칙이 필요합니다. 그리고, 할당이 해제된 메모리에 접근 시 정의되지 않는 동작이 발생하지 않도록 하기 위해 해제된 메모리는 참조하지 않도록 보장해야(CERT-C:MEM30-C, CWE-415) 하며, 할당된 메모리는 꼭 해제해야(CERT-C:MEM31-C/MEM34-C, CWE401)한다 라는 메모리 관리 규칙을 정의할 수 있습니다.
[해제된 메모리 참조 금지하는 보안코딩 규칙 예시]
개인 암호키나 비밀키와 같은 보안 알고리즘 관련 주요 보안 정보를 암호화하지 않고 평문 형태로 제어기 외부에 노출시키거나, 주요 정보에 대한 무결성을 보장하기 위해 중요한 데이터는 암호화하여 저장하고 관리(CWE-311, 312, 313, 314)해야 하며, 반복 생성한 동일한 PRNG 시드키나 예측가능한 시드키 사용은 금지(CWE-336, 337)해야 하는 보안 규칙을 정의할 수 있습니다.
결론
CWE, CERT C 및 MISRA C는 보안 코딩 적용을 위한 효율적인 가이드라인을 제시하고 있습니다. CWE, CERT C 코딩 규칙은 사이버보안 취약점에 대한 위험평가와 우선순위 정보를 제공하고 있으며, MISRA C 규칙은 safety 측면과 security 측면까지 커버하는 규칙을 포함하고 있습니다.
자동차 사이버보안에 관한 국제표준이 채택되고, 발효되면서 사이버보안 관리를 위한 조직의 구성부터 사이버 보안 관리 체계 및 차량형식 승인까지 대비해야 할 영역은 광범위하고 다양해졌고, 자동차 제조사(OEM)뿐만 아니라 부품공급사(Tier)까지 CSMS의 전반적인 이해와 보안코딩 규칙에 대한 선정 및 적용이 기초적이고 필수적인 요구사항이 되었습니다. 이러한 시장 변화속에서 보안 코딩을 적용하기 위해 필요한 규칙을 독자들은 검토할 필요가 있기 때문에, 본 기술레터는 코딩 규칙들 중 보안코딩에 적용 가능한 여러 규칙에 대해 기술했습니다. 소프트웨어 개발자뿐만 아니라 테스트 엔지니어는 보안코딩을 적용하기 위해 먼저 여러 코딩 규칙을 검토하고, 해커의 침입을 방어할 있는 보안코딩 가이드라인을 준비할 수 있어야 할 것입니다.
앞으로 자동차 소프트웨어 시장은 더욱 확대될 것으로 예상되며, 차량내부에 구성된 네트워크 또는 외부 모듈과 연결된 통신장치가 보안 위협의 통로가 될 수 있다는 것을 고려하여, 보안 코딩에 대한 전문성을 확보해야 하며, 본 기술레터가 많은 도움이 되셨기를 바랍니다.
참고 자료
- MISRA-C:2012
- CWE Version 4.10, MITRE, 2023
- SEI CERT C Coding Standard, 2016