【问题标题】:Anorm returning 0 results while psql returns 2 resultsAnorm 返回 0 个结果,而 psql 返回 2 个结果
【发布时间】:2015-09-22 04:20:26
【问题描述】:

我正在通过 AJAX 为搜索栏提供动力,该搜索栏传递了与数据库列相关的选定过滤器(单选按钮)和搜索栏中输入的任何内容的搜索字符串。我正在使用的 scala/play/anorm 代码是这样的:

def searchDB(searchString: String, filter: String): List[DatabaseResult] = {
DB.withConnection { implicit c =>
  SQL(
    """
      SELECT name, email, emailsecondary, picture, linkedin, title, company, companylink, companydesc, location, github, stackoverflow, twitter, blog
      FROM mailinglistperson
      WHERE {filter} LIKE '%{searchString}%'
    """).on(
          'filter -> filter,
          'searchString -> searchString
    ).as(databaseResultParser.*)
}

}

当我使用与上述异常代码同构的psql 在数据库 (PostgreSQL) 上运行查询时,它返回 2 个结果,即:

select id, name, email from mailinglistperson where company like '%kixer%';

但是当传递完全相同的值时,异常代码返回 0 个结果(我已经通过 println 验证了这些值)

编辑:当我切换异常代码以使用字符串插值时,我得到:

[error] - play.core.server.netty.PlayDefaultUpstreamHandler - Cannot invoke the action
 java.lang.RuntimeException: No parameter value for placeholder: 3

EDIT2:我还尝试将 '%...%' 与 searchString 一起传递给 LIKE,但仍然得到 0 个结果。

【问题讨论】:

  • 过滤值:你试过LIKE {searchString}searchString = '%...%"吗?这意味着 SQL 命令中没有单个刻度(它们应该被自动处理),并且在 searchString 中传递“%”
  • 关于列名:一般来说,使用命名参数将列名传入SQL是不可能的。 Anorm 似乎以某种方式支持它,但生成的 SQL 命令包含单个刻度(因为名称是“字符串参数”)。所以你可能必须嵌入列名,比如SQL(s"... where $column like {searchString}(这是简单的字符串插值,易受 SQL 注入攻击)
  • 异常混合插值SQL"... WHERE #$column = $searchString"不易受到SQL注入的影响
  • @cchantep 我只评论过,正常的字符串插值很容易受到攻击。感谢您的提示,我不知道混合插值。但是使用 Play 2.4.0 和 2.5.0 进行的快速测试表明它容易受到 SQL 注入攻击?!

标签: postgresql scala anorm


【解决方案1】:

有两个问题 - 列名和过滤器值


至于过滤器值:你必须省略SQL命令中的单个刻度,你应该在参数中传递占位符“%”。如果是字符串,刻度会自动处理。


至于列名:它就像一个字符串参数,所以再次自动处理滴答声:

[debug] c.j.b.PreparedStatementHandle - select ... from ... where 'filter' like '%aaa%'

一种解决方案:使用普通字符串插值s"""... $filter ..."""


大家一起:

SQL(
  s"""
    SELECT name, email, ...
    FROM mailinglistperson
    WHERE $filter LIKE {searchString}
  """).on(
      'searchString -> "%" + searchString + "%"
  ).as(databaseResultParser.*)

但这之前应该附有支票,例如

val validColumns = List("name", "email")
if (validColumns.contains(filter)) == false) {
  throw new IllegalArgumentException("...")
}

防止 SQL 注入。


更新

正如 cchantep 所指出的:如果使用 Anorm >= 2.4,则可以使用混合插值(对于列名和值):

SQL"... WHERE #$filter LIKE $searchString"

在这种情况下,它对 SQL 注入是部分安全的:覆盖值,覆盖列名。

更新 2

关于记录 SQL 语句,见Where to see the logged sql statements in play2?

但是当您使用 PostgreSQL 时,我建议您使用明确的来源:The PostgreSQL log: In postgresql.conf:

log_statement = 'all' # none, ddl, mod, all

然后您将在 PostgreSQL 日志文件中看到如下内容:

LOG: select * from test50 where name like $1

细节:参数:$1 = '%aaa'

【讨论】:

  • 这成功了!如果 anorm 有办法打印已编译的 SQL 代码并传递给数据库进行调试,那就太好了……是吗?
  • 我在答案中添加了一些关于记录 SQL 命令的更多信息。
猜你喜欢
  • 1970-01-01
  • 2017-02-22
  • 1970-01-01
  • 2014-12-18
  • 2015-11-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-01
  • 2015-12-28
相关资源
最近更新 更多