4장. 모든 입력을 확인해라

 

Wisdom will save you from the ways of wicked men, from men whose words are perverse...

 Proverbs 2:12 (NIV)
차례
4.1. 명령 행
4.2. 환경 변수
4.2.1. 몇몇 환경 변수는 위험하다
4.2.2. 환경 변수 저장 포맷은 위험하다
4.2.3. 해결방안 - 추출 및 제거
4.3. 파일 기술자
4.4. 파일 컨텐츠
4.5. 웹 기반 애플리케이션 입력 (특히 CGI 스크립트)
4.6. 다른 입력
4.7. 인간 언어 (로케일) 선택
4.7.1. 로케일 선택 방법
4.7.2. 로케일 지원 메카니즘
4.7.3. 합법적인 값
4.7.4. 최종 결과
4.8. 문자 인코딩
4.8.1. 문자 인코딩 소개
4.8.2. UTF-8 소개
4.8.3. UTF-8 보안 쟁점
4.8.4. UTF-8 합법적인 값
4.8.5. UTF-8 관련 쟁점
4.9. 입력에서 교차 사이트의 악의있는 컨텐트를 예방해라
4.10. 다시 보내질 수도 있는 HTML/URIs 를 필터링해라
4.10.1. 몇몇 HTML 데이타를 제거 및 금지해라
4.10.2. HTML 데이타 인코딩
4.10.3. HTML 데이타 확인
4.10.4. 하이퍼텍스트 링크 (URIs/URLs) 확인
4.10.5. 다른 HTML 태그
4.10.6. 관련 쟁점
4.11. 비질의를 수행하는 HTTP GET 을 금지해라
4.12. 합당한 입력 시간 및 로드 레벨을 제한해라

어떤 입력은 신뢰할 수 없는 사용자로부터 올 수 있는데 이런 입력들은 사용하기 전에 그 정당성을 입증하거나 필터링되어야 한다. 무엇이 합법적인 것인가를 결정해서 그 정의와 일치하는 않는 모든 것을 거절해야 한다. 무엇이 비합법적인 것인가를 식별해서 그러한 경우를 거절하는 코드를 작성하는 것과 같은 반대의 경우는 하지마라. 비합법적인 입력의 중요한 실례를 다루는 것을 잊을 수 있기 때문이다.

그렇지만 비합법적인 값을 식별해야 하는 좋은 이유가 있는데 이는 반드시 확인 (validation) 코드를 철두철미하게 작성하기 위한 일련의 테스트 (보통 머리속에서 실행되는) 와 같다. 저자는 입력 필터를 설정할 때 필터링되지 않을 수 있는 비합법적인 값이 있는지 보기 위해 마음속으로 필터를 공격한다. 다음은 입력에 따라 입력 필터가 예방할 필요가 있는 공통된 비합법적인 값들의 예이다: 빈 문자열, ".", "..", "../", "/" 또는 "." 로 시작하는 모든 것, 안에 "/" 또는 "&" 가 있는 모든 것, 모든 제어 문자 (특히 NIL 과 개행) 와/또는 "high bit" 이 설정되어 있는 모든 문자 (특히 십진수 254 와 255 값). 다시 한번 작성한 코드는 "bad" 값에 대해 검사되지 않아야 한다: 반드시 패턴이 입력 값을 합법적인 값으로 엄격히 제한하도록 이를 마음속으로 검사해야 한다. 패턴이 충분히 엄밀하지 않다면 다른 문제가 있는 지를 살펴 보기 위해 패턴을 주의깊게 재조사해야 한다.

최대 문자 길이 (적절하다면 최소 길이) 를 제한하고 그러한 길이가 초과될 때 반드시 제어가 되도록 해라 (버퍼 오버플로우에 대한 더욱 많은 정보는 5장 을 보라).

다음은 신뢰되지 않은 사용자로부터 온 것들 사용하기 전에 확인해야 하는 약간의 공통적인 데이타 타입과 입력들이다:

위에 언급한 사항을 고려하지 않는다면 합법적 문자 패턴에 프로그램 내부 또는 결과로써 생기는 출력에 대해 특별한 의미를 갖는 문자들 또는 일련의 문자들을 포함하지 않아야 한다:

이러한 테스트는 추후 수정을 위해 타당성 테스트를 쉽게 살펴볼 수 있도록 한 곳에 집중되어 있어야 한다.

타당성 테스트가 실제로 정확함을 확인해라; 이는 다른 프로그램이 사용할 입력 (파일 이름, 이메일 주소 또는 URL 등) 을 검사할 때 특히 문제가 된다. 대개 이러한 테스트는 검사 프로그램과 실제 데이타를 사용하는 프로그램이 다른 가정을 하는 경우 미묘한 에러를 갖는데 소위 "대리 (deputy) 문제" 를 야기한다. 관련된 표준이 있다면 이를 살펴보고 또한 프로그램이 각자가 알아야 필요가 있는 확장을 가지고 있는지 살펴보기 위해 검색해라.

사용자 입력을 해석할 때 일시적으로 모든 권한을 없애거나 더 나아가서 별개의 프로세스를 생성하는 것 (파서의 권한을 영구적으로 없애고 다른 프로세스가 파서 요청에 대해 보안 검사를 수행한다) 은 좋은 생각이다. 이는 파싱 태스크가 복잡하거나 (lex 또는 yacc 와 유사한 도구를 사용하는 경우) 또는 프로그래밍 언어 (예, C 와 C++) 가 버퍼 오버플로우에 대해 보호하지 않는다면 특히 들어맞는다. 권한 최소화에 대해 더욱 자세한 정보를 얻기 위해서는 6.3절 을 보라.

보안 결정 (예, 사용자에게 로그인 허용) 에 데이타를 사용할 때 반드시 신뢰할 수 있는 채널을 사용해라. 예를 들어 공개 인터넷에서 사용자를 인증하는 유일한 방법으로 머신 IP 주소 또는 포트 넘버를 사용하지 마라. 대부분의 환경에서 이 정보는 어쩌면 악의있는 사용자에 의해 설정될 수 있다. 더욱 자세한 정보는 6.9절 를 보라.

다음 하부 절은 다양한 종류의 입력을 논의한다; 입력은 환경 변수, umask 값 등과 같은 프로세스 상태를 포함함을 주목해라. 모든 입력이 신뢰할 수 없는 사용자에 의해 제어될 수는 없는데 따라서 이러한 사용자가 제어할 수 있는 그러한 입력에 대해서만 주의를 기울이면 된다.