푸터 콘텐츠로 바로가기
Iron Academy Logo
C# 데이터베이스 통합

SQL 인젝션이란 무엇이며 이를 C#에서 어떻게 방지할까요?

Tim Corey
34분 33초

SQL 인젝션은 공격자가 사용자 입력을 통해 악성 SQL 코드를 데이터베이스 서버로 전송할 수 있도록 하는 코드 삽입 기법입니다. Tim Corey는 자신의 비디오 " SQL 인젝션이란 무엇이며 C#에서 어떻게 방지할 수 있을까요? "에서 SQL 인젝션 취약점이 실제 코드에서 어떻게 나타나는지 정확하게 보여주고, 여러 성공적인 SQL 인젝션 공격 사례(union 기반 공격 및 파괴적 공격 포함)를 제시하며, C#에서 적용할 수 있는 실용적인 SQL 인젝션 방지 기법을 설명합니다. 이 글은 Tim의 단계별 설명에 따라 작성되었으므로 Tim이 보여주는 정확한 문제점과 해결 방법을 확인할 수 있습니다.

데모 앱과 그 중요성

Tim은 로컬 InjectableDB (People 및 Secrets 테이블)에 연결된 간단한 WPF 데모 앱으로 시작합니다. 앱의 웹 양식과 유사한 검색 상자는 사용자 입력(성)을 받아 ID, 이름 및 성을 반환하는 SQL 쿼리를 생성합니다. Corey를 입력하면 Tim Corey가 나오는 것처럼 "작동"하는 것은 맞지만, Tim은 핵심을 강조합니다. "애플리케이션이 작동한다고 해서 안전하다는 의미는 아닙니다." 정상적으로 작동하는 웹 애플리케이션이라도 사용자 입력값을 문자열 연결이나 동적 SQL을 통해 SQL 문에 직접 삽입하는 경우 SQL 인젝션 취약점이 존재할 수 있습니다.

안전하지 않은 코드 - 문자열 연결 및 동적 SQL

팀은 많은 개발자들이 사용하는 바로 그 위험한 패턴을 보여줍니다.

var sql = $"SELECT * FROM People WHERE LastName = '{searchText}'";
var results = connection.Query<Person>(sql);
var sql = $"SELECT * FROM People WHERE LastName = '{searchText}'";
var results = connection.Query<Person>(sql);

이 원래 쿼리는 문자열 연결을 사용하여 SQL 문을 생성합니다. 팀은 다음과 같이 경고합니다. 사용자 입력을 SQL 쿼리에 직접 삽입하는 코드를 발견하면 즉시 중단하십시오. 이는 SQL 인젝션 취약점입니다. 공격자는 SQL 명령의 구조를 변경하거나 추가적인 악성 SQL 문을 실행하는 악의적인 입력을 생성할 수 있습니다.

공격자가 이를 악용하는 방법 — UNION 및 DROP

SQL 인젝션 공격이 어떻게 작동하는지 보여주기 위해 Tim은 SQL Server에서 쿼리를 작성한 다음 UNION ALL과 SQL 주석(--)을 사용하여 후행 문자를 숨기는 방식으로 인젝션을 구성합니다. Tim이 보여주는 악성 페이로드 예시:

  • Union 기반 SQL 인젝션을 사용하여 다른 테이블을 읽으려는 시도:

    UNION ALL SELECT ID, Username AS FirstName, Password AS LastName FROM Secrets;

    이렇게 하면 Secrets 의 결과가 원래 SELECT 결과 집합에 혼합되어 사용자 이름 및 암호와 같은 민감한 데이터가 노출됩니다.

  • 테이블을 삭제하기 위한 파괴적 주입:

    DemoTable 테이블을 삭제합니다.

    이는 첫 번째 SQL 문을 세미콜론으로 끝내고 삭제 명령을 추가하여 두 번째 SQL 문(DROP TABLE)을 실행합니다. 팀은 테이블이 사라진 것을 보여줍니다. 데이터베이스가 악의적인 SQL에 의해 수정된 것입니다.

팀의 요점은 공격자가 테이블이나 열 이름을 미리 알 필요가 없다는 것입니다. 데이터베이스 서버에서 테이블이나 열 이름을 열거하거나, 단순히 무작위 또는 시간 기반 기법을 사용하여 동작을 파악할 수 있습니다.

해결 방법 1 — 매개변수화된 쿼리

팀이 취할 첫 번째이자 가장 중요한 조치는 사용자 데이터를 사용하여 SQL 문자열을 생성하는 것을 중단하는 것입니다. 동적 SQL을 매개변수화된 쿼리로 대체하십시오.

string sql = "SELECT * FROM People WHERE LastName = @LastName";
var results = connection.Query<Person>(sql, new { LastName = searchText });
string sql = "SELECT * FROM People WHERE LastName = @LastName";
var results = connection.Query<Person>(sql, new { LastName = searchText });

Tim은 매개변수화(준비된 문 스타일 사용)는 데이터베이스가 사용자가 제공한 입력을 엄격하게 데이터로 처리한다는 것을 의미한다고 설명합니다. 즉, 악의적인 SQL은 단순한 문자열 값으로만 ​​처리되어 SQL 구조를 변경할 수 없게 됩니다. 이는 유니온 기반 페이로드 및 추가된 세미콜론(;)을 포함한 많은 일반적인 SQL 인젝션 공격을 방지합니다. DROP TABLE 명령어.

그는 또한 매개변수화와 최소한의 입력 유효성 검사를 결합할 것을 권장합니다. 즉, 성에서 흔히 사용되지 않는 문자(예: 세미콜론 또는 -- 주석 표시)는 제거하거나 차단하고, 아포스트로피와 같은 유효한 문자는 허용하는 것입니다(O'Reilly). 매개변수화된 쿼리와 입력값 정제는 SQL 인젝션 공격에 대한 상당한 보호 기능을 제공합니다.

해결 방법 2 — 저장 프로시저

다음으로 Tim은 두 가지 저장 프로시저를 보여줍니다. 하나는 프로시저 내부에서 SQL 문을 연결한 다음 실행하는 안전하지 않은 저장 프로시저이고, 다른 하나는 매개변수를 직접 사용하는 안전한 저장 프로시저입니다.

  • 안전하지 않은 저장 프로시저는 매개변수로부터 @sql 문자열을 생성하고 이를 실행합니다. 여전히 SQL 인젝션에 취약합니다.

  • 안전한 저장 프로시저는 SELECT 작업을 수행합니다... WHERE LastName = @LastName이고 —safe 매개변수와 함께 실행됩니다.

팀은 다음과 같이 설명합니다. 저장 프로시저를 사용한다고 해서 자동으로 문제가 해결되는 것은 아니며, 저장 프로시저 내부에 동적 SQL을 계속 사용하는 경우에는 더욱 그렇습니다. 하지만 저장 프로시저를 올바르게 사용하면(동적 SQL을 사용하지 않으면) SQL 문을 중앙 집중화하여 쿼리를 매개변수화하고 감사하는 것을 더 쉽게 만들 수 있습니다. 저장 프로시저는 앱에서 SQL 인젝션 방지를 간소화하는 데에도 도움이 될 수 있습니다.

어떤 데이터도 믿지 마세요. 데이터베이스 데이터조차도 믿지 마세요.

팀이 지적하는 중요하지만 종종 간과되는 점은 바로 자신의 SQL 데이터베이스에서 가져온 데이터를 맹목적으로 신뢰해서는 안 된다는 것입니다. 공격자는 때때로 악성 페이로드를 컬럼에 심어두는데("시한폭탄"), 이는 나중에 다른 프로세스에 의해 동적 SQL로 연결됩니다. 팀은 웹 양식, 파일 업로드 또는 자체 데이터베이스에서 입력되는 데이터든 관계없이 모든 단계에서 항상 매개변수를 사용하고 데이터를 검증해야 한다고 강조합니다. 그래야 악의적인 입력이 나중에 주입 공격의 통로가 될 수 없기 때문입니다.

추가 팁 - 최소 권한 원칙 및 데이터베이스 권한 제한

코드 수정 외에도 Tim은 방어적인 구성을 권장합니다. 즉, 애플리케이션 계정에 대한 데이터베이스 권한을 제한하는 것입니다. 데모에서 사용된 연결 방식은 통합 보안을 통해 관리자 계정을 사용하는 것인데, 이는 위험합니다. 대신 최소 권한 원칙을 사용하십시오.

  • 앱에 필요한 권한만 있는 데이터베이스 계정을 생성하세요.

  • 저장 프로시저를 사용하는 경우, 해당 계정에 특정 저장 프로시저에 대한 실행 권한만 부여하고 다른 권한은 부여하지 마십시오.

  • 애플리케이션 계정에 테이블 삭제, 모든 테이블 목록 표시, 다른 데이터베이스 읽기 등을 허용하는 광범위한 관리자 권한을 부여하지 마십시오.

이는 SQL 인젝션 공격이 성공하더라도 그 영향을 줄여줍니다. 공격자가 인젝션을 시도하더라도 계정에 허용된 권한 이상의 작업을 수행할 수 없기 때문입니다.

Tim은 Entity Framework가 이 문제를 복잡하게 만든다고 지적합니다. EF는 마이그레이션이나 스키마 변경과 같은 작업에 종종 높은 권한이 필요합니다. EF를 실제 운영 환경에서 사용하는 경우, 권한 설정과 배포 계획을 신중하게 세워야 합니다.

요약 — 중지, 매개변수화, 정제, 제한

팀은 C# 애플리케이션에서 SQL 인젝션을 방지하기 위한 명확한 체크리스트를 제시하며 영상을 마무리합니다.

  1. 문자열 연결이나 사용자 입력을 포함하는 동적 SQL을 사용하여 SQL 문을 작성하는 것을 중단하십시오.

  2. 매개변수화된 쿼리/준비된 문 패턴을 사용하여 사용자 데이터가 항상 데이터로 처리되도록 합니다.

  3. 필요한 경우 입력값을 정제합니다(세미콜론, SQL 주석, 예상치 못한 문자 등을 차단).

  4. 쿼리 로직을 중앙 집중화할 때는 안전한 저장 프로시저(동적 SQL이 포함되지 않은 프로시저)를 사용하는 것이 좋습니다.

  5. 데이터베이스 계정에 최소 권한을 적용하십시오. 즉, 앱의 데이터베이스 사용자가 할 수 있는 작업을 제한하십시오.

  6. 코드(특히 SQL을 동적으로 생성하는 부분)를 검토하고 SQL 인젝션 취약점을 테스트합니다.

팀의 마지막 경고: 사용자 입력에 대한 부주의한 처리, 동적 SQL 사용, 과도한 데이터베이스 권한 부여는 심각한 보안 침해로 이어질 수 있습니다. 민감한 데이터 유출, 테이블 손상, 또는 장기간에 걸친 탐지되지 않은 데이터 유출 등이 발생할 수 있습니다. SQL 인젝션 방지를 선택 사항이 아닌 핵심 보안 요구 사항으로 간주하십시오.

Hero Worlddot related to SQL 인젝션이란 무엇이며 이를 C#에서 어떻게 방지할까요?
Hero Affiliate related to SQL 인젝션이란 무엇이며 이를 C#에서 어떻게 방지할까요?

사랑하는 것을 공유하여 더 많은 수익을 얻으세요

당신은 .NET, C#, Java, Python, 또는 Node.js를 다루는 개발자를 위한 콘텐츠를 만드나요? 당신의 전문성을 추가 수입으로 전환하세요!

아이언 서포트 팀

저희는 주 5일, 24시간 온라인으로 운영합니다.
채팅
이메일
전화해