방어 프로그래밍

Defensive programming

방어 프로그래밍은 예측하지 못한 상황에서 소프트웨어의 지속적인 기능을 보장하기 위한 방어 설계의 한 형태다. 방어적 프로그래밍 관행높은 가용성, 안전 또는 보안이 필요한 경우에 종종 사용된다.

방어 프로그래밍은 소프트웨어와 소스 코드를 개선하기 위한 접근법이다.

  • 일반 품질 – 소프트웨어 버그 및 문제 수 감소
  • 소스 코드를 이해할 수 있도록 설정 – 소스 코드를 읽을 수 있고 이해할 수 있어야 코드 감사에서 승인된다.
  • 예상치 못한 입력이나 사용자 조치에도 불구하고 소프트웨어가 예측 가능한 방식으로 작동하도록 하는 것.

그러나 지나치게 방어적인 프로그래밍은 결코 발생할 수 없는 오류에 대비하여 런타임과 유지보수 비용을 발생시킬 수 있다. 또한 코드 트랩이 너무 많은 예외를 방지하여 잠재적으로 눈에 띄지 않고 부정확한 결과를 초래할 위험도 있다.

보안 프로그래밍

보안 프로그래밍은 컴퓨터 보안과 관련된 방어 프로그래밍의 하위 집합이다. 보안이 문제지, 반드시 안전이나 가용성은 아니다(소프트웨어가 특정한 방법으로 고장나도록 허용될 수도 있다). 모든 종류의 방어 프로그래밍과 마찬가지로 버그를 피하는 것이 일차적인 목표다. 그러나 그 동기는 정상적인 작동에서 실패할 가능성을 줄이는 것만큼(안전성이 염려되는 것처럼)이 아니라 공격 표면을 줄이는 것이다. 프로그래머는 소프트웨어가 버그를 노출하는 데 적극적으로 악용될 수 있으며 버그가 개입한다고 가정해야 한다.ld는 악의적으로 이용당한다.

인트로 위험_위험(마를 뜨다 *입력하다) {   마를 뜨다 발을 동동 구르다[1000];       // ...      층층적인(발을 동동 구르다, 입력하다);  // 입력 복사.      // ... } 

이 함수는 입력이 1000자 이상일 때 정의되지 않은 동작을 발생시킨다. 어떤 초보 프로그래머들은 어떤 사용자도 그렇게 긴 입력에 들어가지 않을 것이라고 가정했을 때 이것이 문제라고 느끼지 않을 수 있다. 이 특정 버그는 버퍼 오버플로우 공격을 가능하게 하는 취약성을 보여준다. 이 예에 대한 해결책은 다음과 같다.

인트로 secure_secure(마를 뜨다 *입력하다) {   마를 뜨다 발을 동동 구르다[1000+1];  // null 문자를 위해 하나 더 추가.    // ...    // 목적지 길이를 초과하지 않고 입력을 복사한다.   간질간질하다(발을 동동 구르다, 입력하다, 의 크기(발을 동동 구르다));    // strlen(입력) >= size of(str)이면 strncpy가 종료되지 않는다.     // 버퍼의 마지막 문자를 항상 NUL로 설정함으로써 이에 대응한다.   // 효과적으로 문자열을 최대 길이까지 자른다.   // strlen(입력)이 있는 경우 프로그램을 명시적으로 중단하기로 결정할 수도 있다.    // 너무 길다.   발을 동동 구르다[의 크기(발을 동동 구르다) - 1] = '\0';    // ... } 

공격형 프로그래밍

공격형 프로그래밍은 방어형 프로그래밍의 범주로, 특정 오류를 방어적으로 처리해서는 안 된다는 강조가 추가된다. 이 실무에서는 프로그램 통제권 밖의 오류(사용자 입력 등)만 처리하고, 프로그램 방어선 내의 데이터뿐만 아니라 소프트웨어 자체는 이 방법론에서 신뢰할 수 있어야 한다.

내부 데이터 유효성 신뢰

지나치게 방어적인 프로그래밍
경시하다 마를 뜨다* 신호등_콜로나메(열거하다 traffic_light_color c) {     바꾸다 (c) {         케이스 TRACKLIGHED:    돌아오다 "빨간색";         케이스 신호등_노란색: 돌아오다 "노란색";         케이스 교통 조명_녹색:  돌아오다 "녹색";     }     돌아오다 "검은색"; // 죽은 교통신호로 취급한다.     // 경고: 이 마지막 '반환' 문장은 최적화에 의해 삭제될 것이다.     // 'traffic_light_color'의 가능한 모든 값이 목록에 있는 경우 컴파일러     // 이전 '스위치' 문... } 
공격형 프로그래밍
경시하다 마를 뜨다* 신호등_콜로나메(열거하다 traffic_light_color c) {     바꾸다 (c) {         케이스 TRACKLIGHED:    돌아오다 "빨간색";         케이스 신호등_노란색: 돌아오다 "노란색";         케이스 교통 조명_녹색:  돌아오다 "녹색";     }     주장하다(0); // 이 섹션에 연결할 수 없다고 주장하십시오.     // 경고: 이 'assert' 함수 호출은 최적화에 의해 삭제됨     // 'traffic_light_color'의 가능한 모든 값이 목록에 있는 경우 컴파일러     // 이전 '스위치' 문... } 

신뢰할 수 있는 소프트웨어 구성 요소

지나치게 방어적인 프로그래밍
만일 (is_suffer_suffer_suffer(user_config)) {     // 전략: 새 코드가 동일하게 동작한다고 믿지 않음     old_code(user_config); } 다른 {     // 예비: 새 코드가 동일한 사례를 처리한다고 믿지 않음     만일 (new_code(user_config) != 네 알겠습니다) {         old_code(user_config);     } } 
공격형 프로그래밍
// 새 코드에 새 버그가 없을 것으로 예상 만일 (new_code(user_config) != 네 알겠습니다) {     // 적절한 주의를 끌기 위해 프로그램을 크게 보고하고 갑자기 종료     report_properties("뭔가 잘못됐어.");     퇴장하다(-1); } 

기술

다음은 몇 가지 방어 프로그래밍 기법이다.

지능형 소스 코드 재사용

기존 코드를 테스트해 작동하는 것으로 알려지면 이를 재사용하면 버그가 유입될 가능성을 줄일 수 있다.

그러나 코드를 재사용하는 것이 항상 좋은 관행은 아니다. 특히 널리 배포된 경우 기존 코드를 재사용하면 다른 방법으로 가능한 것보다 더 넓은 대상을 대상으로 하는 공격이 생성될 수 있으며 재사용된 코드의 모든 보안과 취약성을 가져올 수 있다.

기존 소스 코드 사용을 고려할 때 모듈(클래스나 기능 등의 하위 섹션)을 신속하게 검토하면 개발자가 잠재적 취약점을 제거하거나 인지하도록 하고 프로젝트에 사용하기에 적합한지 확인할 수 있다.[citation needed]

레거시 문제

이전 소스 코드, 라이브러리, API, 구성 등을 재사용하기 전에, 이전 작업이 재사용에 유효한지, 또는 레거시 문제가 발생하기 쉬운지를 고려해야 한다.

기존 문제는 오래된 설계가 오늘날의 요구사항과 함께 작동할 것으로 예상될 때, 특히 오래된 설계가 그러한 요구사항을 염두에 두고 개발되거나 시험되지 않았을 때 내재된 문제들이다.

많은 소프트웨어 제품이 이전 레거시 소스 코드와 관련된 문제를 경험했다. 예를 들어,

  • 레거시 코드는 방어적 프로그래밍 이니셔티브에 따라 설계되지 않았을 수 있으며, 따라서 새로 설계된 소스 코드보다 품질이 훨씬 낮을 수 있다.
  • 레거시 코드는 더 이상 적용되지 않는 조건에서 작성되고 테스트되었을 수 있다. 이전의 품질보증시험은 더 이상 유효성이 없을 수도 있다.
    • 예 1: 레거시 코드는 ASCII 입력용으로 설계되었을 수 있으나, 현재 입력은 UTF-8이다.
    • 예 2: 레거시 코드는 32비트 아키텍처에서 컴파일되고 테스트되었을 수 있지만, 64비트 아키텍처에서 컴파일할 경우 새로운 산술적 문제(예: 잘못된 서명 테스트, 잘못된 유형 캐스트 등)가 발생할 수 있다.
    • 예 3: 레거시 코드가 오프라인 컴퓨터를 대상으로 할 수 있지만 네트워크 연결이 추가되면 취약해진다.
  • 레거시 코드는 새로운 문제를 염두에 두고 작성된 것이 아니다. 예를 들어 1990년에 작성된 소스 코드는 대부분의 그러한 문제들이 당시에는 널리 이해되지 않았기 때문에 많은 코드 주입 취약성이 발생하기 쉽다.

기존 문제의 주목할 만한 예:

  • Paul Vixie와 David Conrad가 "BINDv9는 완전한 재작성", "안보는 설계에서 핵심 고려사항이었다"[1]로 제시한 BIND 9는 보안, 견고성, 확장성 및 새로운 프로토콜을 오래된 레거시 코드를 재작성하기 위한 핵심 관심사로 명명했다.
  • Microsoft Windows는 WMF 형식과 관련된 "Windows Metafile 취약성" 및 기타 취약성에 시달렸다. Microsoft Security Response Center는 WMF 기능을 "1990년경에 WMF 지원이 추가됨... 보안 환경에서는 그때가 달랐는데... Microsoft의 보안 이니셔티브에 따라 개발되지 않고"[2] 완전히 신뢰할 수 있었다.
  • OracleSQL 주입권한 상승에 대한 우려 사항을 해결하지 않고 작성된 이전 소스 코드와 같은 기존 문제에 대처하고 있으며, 이로 인해 많은 보안 취약점이 발생하여 수정하는 데 시간이 걸리고 불완전한 수정도 생성되었다. 이로 인해 데이비드 리치필드, 알렉산더 코른브뤼스트, 세자르 세루도 등 안보 전문가들로부터 거센 비난을 받았다.[3][4][5] 또 다른 비판은 기본 설치(구 버전에서 가져온 레거시)가 Oracle Database Security Checklist와 같은 자체 보안 권장 사항과 일치하지 않는다는 것이다. Oracle Database Security Checklist는 많은 애플리케이션이 제대로 작동하기 위해 덜 안전한 레거시 설정을 요구하기 때문에 수정하기 어렵다.

표준화

악의적인 사용자들은 잘못된 데이터의 새로운 종류의 표현을 발명할 가능성이 있다. 예를 들어 프로그램이 "/etc/passwd" 파일 액세스를 거부하려고 하면 크래커는 "/etc/./passwd"와 같은 이 파일 이름의 다른 변종을 통과할 수 있다. 정식화 라이브러리는 비캐논적 입력으로 인한 버그를 피하기 위해 채용할 수 있다.

"잠재적" 버그에 대한 낮은 내성

문제가 발생하기 쉬운 것으로 보이는 코드 구조(알려진 취약성 등과 유사)가 버그와 잠재적인 보안 결함이라고 가정한다. 기본적인 엄지의 법칙은 다음과 같다: "는 모든 종류의 보안 악용에 대해 알지 못한다. 내가 아는 사람들로부터 보호해야 하고, 그 다음엔 적극적이어야 해!"

코드 보안을 위한 기타 팁

  • 가장 흔한 문제들 중 하나는 프로그램에 대한 입력과 같은 동적 크기 데이터를 위해 고정 크기 또는 미리 할당된 구조의 점검되지 않은 사용이다(완충 오버플로 문제). 이것은 특히 C의 문자열 데이터에서 흔하다. C 라이브러리 기능: gets 입력 버퍼의 최대 크기는 인수로 전달되지 않으므로 절대 사용해서는 안 된다. C 라이브러리 기능: scanf 안전하게 사용할 수 있지만, 프로그래머가 사용하기 전에 안전한 형식의 문자열을 제거하여 선택하는데 주의를 기울이도록 요구한다.
  • 네트워크를 통해 전송되는 모든 중요 데이터를 암호화/인증 고유한 암호화 체계를 구현하려고 시도하지 말고 입증된 암호화 체계를 사용하십시오. CRC나 이와 유사한 기술로 메시지를 확인하는 것도 네트워크를 통해 전송되는 데이터의 보안을 유지하는 데 도움이 될 것이다.

데이터 보안의 3가지 규칙

 * 모든 데이터는 다른 방법으로 증명될 때까지 중요하다.  * 모든 데이터는 다른 방법으로 증명될 때까지 오염된다.  * 다른 방법으로 증명될 때까지 모든 코드가 불안정함  
    • 당신은 사용자랜드에서 어떤 코드의 보안도 증명할 수 없으며, 더 일반적으로 "클라이언트를 절대 신뢰하지 않는다"라고 알려져 있다.

데이터 보안에 관한 이 세 가지 규칙은 내부 또는 외부에서 소싱된 데이터를 처리하는 방법을 설명한다.

다른 방법으로 증명될 때까지 모든 데이터는 중요하다 - 모든 데이터가 파괴되기 전에 쓰레기로 검증되어야 함을 의미한다.

그렇지 않은 경우 입증될 때까지 모든 데이터가 오염됨 - 무결성을 확인하지 않고 나머지 런타임 환경에 노출되지 않는 방식으로 모든 데이터를 처리해야 함을 의미한다.

다른 방법으로 증명될 때까지 모든 코드는 불안정하다. - 약간의 오성어가 있을 때, 버그나 정의되지 않은 동작이 일반적인 SQL 주입 공격과 같은 공격에 프로젝트나 시스템이 노출될 수 있기 때문에 절대 코드가 안전하다고 가정하지 말라는 것을 상기시키는 좋은 일을 한다.

추가 정보

  • 데이터가 정확한지 확인해야 할 경우, 데이터가 정확한지, 잘못된 것은 아닌지 확인하십시오.
  • 계약별 설계
  • 어설션(어설션 프로그래밍이라고도 함
  • 반환 코드보다 예외 선호
    • 일반적으로 말해서, 예외가 발생한 위치나 프로그램 스택이 좋아 보이는 것을 가리키지 않는 오류 코드 값을 반환하는 대신 API 계약의 일부를 적용하고 개발자를 안내하는 예외 메시지를 던지는 것이 바람직하다. 로깅 및 예외 처리 개선을 통해 소프트웨어의 견고성과 보안성을 높일 수 있다. 개발자 스트레스를 최소화하면서

참고 항목

참조

  1. ^ "fogo archive: Paul Vixie and David Conrad on BINDv9 and Internet Security by Gerald Oskoboiny <gerald@impressive.net>". impressive.net. Retrieved 2018-10-27.
  2. ^ "Looking at the WMF issue, how did it get there?". MSRC. Archived from the original on 2006-03-24. Retrieved 2018-10-27.
  3. ^ Litchfield, David. "Bugtraq: Oracle, where are the patches???". seclists.org. Retrieved 2018-10-27.
  4. ^ Alexander, Kornbrust. "Bugtraq: RE: Oracle, where are the patches???". seclists.org. Retrieved 2018-10-27.
  5. ^ Cerrudo, Cesar. "Bugtraq: Re: [Full-disclosure] RE: Oracle, where are the patches???". seclists.org. Retrieved 2018-10-27.

외부 링크