English 中文(简体)
Does this code prevent SQL injection?
原标题:

Background

I ve been contracted to analyze an existing Data Provider and I know the following code is faulty; but in order to point out how bad it is, I need to prove that it s susceptible to SQL injection.

Question

What "Key" parameter could break the PrepareString function and allow me to execute a DROP statement?

Code Snippet

Public Shared Function GetRecord(ByVal Key As String) As Record
    Dim Sql As New StringBuilder()

    With Sql
        .Append("SELECT * FROM TableName")
        If String.IsNullOrEmpty(Agency) Then
            .Append(" ORDER BY DateAdded")
        Else
            .Append(" WHERE Key =  ")
            .Append(PrepareString(Key))
            .Append(" ")
        End If
    End With

    Return ExecuteQuery(Sql.ToString())
End Function

Public Shared Function PrepareString(ByVal Value As String) As String
    Return Value.Replace("  ", " ") _
                .Replace(" ", "  ") _
                .Replace("`", "  ") _
                .Replace("´", "  ") _
                .Replace("--", "")
End Function
最佳回答

In answer to your direct question: Does this code prevent SQL injection: No

Here s the proof - push this string through the PrepareString method:

Dim input = " " & Chr(8) & "; Drop Table TableName; - " & Chr(8) & "-"
Dim output = PrepareString(input)

Console.WriteLine(input)
Console.WriteLine(output)

I modified the GetRecord method you posted to return the fully prepared SQL string rather than get the record from the database:

Console.WriteLine(GetRecord(output))

And this is the output

Input  = ; Drop Table TableName; --
Output =  ; Drop Table TableName; --
Query  = SELECT * FROM TableName WHERE Key =   ; Drop Table TableName; -- 

Add 1 extra line of code:

My.Computer.Clipboard.SetText(input)

And you ve got the string you need copied right to your clipboard to paste into your input field on the website to complete your SQL injection:

 ; Drop Table TableName; - -

[Noting that the control characters have been omitted from the post output by StackOverflow, so you ll have to follow the code example to create your output]

After the PrepareString method is run, it will have the exact same output - the Chr(8) ASCII code is the backspace which will remove the extra " " that you re appending to mine which will close your string and then I m free to add whatever I want on the end. Your PrepareString doesn t see my -- because I m actually using - - with a backspace character to remove the space.

The resulting SQL code that you re building will then execute my Drop Table statement unhindered and promptly ignore the rest of your query.

The fun thing about this is that you can use non-printable characters to basically bypass any character check you can invent. So it s safest to use parameterized queries (which isn t what you asked, but is the best path to avoid this).

问题回答

To answer your questionable question, no it wouldn t work.

.Replace("``", " ") would prevent legitimate queries with `

.Replace("´", " ") would prevent legitimate queries with ´

.Replace("--", "") would prevent legitimate queries with -- in them

.Replace(" ", " ") would incorrectly modify legitimate queries with in them

and so on.

Furthermore, the full set of escape characters can vary from one RDBMS to another. Parameterized queries FTW.

I think it s safe (at least in SQL server), and I also think the only thing you actually need to do is s = s.Replace(" ", " "). Of course you should use parameterized queries, but you already know that.

I think it is unhackable if you just replace with . I have heard that it is possible to change the escape quote character, which could potentially break this, however I am not sure. I think you are safe though.

This MSDN article covers most of the stuff you need to look out for (I m afraid to say all when it comes to SQL injection).

But I will echo everyone else s sentiment of parameters parameters parameters.

As for your example some gotchas [Edit: Updated these]:

  • wouldn t the string "1 OR 1=1" allow the user to get back everything

  • or worse "1; drop table sometablename"

According to the article you want to check for:

; - Query delimiter.

- Character data string delimiter.

-- - Comment delimiter.

/* ... / - Comment delimiters. Text between / and */ is not evaluated by the server.

xp_ - Used at the start of the name of catalog-extended stored procedures, such as xp_cmdshell.

You are trying to black list characters to implement your own version of SQL Escaping. I would suggest reviewing this URL - SQL escaping is not necessarily the worst choice (i.e. quickly fixing existing apps) but it needs to be done right to avoid vulnerabilities.

That URL links to another page for escaping in SQL Server where the author gives suggestions that help you avoid vulnerabilities without limiting functionality.

If it helps, the articles suggest escaping braces too (I call them square brackets - but []).





相关问题
Manually implementing high performance algorithms in .NET

As a learning experience I recently tried implementing Quicksort with 3 way partitioning in C#. Apart from needing to add an extra range check on the left/right variables before the recursive call, ...

Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

How do I compare two decimals to 10 decimal places?

I m using decimal type (.net), and I want to see if two numbers are equal. But I only want to be accurate to 10 decimal places. For example take these three numbers. I want them all to be equal. 0....

Exception practices when creating a SynchronizationContext?

I m creating an STA version of the SynchronizationContext for use in Windows Workflow 4.0. I m wondering what to do about exceptions when Post-ing callbacks. The SynchronizationContext can be used ...

Show running instance in single instance application

I am building an application with C#. I managed to turn this into a single instance application by checking if the same process is already running. Process[] pname = Process.GetProcessesByName("...

How to combine DataTrigger and EventTrigger?

NOTE I have asked the related question (with an accepted answer): How to combine DataTrigger and Trigger? I think I need to combine an EventTrigger and a DataTrigger to achieve what I m after: when ...

热门标签