SQL Injection (3) - Stored Procedure에서의 SQL Injection

[제목] SQL Injection (3) - Stored Procedure에서의 SQL Injection

지금까지의 SQL Injection 관련 아티클에서 설명한 바와 같이, C#에서 SQL문을 문자열 병합 (string concatenation)으로 처리하는 것은 SQL Injection을 야기하는 주요 원인이 되며, 따라서 SqlParameter를 사용한 Parameterized Query를 이용해야 함을 알 수 있었다. 그러면 다음과 같이 SQL Stored Procedure를 C#에서 호출하는 것은 어떤 문제가 있을 수 있을까?

/* C# */
public void CallWrongSP()
{
    string name = "Park";
    using (SqlConnection conn = new SqlConnection(connStr))
    {                
        conn.Open();

        // Parameterized Query : SP
        SqlCommand cmd = new SqlCommand("sp_Call", conn);
        cmd.CommandType = CommandType.StoredProcedure;                
        SqlParameter pInput = new SqlParameter("@name", name);
        cmd.Parameters.Add(pInput);

        // Run SP
        var rs = cmd.ExecuteReader();
        while (rs.Read())
        {
            Debug.WriteLine(rs[0]);
        }
    }
}

언뜻 보기에, 이 C# 코드는 아무런 문제 없어 보이는데, 실제 저장 프로시져(Stored Procedure, SP)를 보지 않고 C# 코드만 따진다면, 문제될 것이 없다. 하지만, 이 C# 코드가 호출하는 Stored Procedure가 다음과 같다면, SQL Injection이 일어날 수 있다.

--
-- SQL Injection 문제가 있는 Stored Procedure
--
CREATE PROC [dbo].[sp_Call] 
( @name nvarchar(max) )
AS  
BEGIN
   DECLARE @sql nvarchar(max)
   SET @sql = 'SELECT * FROM users WHERE name=''' + @name + ''''
   -- EXEC @sql
   exec sp_executesql @sql
END;

이 SP를 자세히 보면, 전달받은 파라미터 @name의 값을 SELECT 문에 다시 문자열 병합으로 연결하고 있다. 이렇게 병합된 Dynamic SQL문은 EXEC 혹은 sp_executesql 을 사용하여 실행되는데, 여기서는 sp_executesql을 EXEC와 같이 사용하고 있다 . TSQL문에서 EXEC 와 sp_executesql의 차이점은 EXEC (Execute)는 문자열 병합으로 생성된 Dynamic SQL문을 직접 실행하는데 사용되고, sp_executesql은 EXEC 보다 향상된 기능으로 TSQL문에서 파라미터가 되는 부분을 직접 문자열 병합하여 사용하지 않고 C#의 SqlParameter사용예와 같이 파라미터화하여 전달할 수 있다는 것이다. 따라서 위와 같이 문자열 병합 대신 아래 예제와 같이 @name 부분을 다시 파리미터로 만들어 sp_executesql 의 세번째 파라미터에 넣을 수 있다.

--
-- SQL Injection 문제가 없는 Stored Procedure
--
CREATE PROC [dbo].[sp_Call] 
( @name nvarchar(max) )
AS  
BEGIN
   DECLARE @sql nvarchar(max)
   SET @sql = 'SELECT * FROM users WHERE name = @paraName'
   exec sp_executesql @sql, N'@paraName nvarchar(max)', @name
END;

위의 예제에서 @paraName이라는 임의의 파라미터를 만들고 이를 sp_executesql의 두번째 Argument에서 @paraName nvarchar(max)와 같이 파라미터 데이타형을 지정한 후, 세번째 Argument에 해당 파라미터값을 전달하면, sp_executesql은 @name값을 파라미터 하나로 인식하여 SQL Injection을 방지하게 된다. 비록 sp_executesql이 파라미터가 없이 (위의 잘못된 예제처럼) Dyanmic SQL문을 실행할 수는 있지만, 항상 (파라미터가 있는 경우) 해당 파라미터를 지정하여 문장을 수행해야 SQL Injection의 위험으로부터 벗어날 수가 있다.
 



본 웹사이트는 광고를 포함하고 있습니다. 광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.