「全員」がパラメーター化された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による質問のリファレンスの1つにリンクされていました。 http://www.sommarskog.se/dynamic_sql.html
EXECの例はパラメーター化されません。このような入力による損傷を防ぐには、パラメーター化されたクエリ(一部の円で準備されたステートメント)が必要です。
';ドロップテーブルバー;-
それをfuz変数に入れてみてください(バーテーブルを評価する場合は、入れないでください)。より微妙で有害なクエリも可能です。
以下は、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インジェクションの防止に貢献している場合があります。ただし、ほとんどの場合、クエリパラメータを使用して呼び出す必要があります。そうしないと解決できません。ストアドプロシージャexclusivelyを使用する場合、アプリケーションユーザーアカウントのSELECT、UPDATE、ALTER、CREATE、DELETEなどのアクセス許可(EXEC以外のほとんどすべて)をオフにして、そのような保護を取得できます。 。
間違いなく最後のもの、すなわち.
または、もっと大規模に行う必要がありますか...? (はい、
cmd.Parameters.Add()
)
パラメータ化されたクエリには、主に2つの利点があります。
これは本当にパラメーター化されている唯一の例なので、最後の例を使用します。セキュリティ上の懸念(考えられるよりもはるかに一般的です)に加えて、渡される値が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*/}
これにより、データベースの挿入のためにデータがエスケープされます。
1つの利点は、1つの準備されたステートメントで挿入を何度も繰り返すことができ、速度の利点が得られることです。
たとえば、上記のクエリでは、ステートメントを1回準備してから、一連のデータからデータ配列を作成してループし、必要な回数だけ-> executeを繰り返します。
コマンドテキストは次のようにする必要があります。
cmdText = "SELECT foo FROM bar WHERE baz = ?"
cmdText = "EXEC foo_from_baz ?"
次に、パラメーター値を追加します。この方法では、値conが値としてのみ使用されることになりますが、他の方法では、変数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