1. 입력데이터 검증 및 표현
Python 시큐어코딩 가이드
프로그램 입력값에 대한 검증 누락 또는 부적절한 검증, 데이터의 잘못된 형식 지정, 일관되지 않은 언어셋 사용 등으로 인해 발생하는 보안 약점으로 SQL 삽입, XSS 등의 공격을 유발할 수 있다.
1) SQL 삽입
입력값에 쿼리 조작 문자열을 확인하지 않고 쿼리문 생성 및 실행에 사용하는 경우 발생
쿼리가 조작되어 실행되기 때문에 권한 밖의 데이터에 접근할 수 있고, 쿼리 실행을 통해서 제공되는 기능을 우회해서 사용해 해당하는 시스템의 제어권을 탈취할 수 있다.
(1) 안전한 코딩 기법
DB API 사용 시 인자(arguments)를 통해 외부 입력값을 바인딩해서 사용하면 SQL 삽입 공격으로부터 안전하게 보호할 수 있다.
구조를 정의하고 정의된 값을 전달해서 실행하는데, 이때 값을 구조에 의해 반영하는 것은 해당하는 애플리케이션에서 담당해야 한다.
파이썬에서 많이 사용되는 ORM 프레임워크는 쿼리를 직접 만들지 않고, 프레임워크가 알아서 만들어 주기 때문에 SQL 삽입 공격으로부터 안전하다.
쿼리를 만들 때 문자열 결합 형식으로 만들면 안 되고, 입력값에 대한 검증이 있어야 한다.
이를 안전하게 만들기 위해서는 쿼리의 구조를 정의하고 쿼리 실행에 필요한 값을 execute 메서드에 매개변수로 사용해야 한다.
2) 코드 삽입
공격자가 소프트웨어의 의도된 동작을 변경하도록 임의 코드를 삽입해 소프트웨어가 비정상적으로 동작하도록 하는 보안 약점
코드 삽입은 해당하는 코드를 해석해서 실행하는 주는 코드를 말한다. 소스 코드의 코드를 해석해서 실행 해주는 ecal(), exec() 등이 있다.
print(eval('1 + 1'))
위 코드가 있을 때, '1 + 1'은 단순한 문자열이 아니고, python 코드로 실행한다. '1+1'을 해석해서 2라는 값을 출력하게 된다. '1+1'에 파이썬 코드(외부에서 들어오는 값)가 들어가면 해당하는 서버에서 파이썬 코드가 실행되어 결과가 노출되게 된다.
(1) 안전한 코딩기법
동적 코드를 실행할 수 있는 함수를 사용하지 않는 것이 제일 좋은 방법이다. 필요시, 실행할 수 있는 동적 코드를 입력값으로 받지 않도록 외부 입력값에 대해 제한, 화이트리스트 기반 검증을 수행해야 한다.
3) 경로 조작 및 자원 삽입
외부 입력값이 자원 식별자로 사용되는 경우
외부 입력값을 검증, 제한하지 않고 사용하면, 권한 밖 자원에 대해 접근할 수 있고 자원을 선점하거나 충돌시켜 정상적인 서비스를 방해한다.
(1) 안전한 코딩기법
외부로부터 받은 입력값을 자원의 식별자로 사용하는 경우 적절한 검증을 거치도록 하거나 사전에 정의된 리스트에 포함된 식별자만 사용하도록 제한해야 한다. 특히 외부 입력이 파일명인 경우 필터를 적용해 경로 조작 문자열(/, \, .. 등)을 제거해야 한다.
외부 입력값에서 경로 조작 문자열을 제거하기 위해서는 replace, re.sub, filter 함수를 사용해 특수문자 필터링할 수 있다.
4) 크로스사이트 스크립트(XSS)
의도하지 않은 스크립트 코드 실행
크로스사이트 스크립트 공격은 웹사이트에 악성 코드를 삽입하는 공격 방법이다. XSS 공격은 일반적으로 애플리케이션 호스트 자체보다 사용자를 목표로 삼는다.
(1) 유형
- Reflective XSS (Non-persistent XSS)
- 입력값이 다음 화면 출력에 사용하는 경우
- 입력값에 스크립트 코드 포함 여부를 확인하지 않고 그대로 출력에 사용하면 입력값으로 전달된 스크립트 코드가 사용자 브라우저에서 실행
- Stored XSS (Persistent XSS)
- 공격자가 입력한 스크립트 코드가 취약한 서버에 저장
- 사용자가 조회 시 저장된 스크립트 코드가 그대로 사용자 브라우저로 전달되어 실행
- DOM XSS (Client-Side XSS)
- 개발자가 작성한 스크립트 코드의 취약점을 이용
(2) 안전한 코딩기법
외부 입력값 또는 출력값에 스크립트가 삽입되지 못하도록 문자열 치환 함수를 사용하여 치환하거나, html 라이브러리의 escape()를 사용해 문자열을 변환해야 한다. HTML 태그를 허용해야 하는 게시판에서는 허용할 HTML 태그들을 화이트 리스트로 만들어 해당 태그만 지원한다.
파이썬 프레임워크인 Django, Flask 등을 사용하는 경우 악의적인 스크립트가 삽입되지 못하도록 프레임워크 자체에서 공격에 사용될 수 있는 문자를 HTML 특수문자로 치환하여 페이지를 생성하므로 XSS 공격으로부터 안전하다.
Django 에서 mark_safe를 사용하면 Django 에서 HTML 특수문자로 치환하는 기능을 제거하고 사용할 수 있다. 그래서 mark_safe를 사용할 때는 주의가 필요하고 신뢰할 수 없는 데이터에 대해서는 사용하지 않는 것이 안전하다.
autoescape off도 비슷한 기능을 하는 데 사용할 경우 주의가 필요하고 신뢰할 수 없는 값에 대해서는 on으로 설정하는 것이 안전하다. autoescape의 기본값은 on이다.
5) 운영체제 명령어 삽입
외부 입력값이 운영체제 명령어 실행 또는 명령어 일부로 사용되는 경우
OS Command Injection 때 공부한 내용이다.
적절한 검증, 제한을 거치지 않은 사용자 입력값이 운영체제 명령어에 사용되는 경우 시스템 동작 및 운영에 악영향을 미칠 수 있다.
(1) 안전한 코딩기법
외부 입력값에 시스템 명령어를 포함하는 경우 |, ;, &, :, >, <, \ 과같이 멀티 라인 및 리다이렉트 문자 등을 필터링하고 명령을 수행할 파일명과 옵션을 제한해 인자로만 사용될 수 있도록 해야 한다.
os.system은 외부로부터 받은 입력값을 통해 프로그램을 실행하며, 외부에서 전달되는 인자값은 명령어의 생성에 사용된다. 이때 실행할 프로그램을 제한하지 않고 사용하면 공격자는 원하는 모든 프로그램을 실행할 수 있다.
외부에서 입력받은 각이 명령어 인자로 사용되지 않고 명령어 그 자체로 사용될 경우에는 사전에 화이트리스트 배열을 정의한 후 적절한 파라미터를 선택하도록 해야 한다.
6) 위험한 형식 파일 업로드
업로드되는 파일의 크기와 개수를 제한하지 않고 외부에서 접근할 수 있는 경로에 저장했을 때 발생
서버에서 실행할 수 있는 스크립트 파일을 업로드하고, 그 파일을 직접 호출해서 실행한다.
파일에 새로운 보안 약점을 넣어 둔다면, 파일이 실행되면서 서버에 새로운 보안 약점이 생기게 된다.
대표적으로 운영체제 명령어 삽입 공격을 쉽게 할 수 있도록 하는 웹쉘이 있다.
(1) 안전한 코딩기법
파일 업로드 공격을 방지하기 위해서 특정 파일 유형만 허용하도록 화이트리스트 방식으로 파일 유형을 제한해야 한다.
파일 크기 및 파일 개수를 제한하지 않으면 시스템 자원 고갈이 되어 서비스 거부가 발생하는데, 이 서비스 거부 공격이 발생하지 않도록 제한해야 한다.
업로드 파일을 웹 루트 폴더 외부에 저장해 공격자가 URL을 통해 파일을 실행할 수 없도록 해야 하며, 가능하면 업로드된 파일의 이름은 공격자가 추측할 수 없는 무작위한 이름으로 변경 후 저장하는 것이 안전하다.
7) 신뢰되지 않은 URL 주소로 자동 접속 연결
Redirection
리다이렉션 기능이 존재하는 경우, 외부 입력값을 검증, 제한 없이 리다이렉션의 주소로 사용되는 경우 발생한다.
요청한 주소에 리다이렉션 주소로 사용되는 경우가 많은데, 리다이렉션 주소를 검증, 제한하지 않는 경우 공격자가 요청한 해당 주소 사이트와 동일하게 만들어 놓은 사이트로 이동하게 된다. 공격자는 리다이렉션이 들어 있는 주소를 클릭할 수 있게 링크로 만들어 이메일, SMS, 카톡 등을 통해서 불특정 다수에게 전달해 피싱 공격에 악용한다.
(1) 리다이렉트 방법
- HTTP 리다이렉션
- 300번대 상태코드와 Location 응답헤더를 전달해서 클라이언트(브라우저)가 다시 요청
- HTML 리다이렉션
- <head><meta http-equiv="refresh" content="0;URL='리다이렉션할 주소'" /></head>
- JavaScript 리다이렉션
- <script> window.location = "리다이렉션할 주소"; </script>
- 적용 우선순위
- HTTP 리다이렉션
- HTML 리다이렉션
- JavaScript 리다이렉션
(2) 안전한 코딩기법
리다이렉션을 허용하는 모든 URL을 서버 측 화이트리스트로 관리하고 사용자 입력값을 리다이렉션 할 URL이 존재하는지 검증해야 한다.
만약 리다이렉션 URL의 인자 값으로 사용되어야만 하는 경우 모든 리다이렉션에서 프로토콜과 host 정보가 들어가지 않는 상대 URL(relative)을 사용 및 검증해야 한다. 절대 URL(absoute URL)을 사용할 경우 리다이렉션을 실행하기 전에 사용자 입력 URL이 서비스하고 있는 URL로 시작하는지를 확인해야 한다.
8) 부적절한 XML 외부 개체 참조
서버에서 XML 외부 엔티티를 처리할 수 있도록 설정된 경우에 발생
XML 문서에는 DTD(Document Type Definition)를 포함할 수 있으며 DTD는 XML 엔티티(entity)를 정의한다.
취약한 XML parser가 외부값을 참조하는 XML을 처리할 때 공격자가 삽입한 공격 구문이 동작하여 서버 파일 접근, 불필요한 자원 사용, 인증 우회, 정보 노출 등이 발생할 수 있다.
파이썬에서 기본 XML 파서가 제공되는데, 이 파서는 유효성 검사와 같은 고급 기능은 지원하지 않는다. 그렇기 때문에 안정성이 검증된 다른 라이브러리를 사용하는 것이 안전하다.
(1) 안전한 코딩기법
로컬 정적 DTD를 사용하도록 설정하고 외부에서 전송된 XML 문서에 포함된 DTD를 완전하게 비활성화해야 한다. 비활성화를 할 수 없는 경우에는 외부 엔티티 및 외부 문서 유형 선언을 각 파서에 맞는 고유한 방식으로 비활성화한다.
외부 라이브러리를 사용할 경우 기본적으로 외부 엔티티에 대한 구문 분석 기능을 제공하는지 확인하고 제공이 되는 경우 해당 기능을 비활성화할 방법을 확인해 외부 엔티티 구문 분석 기능을 비활성화한다.
9) XML 삽입
외부 입력값에 XPath 구문 또는 XQuery 구문을 조작할 수 있는 문자열 포함 여부를 확인하지 않고 XML 문서를 해석해서 실행하는 데 사용하는 경우에 발생
공격자가 쿼리문의 구조를 임의로 변경하고 쿼리를 실행해 허가되지 않은 데이터를 열람하거나 인증 절차를 우회할 수 있는 보안 약점이다.
(1) 안전한 코딩기법
XQuery 또는 XPath 쿼리에 사용되는 외부 입력값에 대하여 특수문자 및 쿼리 예약어를 필터링하고 인자화된 쿼리문을 지원하는 XQuery를 사용해야 한다.
10) LDAP 삽입
LDAP 서버에 조회를 요청할 때 입력값이 사용되는 것
외부 입력값을 적절할 처리 없이 LDAP 쿼리문이나 결과의 일부로 사용하는 경우 LDAP 쿼리문이 실행될 때 공격자는 LDAP 쿼리문의 내용을 마음대로 변경할 수 있다.
(1) LDPA 서버
LDAP은 사용자가 조직, 구성원 등에 대한 데이터를 찾는 데 도움이 되는 프로토콜이다.
LDAP 서버는 디렉터리 서비스로 우리가 가지고 있는 리소스들을 계층 구조로 관리해 주는 서버다.
(2) 안전한 코딩기법
- 올바른 인코딩 함수를 사용해 모든 변수 이스케이프 처리
- 화이트리스트 방식의 입력값 유효성 검사
- 사용자 패스워드와 같은 민감한 정보가 포함된 필드 인덱싱
- LDAP 바인딩 계정에 할당된 권한 최소화
사용자의 입력을 그대로 LDAP 질의문에 사용하면 권한 상승 등의 공격에 노출될 수 있다. 사용자의 입력 중 LDAP 질의문에 사용될 변수를 이스케이프 하여 질의문 실행 시 공격에 노출되는 것을 예방해야 한다.
11) 크로스사이트 요청 위조(CSRF)
공격자가 심어 놓은 자동화된 요청이 서버에서 희생자의 권한으로 실행되는 것
웹 응용프로그램이 사용자로부터 받은 요청이 해당 사용자가 의도한 대로 작성되고 전송된 것인지 확인하지 않는 경우 발생한다. 공격자는 사용자가 인증한 세션이 특정 동작을 수행해도 계속 유지되어 정상적인 요청과 비정상적인 요청을 구분하지 못하는 점을 악용한다.
정상적인 페이지로부터의 요청인지, 공격자가 작성한 자동화된 요청인지를 확인하지 않고 요청을 처리하고, 주요 기능임에도 불구하고 인증 여부 및 요청 처리에 필요한 값 전달 여부만 확인하고 사용자가 요청한 것인지 자동화된 코드가 요청한 것인지 확인하지 않고 요청을 처리하는 문제가 있다.
(1) 안전한 코딩기법
해당 요청이 정상적인 사용자의 정상적인 절차에 의한 요청인지를 구분하기 위해 세션별로 CSRF 토큰을 생성하여 세션에 저장하고 사용자가 작업 페이지를 요청할 때마다 hidden 값으로 클라이언트에게 토큰을 전달한 뒤, 해당 클라이언트의 데이터 처리 요청 시 전달되는 CSRF 토큰값을 체크하여 요청의 유효성을 검사하도록 한다.
- 요청 절차 검증
- 텍스트 기반의 토큰을 이용해 요청 절차 검증
- 토큰 전달 과정에 사용자가 관여하지 않고 공격자가 토큰이 있는 페이지를 먼저 호출해 토큰을 추출한 후 다음 페이지를 호출하는 방식으로 공격이 가능
- CAPTCHA
- reCAPTCHA
- 텍스트 기반의 토큰을 이용해 요청 절차 검증
- 주요 기능에 요청 주체를 확인하고 재인증, 재인가 후 처리
12) 서버사이드 요청 위조
서버 내부에서 다른 서버로의 요청 결과를 사용하는 경우, 서버 내부 요청에서 사용할 서버 주소를 외부에서 받아오는 경우, 그 주소를 검증, 제한하지 않으면 의도하지 않은 서버로 전달되어 의도하지 않은 결과 반환
CSRF와 서버사이드 요청 위조는 헷갈릴 수 있다.
CSRF는 클라이언트에서 서버로 요청하면 서버는 처리해서 반환한다. 이때 요청 절차와 검증을 하지 않고 반환하고, 요청은 사람이 하는 것이 아니고 어떤 스크립트와 같은 것을 이용해 자동으로 요청이 발생한다.
서버사이드 요청 위조는 서버 안의 로직에 다른 쪽으로 요청해서 요청의 결과를 받아와서 그 결과를 클라이언트에게 전달하는 것이다. 클라이언트가 서버에 페이지를 요청했는데, 이 서버가 페이지 처리를 다른 서버로 요청해서 결과를 받아와 그 결과와 조합해서 보내는 것이다.
이때 클라이언트에서 전달된 어떠한 값을 이용해서 다른 서버로 요청을 보내는 것인데, 클라이언트에서 전달된 어떠한 값이 변경되면 원래 가야 하는 서버가 아닌 또 다른 서버로 이동해 처리 후 결과를 반환할 수 있게 된다.
(1) 안전한 코딩기법
사용자의 입력값을 화이트리스트 방식으로 필터링한다. 부득이하게 사용자가 지정하는 무작위의 URL 받아들여야 하는 경우라면 내부 URL을 블랙리스트로 지정하여 필터링한다. 동일한 내부 네트워크에 있더라도 기기 인증, 접근권한을 확인하여 요청이 이루어질 수 있도록 한다.
13) HTTP 응답 분할
외부 입력값에 개행문자 포함 여부를 확인하지 않고 응답 헤더의 각으로 사용되는 경우 응답이 분리되어 전달되는 현상
새롭게 추가된 응답 본문에 악성 코드를 삽입하여 전달하는 것이 가능해진다.
외부 입력값에 개행문자가 존재하면 HTTP 응답이 2개 이상으로 분리될 수 있다. 이 경우 공격자는 개행문자를 이용해 첫 번째 응답을 종료시키고 두 번째 응답에 악의적인 코드를 주입해 XSS 및 캐시 훼손 공격 등을 할 수 있다.
요청 헤더가 시작하고 개행문자가 두 번 연속해서 나오면 요청 헤더의 끝을 알 수 있다. 응답 헤더의 끝도 개행문자가 두 번 연속으로 나오는 것으로 끝으로 한다.
(1) 안전한 코딩기법
외부 입력값이 헤더, 쿠키, 로그 등에 사용될 경우에는 항상 개행문자를 검증하고 가능하다면 헤더에 사용되는 예약어 등을 화이트리스트로 제한해야 한다.
응답 분할을 예방하기 위해 \r, \n과 같은 문자에 대해 치환 또는 예외 처리를 적용해 응답 분할이 발생하지 않도록 해야 한다.
14) 정수형 오버플로우
정수형 크기가 고정된 상태에서 변수가 저장할 수 있는 범위를 넘어선 값을 저장할 때 발생
정수를 이진수로 처리할 때 제일 앞자리는 부호비트로 가진다. 이때 양수가 증가하는데, 부호비트를 제외한 나머지가 가득 차면 가장 큰 정수가 돼서 더 이상 증가할 곳이 없음에도 불구하고 양의 정수가 더 증가하면 부호비트를 침범해서 부호비트가 변경되고 사용하고 있는 수는 음수로 변해 가장 작은 정수가 되어 버리는 현상이 나타나는데 이를 정수형 오버플로우라고 한다.
반대로 음수에서 정수가 되면 언더플로우가 됐다고 한다.
(1) 안전한 코딩기법
기본 파이썬 자료형을 사용하지 않고 패키지에서 제공하는 데이터 타입을 사용할 경우 해당 패키지에서 제공하는 데이터 타입의 표현 방식과 최대 크기를 반드시 확인해야 한다.
변수에 값 할당 전에 반드시 변수의 최소 및 최댓값을 확인하고 범위를 넘어서는 값을 할당하지 않는지 테스트해야 한다.
15) 보안 기능 결정에 사용되는 부적절한 입력값
안전한 처리를 위해서는 외부 사용자 입력을 최소화하고, 믿을 수 있는 시스템 내부의 값을 사용하도록 설계하고 구현해야 함
외부 입력값에 대해 신뢰하게 되면, 공격자는 입력값을 조작해 보호 메커니즘을 우회할 수 있게 된다.
인증이나 인가와 같은 보안 결정이 쿠키, 환경변수, 히든 필드 등에 기반을 두어 수행되는 경우 공격자는 입력값을 조작해 보안을 우회할 수 있다. 따라서 충분한 암호화, 무결성 체크를 수행하고 이와 같은 메커니즘이 없는 경우엔 외부 사용자에 의한 입력값을 신뢰해서는 안 된다.
(1) 안전한 코딩기법
상태 정보나 민감한 데이터 특히 사용자 세션 정보와 같은 중요 정보는 서버에 저장하고 보안 확인 절차도 서버에서 실행한다.
16) 포맷 스트링 삽입
포맷 문자열을 지원하는 함수를 사용할 때, 외부 입력값에 포맷 문자열 포함 여부를 확인하지 않고 포맷 문자열 생성에 사용하는 경우 발생
공격자는 포맷 문자열을 이용해 취약한 프로세스를 공격하거나 메모리 내용을 읽고 쓸 수 있다. 이를 통해 취약한 프로세스의 권한을 취득해 임의의 코드를 실행할 수 있다.
공격자는 포맷 문자열을 이용해 내부 정보를 문자열로 만들 수 있고, 이를 그대로 사용하는 경우 중요 정보 유출로 이어질 수 있다.
(1) 안전한 코딩기법
포맷 문자열을 처리하는 함수 사용 시 사용자 입력값을 직접적으로 포맷 문자열로 사용하거나 포맷 문자열 생성에 포함하지 않아야 한다. 사용자로부터 입력받은 데이터를 포맷 문자열로 사용하고자 하는 경우에는 서식 지정자를 포함하지 않거나 파이썬의 내장함수 또는 내장 변수 등이 포함되지 않도록 해야 한다.
댓글