C++ 소프트웨어 보안 이슈들: 온라인 세미나 다시보기 & 요약 정리

소프트웨어 개발 세상은 늘 새로운 사이버 보안 위협과 마주하고 있습니다. 보안에 취약한 소프트웨어가 얼마나 위험한지, 그리고 그 결과의 얼마나 파장이 큰지 우리 모두 너무나 잘 알고 있습니다.

메리 캘리(Mary Kelly)가 진행했던 C++에서의 보안을 주제로 한 온라인 세미나를 확인해보세요. 보안 이슈가 발생하는 이유와 해소 방법들을 확인할 수 있습니다.

온라인 세미나 다시보기는 아래 링크를 클릭해서 다시 볼 수 있습니다:

C++에서의 보안 이슈들

이 글에서는 위 온라인 세미나에서 설명하는 C++에서 발생 가능한 보안 이슈들과 해소 방법들을 간단히 정리해보겠습니다.

버퍼 오버런(Buffer Overruns)

다음은 “초기 스타일” 버퍼 오버런(buffer overrun)의 일반적인 형태 예제입니다:

버퍼 오버플로우(buffer overflows) 처리는 일반적으로 다음과 같은 방식으로 해결합니다:

  • 코드에 대한 코멘트
  • 표준 C++ 라이브러리와 STL 사용
  • 경계(bounds)를 체크하는 라이브러리 활용
  • 버퍼 오버런(buffer overrun) 또는 오버플로우(overflow)의 경우, 일반적으로 퍼지 테스트(fuzz testing)를 가장 많이 사용합니다. 퍼지 테스트는 반랜덤화(semi-randomized) 값을 생성해 입력값을 테스트하는 기술로, 애플리케이션 안정성과 성능 확인에 필요합니다. 퍼즈 라이브러리 중 하나인 libFuzzer를 소개한 적도 있죠.
포맷 스트링(Format String) 문제

추천 해결 방법:

  • 포맷팅 함수에 사용자가 직접 입력한 포맷 스트링을 전달하지 않도록 설정하세요.
  • 고정된 포맷 스트링 또는 신뢰할 수 있는 소스의 포맷 스트링을 사용하세요.
  • 컴파일러 경고와 오류를 꼭 주시하세요.
  • 포맷 스트링을 사용할 때는 printf(“%s”, user_input)을 활용하세요.
  • 더 좋은 방법은, 되도록 printf 계열 함수를 사용하지 않고 스트림 처리(stream operation)를 하는 것입니다.
인티저 오버플로우 (Integer Overflows)

인티저 오버플로우는 작업 결과가 데이터 타입에 허용된 최대값보다 클 때 발생합니다. 충돌, 로직 오류, 권한 상승, 임의 코드 실행 문제를 일으킬 수 있습니다.

다음과 같은 방법으로 쉽게 해결할 수 있습니다:

  • 코드를 이해하고 학습해보세요. 수학을 조금 활용해보세요!
  • 메모리 할당과 배열 인덱스가 오버플로우 되지 않도록 모든 계산 부분을 확인해보세요.
  • 배열 오프셋(offset)과 메모리 할당 사이즈는 unsigned 변수를 사용합니다.
  • 컴파일러 경고를 절대 그냥 지나치지 마세요.
  • size_t를 사용할 때 부호 문제나 잘림 현상이 없는지 확인하세요.
배열 생성과 삭제

프로그램에 new를 사용할 때는, 리스크가 발생하지 않도록 unmanaged 개체를 생성하고, 나중에 delete를 호출해야 할 수도 있습니다. 이는 C++의 잘못된 관행으로, new나 delete를 사용하지 않도록 하세요. 더 좋은 방법은 현대식 C++로 스마트 포인트와 표준 라이브러리 컨테이너 클래스를 사용하는 것입니다. 정확하게 단 하나의 delete와 새로운 new를 매치하기 훨씬 쉽습니다.

잘못된 카피(copy) 연산자와 할당 선언

C++에서 카피(copy) 연산자는 개체에 새로운 변수가 만들어졌을 때 호출되곤 합니다. 만약 카피 연산자를 만들지 않으, 컴파일러가 카피 연산자를 생성합니다. 정말 좋은 기능이죠! 그런데 연산자를 제대로 설정하지 않으면, 오류가 반복 발생합니다.

클래스로 리소스를 제어하고자 할 때는, 비공개 카피 연산자(Private copy constructor)와 할당 연산자를 구현없이도 선언할 수 있습니다. 비공개로 선언한 클래스에 외부 클래스가 이 중 하나를 호출하려고 하면, 비공개 메소드 호출에 대한 컴파일러 오류가 발생합니다. 내부적으로 이 중 하나를 호출하려고 하는 경우에는 링크 에러가 발생합니다.

포인터 초기화

포인터 문제가 발생하지 않기 위해서는 다음의 방법을 사용해보세요. C++에서는 다음 방식을 사용합니다:

  • 선언할 때 포인터를 초기화합니다 – 정말 쉬운 방법이죠. 전에 사용했던 포인터 값을 걱정할 필요없이 더욱 쉽게 디버깅 할 수 있는 정말 좋은 방법입니다.
  • 사용 후 제로 포인터가 출력됩니다.
  • 메모리 누수를 방지하려면, 동일한 추상화 수준에서 반환하고 힙(heap)에서 메모리를 할당하면 됩니다.
  • 포인터가 범위 내에 있는 동안은 블록(block)을 힙(heap)으로 반환합니다.
  • 포인터 타입이 일치하는지 확인합니다.
STL에 대한 이해 부족

C++ 표준을 숙지하는 것이 중요합니다. C++ 언어의 발전을 위해 규범을 생성하는 정말 멋진 전문가들이 있습니다. C++11 부터 C++ 코드 보안을 둘러싼 많은 위험 요소들을 방지할 수 있는 기능들이 더욱 좋아졌습니다. C++ STL이나 C++ 표준 라이브러리에 대한 더 많은 정보는 www.cplusplus.com 이나 cppreference.com 을 꼭 참고해보시기 바랍니다.

유용한 자료들


AI api C++ c++builder c++빌더 database Delphi DelphiCon fmx IDE ideas interbase ios migration modernization news RAD스튜디오 tips UI UIUX vcl 개발 개발사례 개발팁 겟잇 교육 기술레터 기술백서 데이터 데이터베이스 델파이 마이그레이션 모바일 안드로이드 윈도우 윈도우10 인공지능 인터베이스 출시 파이썬 파이어몽키 프로그래밍 프로젝트 현대화