【问题标题】:Error With Dynamically Created SQL Insert statement动态创建的 SQL 插入语句出错
【发布时间】:2011-06-26 16:52:15
【问题描述】:

我可以知道我的陈述有什么问题吗?我收到语法错误。整天都在试图找出问题所在。 :(

cmd.CommandText = "INSERT INTO LogIn(Username,Password) VALUES('" + AddUsernameTextBox.Text + "','" + AddPasswordTextBox.Text + "')";

【问题讨论】:

  • 仅供参考,您允许此代码允许 SQL 注入!!!
  • 构建后打印出字符串,看看是否符合您的预期。
  • @pacheco,你为什么要尝试一些坏事?你看到的问题不仅仅是黑客和SQL注入。也是用户在不知情的情况下在某些字段中输入引号并导致系统崩溃。那么为什么不按照他们应该的方式做事呢?
  • 您的用户名或密码是否包含单引号?
  • 你应该看看参数化查询...见csharp-station.com/Tutorials/AdoDotNet/Lesson06.aspx

标签: c# sql database ms-access oledb


【解决方案1】:
  command.CommandText = "INSERT INTO Login([Username],[Password]) VALUES(@Username, @Password)";

  //Not sure how you create your commands in your project
  //here I'm using the ProviderFactory to create instances of provider specific DbCommands.

  var parameter = dbProviderFactory.CreateParameter();
  parameter.DbType = System.Data.DbType.String;
  parameter.ParameterName = "@Username";
  parameter.Value = AddUsernameTextBox.Text;
  command.Parameters.Add(parameter);

  parameter = dbProviderFactory.CreateParameter();
  parameter.DbType = System.Data.DbType.String;
  parameter.ParameterName = "@Password";
  parameter.Value = AddPasswordTextBox.Text;
  command.Parameters.Add(parameter);

下面是使用 ConnectionStringSettings 和 DbProviderFactory 等的更完整的代码示例。这不会解决您的问题,但如果您使用 ADO.NET 核心,这是进行数据访问的方式,就像您正在做的那样在您的示例中。

  ConnectionStringSettings connectionStringSettings = ConfigurationManager.ConnectionStrings["SomeConnectionName"];
  if (connectionStringSettings == null)
    throw new Exception("Application config file does not contain a connectionStrings section with a connection called \"SomeConnectionName\"");
  DbProviderFactory dbProviderFactory = DbProviderFactories.GetFactory(connectionStringSettings.ProviderName);
  using (var dbConnection = dbProviderFactory.CreateConnection())
  {
    dbConnection.ConnectionString = connectionStringSettings.ConnectionString;
    dbConnection.Open();
    using (var command = dbConnection.CreateCommand())
    {
      command.CommandText = "INSERT INTO Login([Username],[Password]) VALUES(@Username, @Password)";

      var parameter = dbProviderFactory.CreateParameter();
      parameter.DbType = System.Data.DbType.String;
      parameter.ParameterName = "@Username";
      parameter.Value = AddUsernameTextBox.Text;
      command.Parameters.Add(parameter);

      parameter = dbProviderFactory.CreateParameter();
      parameter.DbType = System.Data.DbType.String;
      parameter.ParameterName = "@Password";
      parameter.Value = AddPasswordTextBox.Text;
      command.Parameters.Add(parameter);

      var dbTransaction = dbConnection.BeginTransaction();
      try
      {
        command.ExecuteNonQuery();
        dbTransaction.Commit();
      }
      catch (Exception)
      {
        dbTransaction.Rollback();
        throw;
      }
    }
  }

上述代码所依赖的 app.Config 文件如下所示。当然,在这种情况下,只有配置文件中的 connectionStrings 部分很重要

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <connectionStrings>
    <add name="SomeConnectionName" providerName="System.Data.OleDb" connectionString="Your Provider Specific Connection String" />
  </connectionStrings>
</configuration>

【讨论】:

    【解决方案2】:
    cmd.CommandText = "INSERT INTO LogIn([Username],[Password]) VALUES('" + AddUsernameTextBox.Text + "','" + AddPasswordTextBox.Text + "')";
    

    如果错误是由于保留关键字引起的,此代码将有所帮助:- 用户名和密码。如果不是这种情况,请引用错误。

    【讨论】:

    • 想想如果你使用这个代码,我输入密码'); DROP TABLE LogIn;--会发生什么?参数化查询是您的朋友。
    • 你不必对这里有问题怀有敌意,只要爱尔兰人。奥尼尔先生的帐户会怎样?
    • @Greg:可能不多——Access 不允许多个 SQL 语句一起运行。仍然不是一个好主意,因为升级到不修复它的 DBMS 会很糟糕。
    • @RolandTumble - 我不知道 Access,谢谢。事实上,我什至没有注意到它是 Access。我的“危险!”警笛已经响了。
    【解决方案3】:

    请保护单引号。此外,您可能需要在 Access SQL 字符串中使用结束分号。

    cmd.CommandText = "INSERT INTO LogIn(Username,Password) VALUES('" + AddUsernameTextBox.Text.Replace("'","''") + "','" + AddPasswordTextBox.Text.Replace(" '","''") + "');";

    使用参数化查询当然只有 100% 好;你的其他问题是这个 C#/Visual Studio 通过 OLE/Jet 针对 MS Access 吗?

    【讨论】:

    • 是的,它是 Visual Studio 中的 C# 和通过 OLE 的 MS Access。试过你的说法,但我仍然收到语法错误:(
    • @Pac - 请查看针对问题的评论
    【解决方案4】:

    最好的方法是使用参数:'@' 这样,您的代码将看起来更加清晰易懂。并使您的应用程序更加安全。

    试试这个代码:

                using (var con = new OleDbConnection(_constring))
                {
                    con.Open();
                    using (
                        var cmd =
                            new OleDbCommand(
    "UPDATE LogIn SET Username=@Username, Password=@Password WHERE (ID = @Id)",
                                con))
                    {
                        try
                        {
    
                            cmd.Parameters.AddWithValue("@Username",EditUsernameTextBox.Text);
                            cmd.Parameters.AddWithValue("@Password",EditPasswordTextBox.Text);
                            cmd.Parameters.AddWithValue("@Id",IDTextBox.Text);
    
    
                            cmd.ExecuteNonQuery();
                        }
                        catch (Exception ex)
                        {
                            throw;
                        }
                        finally
                        {
                            con.Close();
                        }
    
                    }
    

    问候!

    【讨论】:

    • AFAIK 您不能将命名参数与 Jet(OP 标记为 ms-access)和 OLEDB 一起使用,您必须用问号替换参数并按照它们出现的顺序引用它们。
    【解决方案5】:

    EditUsernameTextBox.TextEditPasswordTextBox.Text 的值本身是否有引号?这将增加 SQL。

    如果是这样,您需要逃脱它们。或者不要使用已经指出的字符串连接......

    您是否按照要求打印了该声明以查看它的外观...?

    【讨论】:

    • 如何打印报表?对不起这里的新手
    • 你可以在Visual Studio中使用即时窗口,我想这就是你正在使用的。
    【解决方案6】:

    如果您的 ID 不是数字,您错过了一对撇号:

    WHERE (ID ='" + IDTextBox.Text + "')";
    

    【讨论】:

    • 语法错误仍然存​​在。会不会是因为我的 ID DataType 是 AutoNumber?
    • 如果 ID 是自动编号,它是数字并且不需要引号,它不会导致您的语句失败。按要求打印声明并张贴。
    【解决方案7】:

    检查这是否有效。您在 WHERE 语句中缺少值的单引号:

    "UPDATE
        LogIn
    SET
        Username = '" + EditUsernameTextBox.Text + "'
        ,Password = '" + EditPasswordTextBox.Text + "'
    WHERE
        (ID = '" + IDTextBox.Text + "')";
    

    另外,正如 Daniel White 所说,确保您处理好任何 SQL 注入。

    【讨论】:

    • 仍然收到语法错误:/可能是因为我的 ID DataType 是 AutoNumber 吗?
    • 你能提供你传入的数据吗?您是否传递了带有撇号(单引号)或任何其他可能有问题的字符的内容?
    • 我在文本框中输入了所有字母
    • 这至少是一个问题。如果您尝试将自动编号字段与字母字符进行比较,则会收到错误消息。尝试从 WHERE 子句中删除单引号,然后输入数字进行测试。否则,您的查询在语法上基本上是合理的。
    【解决方案8】:

    很可能,IDTextBox.text 中的值不是数字...

    但就像 Daniel 指出的那样,这很容易受到 SQL 注入的攻击。

    如果我输入会发生什么:

    ' ; DROP TABLE login
    

    在 EditUserNameTextBox 字段中

    【讨论】:

    • 它会失败。 Access 不会运行多个语句,但我在狡辩:)
    • 谢谢 Remou,我不知道。只是想举一个例子说明 SQL 注入有多危险
    • 使用 Jet/ACE,它不是很危险,因为没有 DDL 或 DML 语句可以通过 WHERE 子句注入。但是,可以更改操作的行数,这在使用 SQL UPDATE 的情况下可能很危险。有关 Access 的详细信息,请参阅stackoverflow.com/questions/512174/non-web-sql-injection/…
    • 我猜 ' -- 会很危险,有效地清空所有用户名字段...但是不要自己使用访问权限
    • 呃,'-- 在 Access 中会有什么危险?这在 Jet/ACE/Access SQL 中没有任何特别之处,因此您只需传递不会返回任何行的标准。
    【解决方案9】:

    ID 列是整数吗?如果不是,您也需要将值用单引号括起来。 另外,请尝试删除括号。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-10
      • 2018-12-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多