Rspec没有捕获错误StatementInvalid

时间:2016-11-25 12:07:37

标签: ruby-on-rails rspec rspec-rails

我试图保护自己免受SQL注入攻击,我在#where:

中使用变量作为列名
class BuildSegment::FindUsers

  def initialize(params)
    @key = User.connection.quote_column_name(params[:key])
    @negative = params[:negative]
    @pattern = params[:pattern]
  end

  def call
    if @negative
      users = User.where.not("#{@key} LIKE ?", @pattern)
    else
      users = User.where("#{@key} LIKE ?", @pattern)
    end

    users.uniq
  end
end

变量@key取自Hash,可由用户操纵。因此,例如,如果@key = "email LIKE '%' OR email"和我直接将@key传递给Active Record查询,我会得到:

SELECT "users".* FROM "users" WHERE (email LIKE '%' OR email LIKE '')

返回所有用户。我发现quote_column_name(params[:key])是一个返回ActiveRecord::StatementInvalid错误的解决方案:

ActiveRecord::StatementInvalid:
       PG::UndefinedColumn: ERROR:  column "email LIKE '%com%' OR email" does not exist
       LINE 1: SELECT DISTINCT "users".* FROM "users" WHERE ("email LIKE '%...
                                                             ^
       : SELECT DISTINCT "users".* FROM "users" WHERE ("email LIKE '%com%' OR email" LIKE '')

然而,这项测试失败了:

expect(segment_builder.call).to raise_error(ActiveRecord::StatementError)

完全回溯:

Failures:

  1) BuildSegment is protected from SQL injection
     Failure/Error: users_to_add = users.flatten

     ActiveRecord::StatementInvalid:
       PG::UndefinedColumn: ERROR:  column "email LIKE '%com%' OR email" does not exist
       LINE 1: SELECT DISTINCT "users".* FROM "users" WHERE ("email LIKE '%...
                                                             ^
       : SELECT DISTINCT "users".* FROM "users" WHERE ("email LIKE '%com%' OR email" LIKE '')
     # ./app/services/build_segment.rb:51:in `flatten'
     # ./app/services/build_segment.rb:51:in `users_passing_all_rules'
     # ./app/services/build_segment.rb:46:in `users_passing_filter'
     # ./app/services/build_segment.rb:32:in `block in users_meeting_requirements_for'
     # ./app/services/build_segment.rb:31:in `each'
     # ./app/services/build_segment.rb:31:in `users_meeting_requirements_for'
     # ./app/services/build_segment.rb:8:in `call'
     # ./spec/services/build_segment_spec.rb:107:in `block (2 levels) in <top (required)>'
     # ------------------
     # --- Caused by: ---
     # PG::UndefinedColumn:
     #   ERROR:  column "email LIKE '%com%' OR email" does not exist
     #   LINE 1: SELECT DISTINCT "users".* FROM "users" WHERE ("email LIKE '%...
     #                                                         ^
     #   ./app/services/build_segment.rb:51:in `flatten'

哪里可能是我的错误?

2 个答案:

答案 0 :(得分:1)

您的代码有两个问题:

1)错误为ActiveRecord::StatementInvalid,而非ActiveRecord::StatementError

2)您需要使用expect {}的块语法来捕获异常。有关详细信息,请参阅https://www.relishapp.com/rspec/rspec-expectations/docs/built-in-matchers/raise-error-matcher

答案 1 :(得分:0)

在我看来,您并没有正确地转发SQL。

看看这是否适合你:

{{1}}