Bard, ChatGPT 및 Bing Chat과 같은 인공 지능 도구는 현재 증가하고 있는 LLM(Large Language Model) 범주의 유명 도구입니다.
LLM은 일상적인 인간 언어를 채팅 프롬프트로 사용하여 의사소통할 수 있도록 방대한 데이터 세트에 대한 교육을 받았습니다. LLM의 유연성과 잠재력을 고려하여 기업은 LLM을 기술 산업 내부의 많은 워크플로에 통합하여 우리의 삶을 더 좋고 쉽게 만들고 있습니다. 주요 AI 워크플로 통합 중 하나는 자동 완성 코드 플러그인으로, 더 빠르고 효율적으로 코딩하기 위해 일치하는 코드 패턴을 예측하고 생성하는 기능을 제공합니다.
현재 AI 코드 생성기 도구 시장에는 GitHub Copilot , Amazon CodeWhisperer , Google Cloud Code(Duet AI) , Blackbox AI Code Generation 등을 포함한 많은 플레이어가 있습니다. 이 블로그 게시물에서는 개발자가 이러한 도구를 사용하는 동안 직면하게 되는 일반적인 보안 함정의 예를 간략하게 설명합니다.
이 기사의 목적 은 자동 생성 코드를 맹목적으로 신뢰할 수 없으며 소프트웨어 취약점이 발생하지 않도록 보안 검토가 필요하다는 인식을 높이고 강조하는 것입니다.
참고: 일부 공급업체에서는 자동 완성 도구에 안전하지 않은 코드 조각이 포함될 수 있다고 제안합니다.
많은 기사에서는 자동 완성 도구가 IDOR , SQL 삽입, XSS와 같은 알려진 취약점을 생성한다는 점을 이미 강조했습니다. 이 게시물에서는 AI 자동 완성이 코드에 버그를 삽입할 가능성이 높은 코드 컨텍스트에 더 많이 의존하는 다른 취약점 유형을 강조할 것입니다.
보안 및 AI 코드 생성 도구 코드용으로 훈련된 AI 모델은 일반적으로 작동하는 코드를 생성하는 주요 임무를 가지고 대규모 코드 기반에서 훈련됩니다.
많은 보안 문제에는 성능 측면을 손상시키지 않으면서 알려지고 정의된 완화 방법이 있습니다(예: 사용자 입력/매개변수를 쿼리에 직접 연결하지 않으면 SQL 주입을 피할 수 있음). 따라서 안전하지 않은 방식으로 코드를 작성합니다.
그러나 많은 보안 문제는 상황에 따라 달라지므로 내부 기능으로 구현하면 완벽하게 안전할 수 있지만 클라이언트의 외부 입력에 직면하면 취약점이 되므로 AI의 학습 데이터 세트를 통해 구별하기가 어렵습니다.
이러한 취약점에서 코드의 구체적인 사용법은 일반적으로 코드의 다른 부분과 애플리케이션의 전반적인 목적에 따라 달라집니다.
다음은 이러한 유형의 취약점을 보여주는 몇 가지 일반적인 사용 사례와 테스트한 예입니다.
AI 코드 생성 도구가 위 사례를 어떻게 처리하는지 확인한 후 적절한 보안 필터 및 기타 완화 메커니즘을 생성하는 능력을 테스트하려고 했습니다.
다음은 의도적으로 보안 코드를 요청하여 테스트한 몇 가지 일반적인 사용 사례와 예입니다.
많은 애플리케이션에는 파일 이름을 기반으로 사용자에게 파일을 다시 가져오는 코드가 포함되어 있습니다. 서버의 임의 파일을 읽기 위해 디렉터리 탐색을 사용하는 것은 악의적인 행위자가 승인되지 않은 정보를 얻기 위해 사용하는 일반적인 방법입니다.
파일을 다시 가져오기 전에 사용자가 입력한 파일 이름/파일 경로 입력을 삭제하는 것이 당연해 보일 수 있지만 일반 코드 베이스로 훈련된 AI 모델에는 어려운 작업이라고 가정합니다. 이는 일부 데이터 세트에서는 그럴 필요가 없기 때문입니다. 정리된 경로를 기능의 일부로 사용하거나 (성능을 저하시키거나 기능에 해를 끼칠 수도 있음) 내부 사용 전용이므로 정리되지 않은 경로로 인해 피해를 입지 않습니다.
AI 도구 제안(Google Cloud Code - Duet AI): Google Cloud Code - Duet AI 자동 완성을 사용하여 사용자 입력에서 기본 파일 가져오기 기능을 생성해 보겠습니다. Duet AI가 함수 및 경로 이름을 기반으로 코드를 자동 완성하도록 합니다.
회색으로 볼 수 있듯이 자동 완성 제안은 Flask의 기본 파일 처리 기능인 Flask의 " send_file " 기능을 사용하는 것입니다.
그러나 Flask의 문서에도 " 사용자가 제공한 파일 경로를 전달하지 마십시오 "라고 명시되어 있습니다. 즉, 사용자 입력을 "send_file" 함수에 직접 삽입하는 동안 사용자는 예를 들어 디렉터리 순회 문자를 사용하여 파일 시스템의 모든 파일을 읽을 수 있다는 의미입니다. 예를 들어 파일 이름에 "../"가 있습니다.
적절한 구현:
"send_file" 기능을 Flask의 안전한 "send_from_directory" 기능으로 바꾸면 디렉터리 탐색 위험이 완화됩니다. 특정 하드 코딩된 디렉터리(이 경우 "내보내기")에서만 파일을 가져올 수 있습니다.
PHP 및 NodeJS와 같은 일부 프로그래밍 언어에서는 두 가지 다른 유형의 변수를 비교할 수 있으며 프로그램은 작업을 완료하기 위해 뒤에서 유형 변환을 수행합니다.
느슨한 비교는 배후에서 변수의 유형을 확인하지 않으므로 유형 저글링 공격에 더 취약합니다. 그러나 느슨한 비교의 사용은 그 자체로는 안전하지 않은 코딩 관행으로 간주되지 않으며 코드의 컨텍스트에 따라 다릅니다. 그리고 AI 모델이 사례를 구분하는 것도 어렵습니다.
AI 도구 제안(Amazon CodeWhisperer): PHP 유형 저글링의 가장 일반적인 예는 JSON 요청(입력 유형 제어 가능)을 통해 읽은 사용자 입력이 느슨한 비교(“ ” 에 도달하는 비밀 토큰/해시의 느슨한 비교입니다. ) 대신 엄격한 형식(" =")을 사용합니다 .
나타나는 대로 CodeWhisperer는 자동 완성 제안에서 느슨한 비교 조건을 생성합니다.
secret_token의 느슨한 비교를 통해 공격자는 $data[“secret_token”] == “secret_token” 비교를 우회할 수 있습니다. “secret_token” 값이 True(부울)인 JSON 개체를 제출하는 동안 느슨한 비교 결과도 True입니다 (최신 PHP 버전에서도).
"안전하게" 수표를 작성하기 위해 도구를 "힌트"(주석 사용)하는 경우에도 엄격한 비교가 포함된 코드 조각을 생성하지 않았습니다.
적절한 구현:
엄격한 비교(“===”)를 지정하는 경우에만 유형 저글링 공격으로부터 보호됩니다.
"비밀번호 찾기" 메커니즘의 취약점은 SaaS 애플리케이션에서 매우 일반적이며 다음과 같은 CVE의 근본 원인이었습니다.
특히, 유니코드 대소문자 매핑 충돌 취약성은 사용자 입력이 비교 표현식에서 대문자 또는 소문자로 표시되고 원래 값이 코드에서도 사용되는 경우 발생합니다. 일부 다른 문자는 변환 시 동일한 문자 코드를 생성합니다. 예를 들어, "ß"와 "SS"는 모두 대문자인 경우 "0x00DF"로 변환됩니다.
이러한 경우는 일반적으로 비교 확인을 속이고 나중에 예상과 다른 원래 값을 사용하여 일부 보안 확인을 우회/오도하는 데 사용됩니다. 이러한 사례는 특히 많은 구현이 가능한 경우 파악하기 매우 어렵습니다.
AI 도구 제안(GitHub Copilot): 이 취약점 유형에 특히 취약한 메커니즘은 비밀번호 찾기 메커니즘 입니다. 원하지 않는 불일치를 방지하기 위해 검사를 수행할 때 사용자 입력을 대문자 또는 소문자(이메일 주소 또는 도메인 이름)로 정규화하는 것이 일반적입니다.
예를 들어, 비밀번호 찾기 기능에 대한 Copilot 생성 코드(아래)를 살펴보면 이 문제에 취약하다는 것을 알 수 있습니다.
Copilot의 코드는 먼저 소문자 이메일 주소를 조회합니다.
그런 다음 나머지 프로세스를 진행할 때 다음을 제안합니다.
보시다시피 자동 완성 제안은 임의의 비밀번호를 생성하여 사용자의 이메일 주소로 보냅니다. 그러나 처음에는 사용자 계정을 가져오기 위해 사용자 이메일의 소문자 버전을 사용한 다음 복구 이메일의 대상으로 원래 사용자의 이메일을 '있는 그대로'(소문자 변환 없이) 계속 사용합니다.
예를 들어, 공격자가 "[email protected]"("K"는 켈빈 기호 유니 코드 문자임)의 받은 편지함을 소유하고 이 이메일을 "비밀번호 찾기" 메커니즘에 사용한다고 가정해 보겠습니다. 이메일 "[email protected]" 및 "[email protected]"은 '있는 그대로' 동일 하지 않지만 소문자로 변환하면 다음과 같습니다.
이메일 주소 “[email protected]”을 사용하면 “[email protected]”에 대한 계정 정보를 가져오지만 재설정된 비밀번호는 공격자의 받은 편지함(“[email protected]”)으로 전송되어 “ [email protected]' 계정입니다.
적절한 구현: 사용자 계정을 가져오는 데 사용되는 이메일 주소는 복구 이메일 주소와 정확히 동일해야 합니다(즉, send_email 매개변수도 email.lower()를 사용합니다).
또한, 예방 조치로 사용자가 제공한 값 대신 서버에 이미 저장되어 있는 값을 사용하는 것이 좋습니다.
자동 완성 도구를 혼동할 수 있는 또 다른 주제는 특히 복잡한 클라우드 인프라의 구성 파일 작성입니다.
주된 이유는 실제로 보안 모범 사례 지침이 있지만 모든 사람이 이를 따르는 것은 아니며 어떤 경우에는 지침에 어긋날 필요가 있기 때문입니다. 이러한 코드 샘플은 AI 훈련 데이터 세트에 포함될 수 있습니다. 결과적으로 일부 자동 완성 출력은 권장 보안 지침을 위반하게 됩니다.
다음 예에서는 Kubernetes의 가장 작은 실행 단위인 Kubernetes Pod 에 대한 구성 파일을 생성합니다.
AI 도구 제안(블랙박스 AI 코드 생성): 이 예에서는 Pod 구성 파일 생성을 시작합니다.
제안에서는 기능 섹션을 생성하고 루트 사용자로 포드를 실행하는 것과 기본적으로 동일한 Linux 커널 기능(SYS_ADMIN)을 컨테이너에 추가합니다.
적절한 구현: 그렇다면 securityContext를 생략하는 것이 더 낫습니까? 아니요. 기본적으로 다른 많은 기능이 추가되어 최소 권한 원칙을 위반하기 때문입니다.
Docker 보안 모범 사례 에 따르면 가장 안전한 설정은 먼저 모든 Linux 커널 기능을 삭제하고 나중에 컨테이너에 필요한 기능을 추가하는 것입니다.
위에서 언급한 문제를 해결하기 위해 기능 섹션에서는 모든 기능을 삭제하는 것으로 시작한 다음 점차적으로 컨테이너에 필요한 기능을 추가합니다.
사용 사례: 구성 개체 - 안전하지 않은 역직렬화로 이어지는 불일치
많은 취약점에는 애플리케이션이 필수 구성 요소를 처리하는 방법을 결정하는 구성 개체 정의가 필요합니다.
우리가 선택한 예는 Newtonsoft의 C# JSON 역직렬화 라이브러리입니다. 이는 JsonSerializerSettings 개체의 구성, 특히 TypeNameHandling 에 따라 안전하게 또는 비보안적으로 사용될 수 있습니다.
역직렬화 코드를 테스트하는 동안 구성 개체의 정의가 매우 무작위적이며 미묘한 변경으로 인해 다른 구성 집합이 생성될 수 있음을 확인했습니다.
AI 도구 제안(Amazon CodeWhisperer): 다음 예는 개발자가 사용하는 메서드 이름만을 기반으로 하는 일관되지 않은 동작을 표시합니다.
TypeNameHandling 속성이 "Auto" 및 "ALL"이기 때문에 안전하지 않은 JSON 역직렬화를 초래하는 두 가지 구성을 볼 수 있습니다. 이러한 속성을 사용하면 JSON 문서에서 역직렬화된 클래스를 정의할 수 있으므로 공격자가 임의의 클래스를 역직렬화할 수 있습니다. 예를 들어 "System.Diagnostics.Process" 클래스를 역직렬화하여 원격 코드 실행에 쉽게 활용할 수 있습니다. 개발자의 원래 코드에서 유일한 차이점은 메서드 이름입니다.
적절한 구현:
기본적으로 JsonSerializerSettings 개체는 안전한 것으로 간주되는 "TypeNameHandling = TypeNameHandling.None"으로 인스턴스화됩니다. 따라서 안전한 TypeNameHandling 값을 생성하는 JsonSerializerSettings의 기본 생성자를 사용합니다.
AI 도구 제안(GitHub Copilot):
우리는 보안 검사가 디렉터리 순회 시도를 수행하는 데 필요한 점-점-슬래시 시퀀스만 피하면서 실제로 순진하다는 것을 알 수 있습니다. 경로 매개변수는 시스템에서 원하는 경로(예: /etc/passwd)를 가리키는 절대 경로일 수 있으며, 이는 보안 검사의 목적을 무효화합니다.
적절한 구현:
여기서 secure_file_read 함수는 파일 이름이 있어야 하는(그리고 이스케이프되어서는 안 되는) 디렉터리(safe_dir)와 함께 (상대) 파일 이름 매개 변수를 가져옵니다. safe_dir과 filename을 결합하여 절대 경로를 생성하고 realpath를 호출하여 정규화된 형식을 가져옵니다. 그런 다음 safe_dir 폴더의 정규화된 형식을 가져옵니다. 그런 다음 정규화된 경로가 정규화된 safe_dir로 시작하는 경우에만 파일 내용이 반환됩니다.
AI 도구 제안(블랙박스 AI 코드 생성): 다음 예에서는 AI 자동 완성기에 위험한 파일 확장자를 필터링하는 기능을 생성하도록 요청했습니다.
제안된 Python 코드는 파일 이름을 가져와 확장자를 구분한 다음 위험한 확장자 목록과 비교합니다.
언뜻 보기에 이 코드 조각은 안전해 보입니다. 그러나 Windows 파일 이름 규칙은 점으로 끝나는 파일 이름을 금지하며, 파일 생성 중에 점(“.”)으로 끝나는 파일 이름을 제공하면 점이 삭제됩니다. 즉, 악성 확장명 뒤에 점이 붙은 파일(예: “example.exe.”)을 제출할 때 Windows에서 생성된 필터가 우회될 수 있다는 의미입니다.
적절한 구현: 일반적으로 더 나은 접근 방식은 허용된 확장자에 대해서만 파일 확장자를 확인하는 화이트리스트를 사용하는 것입니다. 그러나 도구가 블랙리스트 접근 방식(경우에 따라 필요함)을 취했으므로 보다 안전한 블랙리스트 구현을 개략적으로 설명하겠습니다.
다음 코드 조각에서는 영숫자가 아닌 모든 문자에서 확장명을 제거하고 새로 생성된 파일 이름에 연결하여 입력에 대한 사용자의 제어권을 최대한 제거합니다.
결론 - 주의해서 사용하세요. 자동 공동 프로그래머는 아이디어 제안, 코드 자동 완성, 소프트웨어 개발 프로세스 속도 향상에 좋습니다. 우리는 이러한 도구가 시간이 지남에 따라 계속 발전할 것으로 기대하지만, 현재 이 게시물의 사용 사례에서 입증된 것처럼 자동 완성 AI 솔루션은 우리가 마음을 편하게 하고 두 번 확인하지 않고 결과를 신뢰할 수 있을 때까지 극복해야 할 많은 과제를 안고 있습니다. 버그.
취약점이 발생할 가능성을 줄이는 방법은 AI 코드 생성 도구에 의도적으로 보안 코드를 생성하도록 요청하는 것입니다. 이는 일부 사용 사례에서는 유용할 수 있지만 완벽하지는 않습니다. "겉보기에 안전해 보이는" 출력은 소프트웨어 보안에 능숙한 사람이 수동으로 검토해야 합니다.
JFrog 보안 연구 팀 권장 사항 소프트웨어 보안을 돕기 위해 AI 생성 도구로 생성된 코드를 수동으로 검토하는 것뿐만 아니라 진행하면서 취약점을 신뢰할 수 있게 발견할 수 있는 SAST(정적 애플리케이션 보안 테스트)와 같은 보안 솔루션을 통합하는 것이 좋습니다. 위의 예에서 볼 수 있듯이 SAST 도구는 사용 사례 #3에 설명된 유니코드 사례 매핑 충돌을 경고하고 포착할 수 있습니다. 이러한 사전 예방적 접근 방식은 소프트웨어 보안을 보장하는 데 필수적입니다.
JFrog 보안 연구에 대한 최신 정보 유지 보안 연구 팀의 조사 결과와 연구는 JFrog 플랫폼의 애플리케이션 소프트웨어 보안 기능을 향상시키는 데 중요한 역할을 합니다.
연구 웹사이트 와 X @JFrogSecurity 에서 JFrog 보안 연구 팀의 최신 발견과 기술 업데이트를 확인하세요.