關於Sql注入的基本概念,相信不需多說,大家都清楚,經典的注入語句是' or 1=1--
單引號而截斷字符串,“or 1=1”的永真式的出現使得表的一些信息被暴露出來,如果sql語句是select * from 的話,可能你整個表的信息都會被讀取到,更嚴重的是,如果惡意使用都使用drop命令,那么可能你的整個數據庫得全線崩潰。
當然,現在重點不是講sql注入的害處,而是說說如何最大限度的避免注入問題。
sql注入的存在在最大危害,是sql的執行語句沒有和控制語句分開,我們想要select一些東西,但用戶可能拼出' or 1=1甚至再加上delete/update/drop,后來是屬於控制語句了,所以要避免sql的注入,就必須把查詢語句與控制語句分開。
SqlParameter給我們提供了一個很好的類,有了它,我們可以不現拼接字符串,也可以不再擔心單引號帶來的慘劇,因為,這一切會有人來為我們完成的。
簡單的給個示例
傳統的查詢語句的sql可能為
string sql="select * from users where user_id='"+Request.QueryString["uid"]+"'";
很顯然,我們在這里拼接了字符串,這就給sql注入留下了可乘之機。
現在,我們要改寫這樣的語句,使用SqlParameter來做
SqlCommand SqlCmd = new SqlCommand(sql, SqlConn);
SqlParameter _userid = new SqlParameter("uid", SqlDbType.Int);
_userid.Value = Request.QueryString["u_id"];
SqlCmd.Parameters.Add(_userid);
這樣,我們可以保證外接參數能被正確的轉換,單引號這些危險的字符也會轉義了,不會再對庫造成威脅。
當然,這僅是一個示例而已,在真實的情況下,可能你還要對 Request.QueryString["u_id"]進行必要的檢測與分析,這樣才安全
所以,使用參數化的sql語句,是一種很好的做法
Dim sql As StringBuilder = New StringBuilder()
sql.Append("")
sql.Append("SELECT * FROM test")
sql.Append(" WHERE a= @p1 ")
Dim command As SqlCommand = dac.CreateCommand(sql.ToString()) 'dac為自己寫的類
Dim param As SqlParameter = New SqlParameter()
param .ParameterName = "@p1"
param .SqlDbType = SqlDbType.NVarChar
param .Value = b 'b為該函數的參數(ByVal b as String)
command .Parameters.Add(param)
Dim reader As SqlDataReader = command.ExecuteReader()
SqlParameter 構造函數
SqlParameter 構造函數 (String, SqlDbType, Int32, ParameterDirection, Byte, Byte, String, DataRowVersion, Boolean, Object, String, String, String)
初始化 SqlParameter 類的一個新實例,該類使用參數名、參數的類型、參數的長度、方向、精度、小數位數、源列名稱、DataRowVersion 值之一、用於源列映射的布爾值、SqlParameter 的值、此 XML 實例的架構集合所在的數據庫的名稱、此 XML 實例的架構集合所在的關系架構以及此參數的架構集合的名稱。
命名空間: System.Data.SqlClient
程序集: System.Data(在 system.data.dll 中)
C#
public SqlParameter (
string parameterName,
SqlDbType dbType,
int size,
ParameterDirection direction,
byte precision,
byte scale,
string sourceColumn,
DataRowVersion sourceVersion,
bool sourceColumnNullMapping,
Object value,
string xmlSchemaCollectionDatabase,
string xmlSchemaCollectionOwningSchema,
string xmlSchemaCollectionName
)
參數
parameterName
要映射的參數的名稱。
dbType
SqlDbType 值之一。
size
參數的長度。
direction
ParameterDirection 值之一。
precision
要將 Value 解析為的小數點左右兩側的總位數。
scale
要將 Value 解析為的總小數位數。
sourceColumn
源列的名稱。
sourceVersion
DataRowVersion 值之一。
sourceColumnNullMapping
如果源列可為空,則為 true;如果不可為空,則為 false。
value
一個 Object,它是 SqlParameter 的值。
xmlSchemaCollectionDatabase
此 XML 實例的架構集合所在的數據庫的名稱。
xmlSchemaCollectionOwningSchema
包含此 XML 實例的架構集合的關系架構。
xmlSchemaCollectionName
此參數的架構集合的名稱。
備注
如果未在 size 和 precision 參數中顯式設置 Size 和 Precision,則從 dbType 參數的值推斷出它們。
SqlParameter 類
表示 SqlCommand 的參數,也可以是它到 DataSet 列的映射。無法繼承此類。
有關此類型所有成員的列表,請參閱 SqlParameter 成員。
System.Object
System.MarshalByRefObject
System.Data.SqlClient.SqlParameter
[Visual Basic]
NotInheritable Public Class SqlParameter
Inherits MarshalByRefObject
Implements IDbDataParameter, IDataParameter, ICloneable
[C#]
public sealed class SqlParameter : MarshalByRefObject,
IDbDataParameter, IDataParameter, ICloneable
[C++]
public __gc __sealed class SqlParameter : public
MarshalByRefObject, IDbDataParameter, IDataParameter, ICloneable
[JScript]
public class SqlParameter extends MarshalByRefObject implements
IDbDataParameter, IDataParameter, ICloneable
線程安全
此類型的所有公共靜態(Visual Basic 中為 Shared)成員是線程安全的。但不保證任何實例成員是線程安全的。
備注
參數名稱不區分大小寫。
示例
[Visual Basic, C#, C++] 下面的示例通過 SqlDataAdapter 中的 SqlParameterCollection 集合創建 SqlParameter 的多個實例。這些參數用於從數據源中選擇數據並將數據放在 DataSet 中。此示例假定已經用適當的架構、命令和連接創建了 DataSet 和 SqlDataAdapter。
[Visual Basic]
Public Sub AddSqlParameters()
' ...
' create myDataSet and myDataAdapter
' ...
myDataAdapter.SelectCommand.Parameters.Add("@CategoryName", SqlDbType.VarChar, 80).Value = "toasters"
myDataAdapter.SelectCommand.Parameters.Add("@SerialNum", SqlDbType.Int).Value = 239
myDataAdapter.Fill(myDataSet)
End Sub 'AddSqlParameters
[C#]
public void AddSqlParameters()
{
// ...
// create myDataSet and myDataAdapter
// ...
myDataAdapter.SelectCommand.Parameters.Add("@CategoryName", SqlDbType.VarChar, 80).Value = "toasters";
myDataAdapter.SelectCommand.Parameters.Add("@SerialNum", SqlDbType.Int).Value = 239;
myDataAdapter.Fill(myDataSet);
}
[C++]
public:
void AddSqlParameters()
{
// ...
// create myDataSet and myDataAdapter
// ...
myDataAdapter->SelectCommand->Parameters->Add(S"@CategoryName", SqlDbType::VarChar, 80)->Value = S"toasters";
myDataAdapter->SelectCommand->Parameters->Add(S"@SerialNum", SqlDbType::Int)->Value = __box(239);
myDataAdapter->Fill(myDataSet);
}
[JScript] 沒有可用於 JScript 的示例。若要查看 Visual Basic、C# 或 C++ 示例,請單擊頁左上角的“語言篩選器”按鈕 。
要求
命名空間: System.Data.SqlClient
平台: Windows 98, Windows NT 4.0, Windows ME, Windows 2000, Windows XP Home Edition, Windows XP Professional, Windows Server 2003 系列, .NET Framework 精簡版
程序集: System.Data (在 System.Data.dll 中)
使用SqlParameter
SqlParameter[] p =
{
SqlHelper.MakeInParam("@EntryID",SqlDbType.Int,4,ev.EntryID),
SqlHelper.MakeInParam("@BlogID",SqlDbType.Int,4,ev.BlogID),
SqlHelper.MakeInParam("@URL",SqlDbType.NVarChar,255,DataHelper.CheckNull(ev.ReferralUrl)),
SqlHelper.MakeInParam("@IsWeb",SqlDbType.Bit,1,ev.PageViewType)
};
SqlHelper.ExecuteNonQuery(conn,CommandType.StoredProcedure,"blog_TrackEntry",p);
但我想問的是 SqlParameter
SqlParameter parm = new SqlParameter(PARM_ORDER_ID, SqlDbType.Int);
parm.Value = orderId;
因為我寫了個方法是傳遞SqlParameter類型的參數
但有時要做些判斷
像
SqlParameter parm = new SqlParameter(PARM_ORDER_ID, SqlDbType.Int);
parm.Value = orderId;
{
//添加一個參數
}
{
//如果對象存在
if (article.ID != -1)
return -1;
else
article.ID = TableHelper.GetSequence(SQLHelper.ConnectionString, "Article", "ID");
int successCount = 0;
paras[1].Value = article.Title;
paras[2].Value = article.DateAdded;
paras[3].Value = article.Text;
paras[4].Value = article.SourceUrl;
paras[5].Value = article.PostType;
paras[6].Value = article.Author;
paras[7].Value = article.Email;
paras[8].Value = article.SourceName;
paras[9].Value = article.BlogID;
paras[10].Value = article.CategoryID;
paras[11].Value = article.Summary;
paras[12].Value = article.IsBySummary;
paras[13].Value = article.DateUpdated;
paras[14].Value = article.TitleUrl;
paras[15].Value = article.FeedBackCount;
paras[16].Value = article.PostConfig;
paras[17].Value = article.EntryName;
paras[18].Value = article.KeyWord;
successCount = SQLHelper.ExecuteNonQuery(conn, CommandType.Text, SQL_THIS, paras);
return successCount;
}