直接执行SQL是错误的应用程序设计吗?

直接执行SQL是错误的应用程序设计吗?,sql,stored-procedures,ios,Sql,Stored Procedures,Ios,我正在开发一个iOS应用程序,它是另一个项目的管理员/查看器。其想法是,该应用程序将能够将存储在数据库中的数据处理成多种可视化效果——总体效果与之类似。我让可视化完全由用户配置:用户定义她想要看到的内容并添加限制 例如,她可能会指定在过去三周内用当前活跃且不在美国的用户帐户绘制一个指标 我的问题是,我能想到的唯一设计是或多或少地将直接SQL从iOS应用程序传递到后端服务器,以针对数据库执行。我知道这是一种不好的做法,一切都应该用存储过程来编写。但除此之外,我如何保持足够的灵活性来保留完全用户定义

我正在开发一个iOS应用程序,它是另一个项目的管理员/查看器。其想法是,该应用程序将能够将存储在数据库中的数据处理成多种可视化效果——总体效果与之类似。我让可视化完全由用户配置:用户定义她想要看到的内容并添加限制

例如,她可能会指定在过去三周内用当前活跃且不在美国的用户帐户绘制一个指标

我的问题是,我能想到的唯一设计是或多或少地将直接SQL从iOS应用程序传递到后端服务器,以针对数据库执行。我知道这是一种不好的做法,一切都应该用存储过程来编写。但除此之外,我如何保持足够的灵活性来保留完全用户定义的查询呢


虽然应用程序确实组成了SQL,但直接SQL永远不会被用户看到或注入。这些都是在UIDateTimeChooser、UIPickerViews等中抽象出来的。

如果你想让用户发送实际的sql,试着过滤“删除并截断”之类的词。如果你必须允许删除,你可以强制他们使用主键。

编辑:我不喜欢这里的答案。我同意下面的一些评论,我建议您在客户机上构建“查询”对象,并将其传递给web服务,该服务使用准备好的语句构造SQL语句。这对于SQL注入是安全的,因为您使用的是预处理语句,并且您可以控制您所控制的web服务中正在构造的内容的安全性

编辑结束

执行从客户机传递的SQL没有什么问题。尤其是在查询构建的情况下

例如,您可以通过将where子句与“AND”连接来添加尽可能多的where子句。但是,您不应该允许用户指定SQL是什么。相反,您应该提供一个允许用户生成查询的界面。这有几个好处:

  • 更好的用户体验(除了开发人员,谁还想编写SQL?)
  • 注射更安全。您根本不可能过滤掉所有危险的SQL字符串
  • 除此之外,执行动态SQL而不是使用存储过程是绝对正确的。你认为
    一切都应该用存储过程来编写的观点对我来说似乎是错误的。当然,存储过程在很多方面都很好,但是使用它们也有很多缺点

    事实上,过度使用存储过程有时会导致性能问题,因为开发人员在多个位置重用同一存储过程,即使他们不需要它返回的所有数据


    不过,您可能需要研究的一件事是在服务器端构建SQL,并传递所构建查询的某种内部表示。如果您有某种公开的web服务,并允许您的客户机运行它想要运行的任何SQL,那么您就有一个安全问题。这也有助于版本控制。如果您修改数据库,就可以使用它修改web服务,而不用担心使用旧客户端构建无效SQL的人。

    我认为这种完全由用户配置的可视化更像是构建块。
    我不会将直接sql查询传递到后端。我会让用户发送参数(要使用的wich视图、where子句中的过滤器,等等)。但是让用户注入sql这是一个潜在的噩梦(无论是安全还是维护)

    只要您知道注入问题,应用程序向数据库发送sql命令并没有错。所以不要在你的代码中这样做:

    (Pseudocode)
    
    String sqlCommand = "SELECT something FROM YOURTABLE WHERE A='" + aTextInputFieldInYourGui + "'";
    cmd.execute(sqlCommand);
    
    为什么不呢?查看如果用户在GUI中的ATExtInputField中输入此行会发生什么
    “从表格中删除*转到选择”
    (这里假设您的数据库是MS SQL Server,对于其他RDBMS,语法略有不同)

    改为使用准备好的语句和参数绑定

    (Pseudocode)
    String sqlCommand = "SELECT something FROM YOURTABLE WHERE A=?";
    cmd.prepare(sqlCommand);
    cmd.bindParam(1, aTextInputFieldInYourGui);
    cmd.execute();
    

    关于

    数据库中的所有数据是否对所有用户都可用,还是只允许每个用户访问数据的子集?如果是后者,仅将数据库登录限制为只读访问是不足以保护数据的

    举个简单的例子,用户可能会破坏您的界面,以便提交查询
    SELECT password,从登录名为'admin'
    的用户处获取salt,劫持响应以获取原始数据,并强制输入您的管理员密码。随着应用程序的普及,恶意用户池的增长超过了线性增长,直到最终他们的集体智慧超过你的团队;你不应该把自己置于成功就是失败的境地

    您可以接受客户端应用程序发送的SQL查询,并尝试在服务器端对其进行解析,以便对查询应用适当的限制,也就是说,将用户隔离。但要做到这一点,需要在服务器代码中编写一个小型SQL解析器,谁愿意做这些工作呢?编写能够编写SQL的代码要比编写能够读取SQL的代码容易得多

    我的团队为一个相当复杂的web应用程序中的报告界面解决了一个类似的问题,我们的方法是这样的:

    由于您已经打算使用图形界面来构建查询,因此将界面元素中的原始数据转换为表示用户输入(以及查询)的数据结构将相当容易。例如,用户可以使用您的界面指定一个条件,即他们希望结果仅限于2010年5月5日除John以外的所有人收集的结果。(假设John的
    UserID
    为3。)使用我的团队使用的JSON格式的变体,您只需将UI中的数据撕成如下内容:

    { "ConditionType": "AND",
      "Clauses": [
        { "Operator": "Equals",
          "Operands": [
            { "Column": "CollectedDate" },
            { "Value": "2010-05-05" }
          ]
        },
        { "Operator": "NotEquals",
          "Operands": [
            { "Column": "CollectedByUserID" },
            { "Value": 3 }
          ]
        }
      ]
    }
    
    在客户端,创建这个k