Rspec 未捕获错误 StatementInvalid
Rspec is not catching error StatementInvalid
我试图保护自己免受 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 '')
其中 returns 所有用户。我发现 quote_column_name(params[:key])
作为 returns 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'
我的错误在哪里?
在我看来你没有正确转义 SQL。
看看这是否适合你:
User.where.not("#{@key} LIKE ?, '#{@pattern}'")
User.where("#{@key} LIKE ?, '#{@pattern}'")
您的代码有两个问题:
1)错误是ActiveRecord::StatementInvalid
,不是ActiveRecord::StatementError
,而是
2) 您需要使用expect {}
的块语法来捕获异常。有关详细信息,请参阅 https://www.relishapp.com/rspec/rspec-expectations/docs/built-in-matchers/raise-error-matcher。
我试图保护自己免受 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 '')
其中 returns 所有用户。我发现 quote_column_name(params[:key])
作为 returns 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'
我的错误在哪里?
在我看来你没有正确转义 SQL。
看看这是否适合你:
User.where.not("#{@key} LIKE ?, '#{@pattern}'")
User.where("#{@key} LIKE ?, '#{@pattern}'")
您的代码有两个问题:
1)错误是ActiveRecord::StatementInvalid
,不是ActiveRecord::StatementError
,而是
2) 您需要使用expect {}
的块语法来捕获异常。有关详细信息,请参阅 https://www.relishapp.com/rspec/rspec-expectations/docs/built-in-matchers/raise-error-matcher。