Ruby on Rails ActiveRecord

时间:2017-08-10 20:42:53

标签: ruby-on-rails ruby activerecord

我试图编写一个接受字符串数组的Ruby方法(例如,["EG", "K", "C"],并返回icao_code字段以Airport.where("icao_code LIKE ?", "#{icao_start}%")字段开头的数据库表中的所有记录那些字符串(例如,KORD,EGLL和CYVR都匹配)。数组的长度会有所不同,并且会由用户输入,因此需要对其进行清理。

如果我只搜索单个字符串,我可以执行def in_region(icao_starts) where_clause = icao_starts.map{|i| "icao_code LIKE '#{i}%'"}.join(" OR ") return Airport.where(where_clause) end 之类的操作。但是,由于我需要搜索任意数量的字符串,我无法使用该语法。

现在,我的工作原理如下:

library(plotly)
whole_dat = data.frame(x1 = rnorm(50), y1 = rnorm(50), z1 = rnorm(50))
p <-
   plot_ly() %>%
   add_markers(
   x = whole_dat$x1,
   y = whole_dat$y1,
   z = whole_dat$z1)


p = layout(p,
  scene = list(
    annotations = list(list(
      x = 0.3,
      y = -3,
      z = -0.1,
      text = "12345",
      textangle= 0,
      ax = 0,
      ay = -75,
      xref='x',
      axref='x',
      yref = 'paper',
      ayref = 'paper',
      zref = 'paper',
      #showarrow=TRUE,
      arrowcolor= "black",
      arrowsize= 3,
      arrowwidth= 1,
      arrowhead= 1
    ))
  )
)
htmlwidgets::saveWidget(as_widget(p), "test.html")

但是,我有点担心使用不受信任的用户输入这样的设置,因为我怀疑它会受到SQL注入的攻击。<​​/ p>

有更好的方法以更安全的方式获得相同的结果吗?

2 个答案:

答案 0 :(得分:1)

你可以考虑这样的事情:

def in_region(icao_starts)
  where_clause = "icao_code LIKE '#?%' OR " * icao_starts.length
  return Airport.where(where_clause.sub(/\ OR\ $/, ''), *icao_starts)
end

这将构建一个(可能很长?)字符串,其中包含?个占位符。 *icao_starts会将该数组扩展为where子句的参数,因此每个?最终都会被安全替换。 sub(/\ OR\ $/, '')只是简化了最后的OR(如果您愿意,可以附加1=0)。

如果我是你,我还会在你做任何事情之前在.uniq上执行icao_starts,在一些合理的长度上限,截断数组,并且还有一个允许值的白名单< / s>(哦,忘记了,我以为用户正在按机场代码搜索)。这应该是绝对可靠的。

答案 1 :(得分:1)

你没有将用户输入插入到SQL查询中。这很危险,使您的代码容易受到SQLI攻击。

def in_region(icao_starts)
  conditions = icao_starts.map { "icao_code LIKE ?"}
  Airport.where(conditions.join(' OR '), *icao_starts.map { |name| "#{name}%"})
end

它与bogardpd的解决方案非常相似,但是没有使用正则表达式来摆脱最后的&#34; OR&#34;