bestsource

매개 변수화된 SQL 쿼리를 만들려면 어떻게 해야 합니까?내가 왜 그래야 돼?

bestsource 2023. 6. 3. 08:34
반응형

매개 변수화된 SQL 쿼리를 만들려면 어떻게 해야 합니까?내가 왜 그래야 돼?

"모두"가 매개 변수화된 SQL 쿼리를 사용하여 모든 사용자 입력을 확인할 필요 없이 SQL 주입 공격으로부터 보호하고 있다고 들었습니다.

이걸 어떻게 하나요?저장 프로시저를 사용할 때 이 메시지가 자동으로 표시됩니까?

제가 이해하는 바로는 이것은 매개변수가 아닙니다.

cmdText = String.Format("SELECT foo FROM bar WHERE baz = '{0}'", fuz)

매개 변수화됩니까?

cmdText = String.Format("EXEC foo_from_baz '{0}'", fuz)

아니면 SQL 주입으로부터 자신을 보호하기 위해 이와 같은 보다 광범위한 작업을 수행해야 합니까?

With command
    .Parameters.Count = 1
    .Parameters.Item(0).ParameterName = "@baz"
    .Parameters.Item(0).Value = fuz
End With

보안 고려 사항 외에 매개 변수화된 쿼리를 사용하면 다른 이점이 있습니까?

업데이트: 이 훌륭한 기사는 Grotok의 질문 참조 중 하나에 링크되었습니다.http://www.sommarskog.se/dynamic_sql.html

EXEC질문의 예제는 매개 변수화되지 않습니다.이러한 입력이 손상을 초래하지 않도록 하려면 매개 변수화된 쿼리(일부 원에서 준비된 문)가 필요합니다.

';Drop TABLE 막대;--

그것을 당신의 안에 넣어 보세요.fuz변수(또는 그렇지 않음, 만약 당신이 가치를 매긴다면)bar표)를 선택합니다.더 미묘하고 손상되는 쿼리도 가능합니다.

다음은 SQL Server에서 매개 변수를 수행하는 방법의 예입니다.

Public Function GetBarFooByBaz(ByVal Baz As String) As String
    Dim sql As String = "SELECT foo FROM bar WHERE baz= @Baz"

    Using cn As New SqlConnection("Your connection string here"), _
        cmd As New SqlCommand(sql, cn)

        cmd.Parameters.Add("@Baz", SqlDbType.VarChar, 50).Value = Baz
        Return cmd.ExecuteScalar().ToString()
    End Using
End Function

저장 프로시저가 SQL 주입을 방지하는 것으로 간주되기도 합니다.그러나 대부분의 경우 여전히 쿼리 매개 변수를 사용하여 호출해야 하거나 도움이 되지 않습니다.저장 프로시저를 단독으로 사용하는 경우 응용 프로그램 사용자 계정에 대한 SELECT, UPDATE, ALTER, CREATE, DELETE 등(EXEC를 제외한 모든 항목)에 대한 사용 권한을 해제하고 이러한 방식으로 일부 보호를 받을 수 있습니다.

확실히 마지막, 즉.

아니면 좀 더 광범위한 작업을 수행해야 합니까? (네,cmd.Parameters.Add())

매개 변수화된 쿼리에는 두 가지 주요 이점이 있습니다.

  • 보안:SQL 주입 취약성을 방지하는 좋은 방법입니다.
  • 성능:다른 매개 변수만 사용하여 동일한 쿼리를 정기적으로 호출하는 경우 매개 변수화된 쿼리를 사용하면 데이터베이스에서 상당한 성능 향상을 가져올 수 있습니다.
  • 추가: 데이터베이스 코드의 날짜 및 시간 형식 문제에 대해 걱정할 필요가 없습니다.마찬가지로 영어 이외의 로케일이 있는 컴퓨터에서 코드를 실행할 경우 소수점/소수점 쉼표에 문제가 없습니다.

이 예제가 진정으로 모수화된 유일한 예제이기 때문에 마지막 예제를 사용하려고 합니다.를 할 수 이 가장 NET이 매개 변수화를 처리할 수 있도록 하는 것이 가장 좋습니다. 전달하는 값에 단일 따옴표가 필요한지 여부는 확인할 수 없기 때문입니다.Type각 매개 변수의

[편집] 예는 다음과 같습니다.

SqlCommand command = new SqlCommand(
    "select foo from bar where baz = @baz",
    yourSqlConnection
);

SqlParameter parameter = new SqlParameter();
parameter.ParameterName = "@baz";
parameter.Value = "xyz";

command.Parameters.Add(parameter);

대부분의 사람들은 PHP의 PDO 또는 Perl DBI와 같은 서버 측 프로그래밍 언어 라이브러리를 통해 이 작업을 수행합니다.

예를 들어 PDO의 경우:

$dbh=pdo_connect(); //you need a connection function, returns a pdo db connection

$sql='insert into squip values(null,?,?)';

$statement=$dbh->prepare($sql);

$data=array('my user supplied data','more stuff');

$statement->execute($data);

if($statement->rowCount()==1){/*it worked*/}

이렇게 하면 데이터베이스 삽입을 위해 데이터를 이스케이프할 수 있습니다.

한 가지 장점은 준비된 문장 하나로 삽입을 여러 번 반복할 수 있어 속도가 향상된다는 것입니다.

예를 들어, 위 쿼리에서 문을 한 번 준비한 다음 데이터 집합에서 데이터 배열을 생성하고 -> 실행을 필요한 만큼 반복할 수 있습니다.

명령 텍스트는 다음과 같아야 합니다.

cmdText = "SELECT foo FROM bar WHERE baz = ?"

cmdText = "EXEC foo_from_baz ?"

그런 다음 모수 값을 추가합니다.변수 fuz가 다음과 같이 설정된 경우 다른 방법을 사용하면 값이 계속 값으로 사용됩니다.

"x'; delete from foo where 'a' = 'a"

무슨 일이 일어날지 알 수 있습니까?

여기에 SQL로 시작하는 짧은 클래스가 있습니다. 여기서 빌드하여 클래스에 추가할 수 있습니다.

MySQL

Public Class mysql

    'Connection string for mysql
    Public SQLSource As String = "Server=123.456.789.123;userid=someuser;password=somesecurepassword;database=somedefaultdatabase;"

    'database connection classes

    Private DBcon As New MySqlConnection
    Private SQLcmd As MySqlCommand
    Public DBDA As New MySqlDataAdapter
    Public DBDT As New DataTable
    Public BindSource As New BindingSource
    ' parameters
    Public Params As New List(Of MySqlParameter)

    ' some stats
    Public RecordCount As Integer
    Public Exception As String

    Function ExecScalar(SQLQuery As String) As Long
        Dim theID As Long
        DBcon.ConnectionString = SQLSource
        Try
            DBcon.Open()
            SQLcmd = New MySqlCommand(SQLQuery, DBcon)
            'loads params into the query
            Params.ForEach(Sub(p) SQLcmd.Parameters.AddWithValue(p.ParameterName, p.Value))

            'or like this is also good
            'For Each p As MySqlParameter In Params
            ' SQLcmd.Parameters.AddWithValue(p.ParameterName, p.Value)
            ' Next
            ' clears params
            Params.Clear()
            'return the Id of the last insert or result of other query
            theID = Convert.ToInt32(SQLcmd.ExecuteScalar())
            DBcon.Close()

        Catch ex As MySqlException
            Exception = ex.Message
            theID = -1
        Finally
            DBcon.Dispose()
        End Try
        ExecScalar = theID
    End Function

    Sub ExecQuery(SQLQuery As String)

        DBcon.ConnectionString = SQLSource
        Try
            DBcon.Open()
            SQLcmd = New MySqlCommand(SQLQuery, DBcon)
            'loads params into the query
            Params.ForEach(Sub(p) SQLcmd.Parameters.AddWithValue(p.ParameterName, p.Value))

            'or like this is also good
            'For Each p As MySqlParameter In Params
            ' SQLcmd.Parameters.AddWithValue(p.ParameterName, p.Value)
            ' Next
            ' clears params

            Params.Clear()
            DBDA.SelectCommand = SQLcmd
            DBDA.Update(DBDT)
            DBDA.Fill(DBDT)
            BindSource.DataSource = DBDT  ' DBDT will contain your database table with your records
            DBcon.Close()
        Catch ex As MySqlException
            Exception = ex.Message
        Finally
            DBcon.Dispose()
        End Try
    End Sub
    ' add parameters to the list
    Public Sub AddParam(Name As String, Value As Object)
        Dim NewParam As New MySqlParameter(Name, Value)
        Params.Add(NewParam)
    End Sub
End Class

MS SQL/Express

Public Class MSSQLDB
    ' CREATE YOUR DB CONNECTION
    'Change the datasource
    Public SQLSource As String = "Data Source=someserver\sqlexpress;Integrated Security=True"
    Private DBCon As New SqlConnection(SQLSource)

    ' PREPARE DB COMMAND
    Private DBCmd As SqlCommand

    ' DB DATA
    Public DBDA As SqlDataAdapter
    Public DBDT As DataTable

    ' QUERY PARAMETERS
    Public Params As New List(Of SqlParameter)

    ' QUERY STATISTICS
    Public RecordCount As Integer
    Public Exception As String

    Public Sub ExecQuery(Query As String, Optional ByVal RunScalar As Boolean = False, Optional ByRef NewID As Long = -1)
        ' RESET QUERY STATS
        RecordCount = 0
        Exception = ""
        Dim RunScalar As Boolean = False

        Try
            ' OPEN A CONNECTION
            DBCon.Open()

            ' CREATE DB COMMAND
            DBCmd = New SqlCommand(Query, DBCon)

            ' LOAD PARAMS INTO DB COMMAND
            Params.ForEach(Sub(p) DBCmd.Parameters.Add(p))

            ' CLEAR PARAMS LIST
            Params.Clear()

            ' EXECUTE COMMAND & FILL DATATABLE
            If RunScalar = True Then
                NewID = DBCmd.ExecuteScalar()
            End If
            DBDT = New DataTable
            DBDA = New SqlDataAdapter(DBCmd)
            RecordCount = DBDA.Fill(DBDT)
        Catch ex As Exception
            Exception = ex.Message
        End Try


        ' CLOSE YOUR CONNECTION
        If DBCon.State = ConnectionState.Open Then DBCon.Close()
    End Sub

    ' INCLUDE QUERY & COMMAND PARAMETERS
    Public Sub AddParam(Name As String, Value As Object)
        Dim NewParam As New SqlParameter(Name, Value)
        Params.Add(NewParam)
    End Sub
End Class

언급URL : https://stackoverflow.com/questions/542510/how-do-i-create-a-parameterized-sql-query-why-should-i

반응형