1

SQL インジェクションに対する従来の ASP 保護から SQL インジェクションに対する保護に大きな助けを得た後、パラメーター化されたクエリを使用しても解決できない大きな問題に遭遇しました。

name = Trim(Request.QueryString("name"))
flds = Trim(Request.QueryString("flds"))
sql = "set rowcount 0 select " & flds & " from [TABLE] where Name = '" & name & "'"

私が理解していることから、パラメーター化されたクエリは、WHERE 句 (この場合はnameフィールド.

fldsユーザーが返したいパラメーターのコンマ区切りリストです。明らかなように、 SQL インジェクションに対して非常に脆弱です。

コードを保護するために必要な 1 つのアイデアは、静的に生成された有効なフィールドの辞書を作成し、flds文字列を "," で分割し、辞書に対して各値を検証し、すべてのフィールドで構成される SQL クエリを作成することです。辞書に存在します。

この方法はセキュリティのために機能しますが、データベースに変更が加えられるたびに静的リストを変更する必要があるように思えます (ただし、それらはまれです)。

このコードを SQL インジェクション攻撃から保護するためのより良い/適切な方法はありますか?

4

4 に答える 4

2

SQL Server で分割関数を作成します (新しいバージョンにはより良い関数がありますが、これは SQL Server 2000 で得られるものです)。

CREATE FUNCTION dbo.SplitStrings
(
   @List       NVARCHAR(4000),
   @Delimiter  CHAR(1)
)
RETURNS @Items TABLE
(
   Item NVARCHAR(4000)
)
AS
BEGIN
   DECLARE
       @Item VARCHAR(12),
       @Pos  INT;

   WHILE LEN(@List)>0
   BEGIN
       SET @Pos = CHARINDEX(@Delimiter, @List);

       IF @Pos = 0
           SET @Pos = LEN(@List)+1;

       SET @Item = LEFT(@List, @Pos-1);

       INSERT @Items SELECT LTRIM(RTRIM(@Item));

       SET @List = SUBSTRING(@List, @Pos + LEN(@Delimiter), LEN(@List));

       IF LEN(@List) = 0 BREAK;
   END
   RETURN;
END
GO

次に、ストアド プロシージャを作成します。

CREATE PROCEDURE dbo.RunScaryQuery
  @columns NVARCHAR(4000),
  @table   NVARCHAR(255)
AS
BEGIN
  SET NOCOUNT ON;

  DECLARE @collist NVARCHAR(4000), @sql NVARCHAR(4000);

  SELECT @collist = COALESCE(@collist + ',', '') + c.name 
    FROM syscolumns AS c
    INNER JOIN dbo.SplitStrings(@columns, ',') AS s
    ON s.Item = c.name
    WHERE c.id = OBJECT_ID(@table);

  SELECT @sql = 'SELECT ' + @collist + ' FROM ' + @table
  -- where ...
  ;

  EXEC sp_executesql @sql;
END
GO

次に、適切にパラメーター化されたコマンド オブジェクトを使用して、ASP からそのストアド プロシージャを呼び出します。

これにより、テーブルに実際に存在する列名のみを使用して SQL クエリが生成されるようになります。(意味のないものは無視されます。)

これは、リストに少なくとも 1 つの有効な列名を取得することを前提としています。

于 2012-06-13T19:22:29.403 に答える
0

うーん...だから私は別の解決策を取ります。

私は最初にすべての有効なフィールドを返すSQLクエリを持っています

select
   tcol.name
from
  sysObjects tobj
  join syscolumns tcol on tobj.id = tcol.id
where
  tobj.xtype = 'U'
  and tobj.name = '[TABLE]'

次に、@peterによって提案されたようにすべての要素を検証します。次に、検証されたすべてのパラメーターを使用してクエリ文字列が作成され、2番目のクエリで名前がパラメーターとして渡されます。

これにより、データベースのオーバーヘッドと負担が最小限に抑えられるようです。

于 2012-06-13T20:06:06.007 に答える
0

私は家にいて、テストするデータベースはありませんが、これで十分です

name = Trim(Request.QueryString("name"))
flds = split(Trim(Request.QueryString("flds")),",")
sql = "set rowcount 0 select * from [TABLE] where Name = '" & name & "'"
set oRst = oConn.execute(sql)
on error resume next
do while not oRst.eof
  result    = ""
  separator = ""
  for each field in flds
    for each requested_field in flds
      if uCase(field.name) = uCase(trim(requested_field)) then
        result = result & separator & field.value
        separator = ","
      end if
    next
  next
  response.write result & "<br>"
  oRst.movenext
loop
于 2012-06-13T19:33:22.933 に答える
-1

http://www.userfriendlythinking.com/Blog/BlogDetail.asp?p1=7013&p2=119&p7=3001をご覧ください。

これは、パラメーター化されたクエリの使用法を示しています。

于 2012-06-14T11:06:35.170 に答える