AI가 당신의 C# 코드를 작성하고 있으며, 이제 AI가 이를 공격하고 있습니다. 이 결함을 먼저 해결하세요
요약
AI가 생성한 코드의 보안 취약점, 특히 C# 환경에서의 SQL 인젝션 및 입력 유효성 검사 누락 문제를 경고합니다. AI가 코드를 작성하는 속도만큼 취약점을 찾아내는 속도도 빨라지고 있어, 로직 기반의 보안 검토가 필수적입니다.
핵심 포인트
- AI 생성 코드의 약 45%가 OWASP Top 10 취약점을 포함함
- C#은 보안 경계 코드의 특성상 AI 취약점 영향력이 매우 높음
- 구문 오류가 아닌 로직 오류로 인해 정적 스캐너 탐지가 어려움
- 입력 유효성 검사 누락이 AI 생성 코드의 가장 흔한 결함임
2026년에 두 가지 사건이 발생했으며, 이 두 사건은 매우 근접한 시기에 일어나 아주 오래전부터 존재해 온 버그(bug)에 대한 당신의 생각을 바꿔놓아야 할 정도입니다.
이 두 가지를 함께 읽어보십시오. AI가 많은 코드를 작성하고 있으며, 이제 AI는 기계의 속도로 그 코드의 구멍을 찾아낼 수 있습니다. 공격에서 느리고 비용이 많이 들던 부분은 사람이 앉아서 코드를 읽으며 침투 경로를 찾는 것이었습니다. 그 부분이 자동화되고 있습니다.
따라서 질문은 더 이상 "내 코드가 깨끗한가"가 아닙니다. "가장 가능성 높은 구멍은 어디이며, 내가 그것을 막았는가"입니다. .NET의 경우 데이터 포인트는 한 가지 답을 가리키고 있으며, 이는 전혀 생소한 것이 아닙니다.
연구들이 실제로 발견한 것
2025년 말부터 2026년 사이에 나온 몇몇 독립적인 소스들은 거의 의심스러울 정도로 일치합니다:
- AppSec Santa는 6개의 주요 모델을 통해 534개의 코드 샘플을 OWASP Top 10에 대해 실행했습니다. 약 4개 중 1개는 확인된 취약점(vulnerability)과 함께 결과가 나왔으며, 대부분 SSRF 및 인젝션(injection) (CWE-78/89/94)이었습니다.
- Veracode는 Java, Python, C#, JavaScript에 걸쳐 100개 이상의 모델을 대상으로 더 광범위하게 테스트했으며, 생성된 코드의 45%가 SQL 인젝션을 포함한 OWASP Top 10 문제를 유발하는 것을 확인했습니다. 이 비율은 반복된 사이클 동안 감소하지 않았습니다.
- Endor Labs와 몇몇 학술 검토 결과는 동일한 근본 원인에 계속 도달하고 있습니다: 입력 유효성 검사(input validation) 누락이 AI 생성 코드에서 가장 흔한 결함입니다. 모델은 당신이 하지 말라고 말하지 않는 한 기본적으로 이를 누락합니다.
특히 C# 개발자들을 괴롭힐 부분은 다음과 같습니다: 실제 환경에서 AI가 유발하는 취약점을 측정한 2026년 논문에 따르면, AI의 순 기여도는 C#에서 이례적으로 높게 나타났으며, 순 영향력 점수는 약 +7.6%로 조사된 모든 언어 중 최상위권에 근접했습니다. 그들의 설명은 마치 우리의 일상 업무를 묘사하는 것 같습니다: 보안 경계(security boundaries)에 바로 위치하며 반복적이고 패턴 기반의 호출 지점(call sites)으로 가득 찬 웹 및 API 코드입니다. 이는 모델이 경계에 대해 생각하며 멈추지 않고 기꺼이 자동 완성(autocomplete)할 법한 바로 그런 종류의 것입니다.
기억해 둘 만한 수치가 하나 더 있습니다. AppSec Santa의 조사에 따르면, 확인된 취약점의 78%가 실행한 5개의 스캐너 중 단 하나에 의해서만 탐지되었습니다. 생성된 코드는 깨끗합니다. 컴파일도 잘 되고, 린터(linter)도 통과하며, 읽기에도 문제가 없습니다. 버그는 구문(syntax)이 아닌 로직(logic)에 존재하며, 이는 정적 스캐너(static scanners)가 가장 못하는 부분이자 리뷰어의 눈이 아무것도 잘못되어 보이지 않기 때문에 그냥 지나치게 되는 바로 그 지점입니다.
결함: 아무도 확인하지 않은 입력값으로부터 발생하는 SQL 인젝션 (SQL injection)
이것은 제가 끊임없이 목격하는 사례입니다. 빠른 검색 엔드포인트(endpoint)를 요청하면, 첫 실행 시에는 잘 작동하는 결과물을 받게 됩니다:
// AI가 생성한, "작동은 하지만" SQL 인젝션에 완전히 노출된 코드
public async Task<List<Product>> Search(string name)
{
...
코드는 실행됩니다. 데모도 통과합니다. 그리고 이는 Veracode와 OWASP 데이터가 계속해서 지적하는 것과 동일한 버그입니다. name 변수가 쿼리 문자열(query string)로 직접 들어가기 때문입니다. 모델 입장에서는 이를 검증하거나 매개변수화(parameterize)해야 할 이유가 없었습니다. 프롬프트(prompt) 어디에도 입력값이 적대적이라는 언급이 없었으며, 모델의 학습 데이터는 정확히 이러한 지름길로 가득 차 있습니다.
일반적인 제품명을 입력하면 일반적인 결과가 나옵니다. SQL을 입력하면 SQL을 실행하게 됩니다. 핵심을 설명하기 위해 굳이 페이로드(payload)를 제공할 필요도 없습니다. 문자열 자체가 여기서 신뢰 경계(trust boundary)가 되어야 하는데, 경계가 존재하지 않는 것입니다.
해결책은 지루합니다. 그것이 바로 핵심입니다.
두 가지 계층이 있습니다.
첫째, 문자열을 이어 붙여서 SQL을 만드는 행위를 중단하십시오. 프로바이더(provider)가 대신 매개변수화하도록 하십시오. EF Core에서는 FromSqlInterpolated가 단순한 문자열 보간(string interpolation)처럼 보임에도 불구하고 이 역할을 수행합니다. 핵심은 보간(interpolation)에 사용된 모든 값이 명령 텍스트(command text)에 연결(concatenated)되는 것이 아니라, SQL 매개변수(parameter)로 전송된다는 점입니다:
public async Task<List<Product>> Search(string name)
{
var pattern = $"%{name}%";
...
이 줄은 실제로 이해할 가치가 있습니다. 왜냐하면 이 줄과 문제가 있는 버전 사이의 차이점은 한눈에 보이지 않기 때문입니다. FromSqlRaw는 완성된 문자열을 가져와 그대로 신뢰합니다. 반면 FromSqlInterpolated는 FormattableString을 가져와 각 구멍(hole)을 매개변수(parameter)로 변환하므로, pattern은 SQL Server에 쿼리 텍스트의 일부가 아닌 값(value)으로서 전달됩니다. 겉보기에는 똑같은 $"..." 형식이지만, 보안 측면에서의 이야기는 완전히 다릅니다.
만약 실제로 원시 SQL (raw SQL)이 필요한 것이 아니라면, 이를 건너뛰고 LINQ가 쿼리를 구축하도록 하세요. 그러면 해당 문제는 발생하지 않습니다.
public async Task<List<Product>> Search(string name)
=> await _db.Products
.Where(p => EF.Functions.Like(p.Name, $"%{name}%"))
...
두 번째 계층: 데이터 계층(data layer)에 도달하기 전, 컨트롤러(controller)와 같은 경계(edge)에서 입력을 검증하세요.
// 리포지토리(repository)가 아닌 컨트롤러 / 엔드포인트(endpoint)에서
if (string.IsNullOrWhiteSpace(name) || name.Length > 100)
return BadRequest("Invalid search term.");
이는 매개변수화 (parameterization)만으로 충분하지 않기 때문이 아닙니다. SQL의 경우 그것만으로 충분합니다. 하지만 "경계에서 모든 입력을 확인한다"는 습관은, AI가 다음에 건네줄 SQL과 전혀 상관없는 버그를 포함하여 해당 카테고리의 모든 문제를 차단하는 습관입니다.
이 중 어느 것도 영리한 기술이 아니며, 그것이 핵심입니다. 가장 흔하게 AI가 유발하는 버그에 대한 방어책은 우리가 이미 알고 있던 지루한 기본 원칙들과 동일합니다. 2026년에 변한 것은 그 주변의 수치입니다. 하루에 생성되는 코드의 양은 더 많아졌고, 코드 한 줄당 투입되는 인간의 주의력은 줄어들었으며, 이제는 그 빈틈을 파고드는 존재가 더 이상 사람이 아닐 실질적인 가능성이 생겼습니다.
실무적인 관점에서는
AI가 생성한 데이터 액세스 (data-access) 코드는 직접 읽기 전까지 검증되지 않은 것으로 취급하세요. 입력 처리 로직이 존재하지 않는다고 가정하십시오. "컴파일이 잘 되고 스캐너(scanner) 결과가 초록색이다"라는 사실이 코드 리뷰를 대신하게 두지 마세요. 데이터에 따르면 단일 스캐너는 이러한 문제의 대부분을 놓치며, 버그는 여전히 인간이 확인해야 하는 로직 속에 자리 잡고 있습니다. 그리고 안전한 버전(매개변수화된 쿼리, 경계에서의 검증)을 반사적으로 사용하도록 습관화하여, 지름길(shortcut) 코드가 애초에 파일에 포함되지 않도록 하십시오.
최근 AI가 작성한 C# 코드를 검토해 오셨다면, 여러분도 저와 같은 현상을 목격하고 계시는지 궁금합니다. 저의 경우, 거의 항상 이러한 문제와 더불어 권한 확인 (authorization checks) 누락이 발견됩니다. 여러분의 검토 과정에서는 어떤 문제들이 계속 나타나고 있나요?
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기