Qodana의 테인트 분석으로 PHP 코드를 보호하세요
이 블로그 게시물은 JetBrains 코드 품질 플랫폼인 Qodana에서 제공하는 게시물입니다. 이 플랫폼은 서버 측 정적 분석 기능을, 원하는 CI 도구로 가져올 수 있도록 설계되었습니다. Qodana는 PhpStorm 및 기타 JetBrains IDE와 동일한 코드 검사 및 프로파일을 사용하므로 IDE는 물론 CI 환경에서 일관된 코드 품질 검사를 보장합니다.
프로젝트 취약점을 악용하고 시스템 보안을 침해하는 일은 단 한 명의 사용자라도 충분히 할 수 있습니다. 개발 팀은 외부 사용자의 악성 입력(‘테인트’)에서 프로그램을 보호하기 위해 정적 분석 루틴에 테인트 검사를 추가합니다.
Qodana 팀은 올해 첫 릴리스를 통해 EAP에서 PHP 테인트 분석 기능을 선보인 바 있습니다. 이 기능은 PHP용 Qodana 2023.1 버전에서만 지원됩니다(jetbrains/qodana-php:2023.1-eap). PHP용 Qodana는 JetBrains에서 최초로 출시한 린터입니다. 따라서 새로운 보안 기능도 PHP 개발자가 가장 먼저 테스트하도록 제공하고자 합니다. 충분한 피드백이 수집되면 앞으로 다른 언어도 추가할 계획입니다.
이 게시물을 읽고 테인트 분석의 정의 및 Qodana의 테인트 분석 방식에 대해 자세히 알아보세요.
테인트 분석이란?
테인트란 외부 사용자가 수정하여 보안 위험을 초래할 수 있는 모든 값을 의미합니다. 코드에 테인트가 있으며, 검증되지 않은 외부 데이터가 프로그램 전체에 배포될 수 있는 경우 해커는 테인트 코드 조각을 실행하여 SQL 삽입, 산술 오버플로, 크로스 사이트 스크립팅, 경로 조작 등의 공격을 시도할 수 있습니다. 일반적으로 해커는 취약점을 악용하여 시스템을 파괴하고, 자격 증명 및 기타 데이터를 탈취하며 시스템 동작을 조작합니다.
테인트 예시. 화면에 GET 매개변수의 임의 데이터가 표시됩니다. 예를 들어, 악성 사용자는 취약점을 악용하여 프로그램의 레이아웃을 변경할 수 있습니다.
개발 팀은 악성 입력에 대한 추가 방어를 구축하기 위해 프로그램의 공격 노출면에서 보안 감사를 실행할 때 테인트 분석을 실행합니다.
테인트 분석은 함수 또는 메서드 본문 전체에서 신뢰할 수 없는 사용자 입력의 흐름을 평가하는 프로세스입니다. 이 분석의 핵심 목표는 예기치 않은 입력이 프로그램 실행에 부정적 영향을 미칠 수 있는지 판단하는 것입니다.
테인트 소스란 잠재적 오염 가능성이 있는 데이터에 프로그램이 액세스하는 위치입니다. 또한 오염된 입력을 허용하기 쉬운 프로그램의 핵심 부분을 테인트 싱크라고 합니다. 이 데이터는 함수 호출 또는 대입을 통해 싱크로 전달될 수 있습니다.
수동으로 테인트 분석을 실행할 경우 외부 사용자로부터 데이터를 받는 모든 위치를 파악하고 시스템에서 각 데이터 조각의 흐름을 추적해야 합니다. 오염된 데이터가 수십 개의 노드에서 사용될 수 있기 때문입니다. 다음으로, 테인트 전달을 방지하려면 아래의 두 가지 접근 방식 중 하나를 취해야 합니다.
데이터 안전성 검사. 즉, 데이터를 안전한 상태로 변환합니다. 아래 예시의 경우 테인트를 해결하기 위해 태그를 제거했습니다.
데이터 유효성 검사. 즉, 추가된 데이터의 필수 패턴 준수 여부를 확인합니다. 아래 예시의 경우 $email 변수에 대한 유효성 검사를 활성화했습니다.
즉, 테인트 분석 검사가 활성화되면 소스에서 싱크까지 사용자의 테인트 데이터를 추적하고, 데이터 안정성 또는 유효성 검사 실행 없이 데이터를 사용할 때 경고를 표시합니다.
Qodana 테인트 분석 작동 방식
PHP용 Qodana의 2023.1 EAP 버전부터 테인트 분석이 실행됩니다. 코드를 스캔하고 오염 및 잠재적 취약성을 강조 표시하는 검사, PhpStorm에서 문제를 열어 즉시 해결하는 기능, 테인트 흐름을 시각화하는 데이터 흐름 그래프가 분석 기능에 포함되어 있습니다.
예시 1. SQL 삽입
SQL 삽입의 예시와 Qodana에서 이를 탐지하는 방식을 살펴보겠습니다.
Qodana는 system_admin() 함수에서 다음과 같은 테인트를 표시합니다.
마커 1~2: $_POST 전역 배열에서 가져온 사용자 양식의 입력 데이터가 안전성 또는 유효성 검사를 거치지 않고 변수 $edit에 대입됩니다. 이러한 경우 테인트입니다.
마커 3: 테인트가 있는 $edit 변수는 적절한 안전성 검사 없이 system_save_settings 함수에 인수로 전달됩니다.
마커 4: $edit 변수의 데이터가$edit 매개변수에 있습니다.
마커 5: $edit 변수가 키($filename)와 값($status)을 갖고 foreach에 전달됩니다. 두 변수 모두 문자열과 연결된 $edit 변수의 테인트 데이터를 포함합니다. $filename 키는 테인트가 있는 SQL 문자열과 연결되고, 테인트 데이터를 db_query에 인수로 전달합니다.
마커 6: $filename 키에는 문자열과 연결된 $edit 변수의 테인트 데이터가 포함되어 있습니다.
마커 7: $filename 키는 테인트가 있는 SQL 문자열과 연결됩니다.
마커 8: 테인트가 있는 SQL 문자열은 테인트 데이터를 db_query에 인수로 전달합니다.
이제 db_query를 살펴보겠습니다.
마커 9: 테인트가 있는 문자열이 $query 매개변수에 있습니다.
마커 10: 이 매개변수는 _db_query 함수의 인수가 됩니다.
이제 _db_query 함수를 살펴보겠습니다.
마커 11: 테인트 데이터가 _db_query 함수의 첫 번째 매개변수 $query에 있습니다.
마커 12: 매개변수의 데이터가 싱크인 mysql_query 함수로 전달됩니다.
위의 전체 데이터 흐름은 데이터가 안정성 또는 유효성 검사를 거치지 않고 $_POST[“edit”]에서 mysql_query($query)로 전달되는 방식을 보여줍니다. 이때 공격자는 $_POST[“edit”] 키와 연결된 SQL 쿼리를 조작하고 SQL 삽입을 트리거할 수 있습니다.
Qodana는 코드베이스 및 테인트 데이터가 사용되는 모든 노드에서 이러한 위험을 탐지하고, 적시에 모든 테인트 데이터의 안정성을 검사합니다.
PhpStorm에서 이슈 열기
예시 2. XSS 문제
Qodana UI에서 전체 테인트 흐름을 시각화하는 그래프를 확인할 수 있습니다. Qodana가 마커 5에 병합될 2개의 소스를 포함하는 XSS 취약성을 시각화하는 방식은 다음과 같습니다.
소스 1
마커 1~2: searchUpdate.pos 파일의 데이터를 읽고 테인트 데이터를 $start 변수에 대입합니다.
소스 2
마커 3-4: 경로가 $posFile에 있는 파일의 데이터를 읽고 테인트 데이터를 $start 변수에 대입합니다.
마커 5: $start 변수의 모든 조건 브랜치에서 병합된 테인트 상태가 doUpdateSearchIndex 메서드에 인수로 전달됩니다.
doUpdateSearchIndex 메서드를 살펴보겠습니다.
마커 6~8: $start 매개변수는 이 데이터 흐름 조각의 테인트 데이터를 포함합니다. 이후 연결된 문자열 내에서 ‘output’ 메서드의 인수로 전달됩니다.
output 메서드를 살펴보겠습니다.
마커 9: 전송된 문자열에 포함된 테인트 데이터가 $out 매개변수에 있습니다.
마커 10: $out 매개변수의 데이터는 안정성 검사를 거치지 않고 print 함수로 전달됩니다. 이 함수가 싱크이며, 악용될 수 있는 XSS 취약점을 초래합니다.
이 취약점을 악용하는 공격자는 마커 1과 2에 예상되는 파일 대신 셸 스크립트를 업로드하는 공격을 할 수 있으며, print 함수에 대한 안정성 검사가 시행되지 않았으므로 웹 페이지에 모든 정보를 입력할 수 있습니다.
Qodana는 이러한 취약점에 대한 경고를 표시하고, 높은 우선순위를 부여하여 조속히 문제를 해결하고 해킹을 방지하도록 지원합니다.
결론
테인트 분석은 악용 가능한 공격 노출면을 제거하는 데 도움이 되므로 소프트웨어의 보안 위험을 줄이는 효과적인 방법입니다. 테인트 분석 및 Qodana에 대해 자세히 알아보려면 Qodana 문서를 참조하세요.
코드를 안전하게 유지하면서, 즐겁게 개발하세요!
게시물 원문 작성자
The PhpStorm Blog : The Lightning-Smart IDE for PHP Programming | The JetBrains Blog