LIKE 쿼리를 작성하려고합니다.
순수한 문자열 요구 사항이 안전하지 않다는 것을 읽었지만 안전한 LIKE 해시 쿼리를 작성하는 방법을 설명하는 문서를 찾을 수 없습니다.
가능합니까? SQL Injection을 수동으로 방어해야합니까?
답변:
쿼리 문자열이 제대로 삭제되었는지 확인하려면 배열 또는 해시 쿼리 구문을 사용하여 조건을 설명합니다.
Foo.where("bar LIKE ?", "%#{query}%")
또는:
Foo.where("bar LIKE :query", query: "%#{query}%")
그것은이 가능성이있는 경우 query
인클루드 수있는 %
문자를 당신은 위생적으로 필요 query
로 sanitize_sql_like
첫째 :
Foo.where("bar LIKE ?", "%#{sanitize_sql_like(query)}%")
Foo.where("bar LIKE :query", query: "%#{sanitize_sql_like(query)}%")
%
쿼리 문자열에서 이스케이프되지 않습니다 . 임의의 "SQL 주입"은 아니지만 여전히 예기치 않게 작동 할 수 있습니다.
%
이기 때문에 를 이스케이프하고 싶지 않습니다 . 이스케이프하면 결과는 기본적으로 일반 쿼리가됩니다. %
LIKE
%
=
query
많은 경우 LIKE 메타 문자를 사용 query
하지 않고 변수 의 문자열을 문자 그대로 일치 query
시키려고합니다. % ... %에 대한보다 현실적인 예를 들어 보겠습니다. 문자열은 경로와 같은 구조를 가지고 있으며 /users/#{user.name}/tags/%
. 내가 할 사용자 이름을 주선 이제 경우 fr%d%
, 내가 관찰 할 수 있습니다 fred
와 frida
의 태그 ...
Arel을 사용하면 다음과 같은 안전하고 이식 가능한 쿼리를 수행 할 수 있습니다.
title = Model.arel_table[:title]
Model.where(title.matches("%#{query}%"))
Model.where(title.matches("%#{query}%").not)
작동하지만 생성 된 SQL은 약간 어색합니다.WHERE (NOT (`models`.`title` LIKE '%foo%'))
Model.where(title.does_not_match("%#{query}%"))
. 생성 : WHERE (`models`.`title` NOT LIKE '%foo%')
%
신뢰할 수없는 입력 을 삭제하지 못함 : >> ActiveRecord::VERSION::STRING => "5.2.3" >> field = Foo.arel_table[:bar] >> Foo.where(field.matches('%')).to_sql => "SELECT `foos`.* FROM `foos` WHERE `foos`.`bar` LIKE '%'"
Model.where.not(title.matches("%#{query}%"))
. does_not_match
그래도 IMO는 더 잘 읽습니다.
중첩 된 연결에 대해 검색 쿼리를 수행하는 사람이있는 경우 다음을 시도하십시오.
Model.joins(:association).where(
Association.arel_table[:attr1].matches("%#{query}%")
)
여러 속성의 경우 다음을 시도하십시오.
Model.joins(:association).where(
AssociatedModelName.arel_table[:attr1].matches("%#{query}%")
.or(AssociatedModelName.arel_table[:attr2].matches("%#{query}%"))
.or(AssociatedModelName.arel_table[:attr3].matches("%#{query}%"))
)
AssociatedModelName
모델 이름 으로 바꾸는 것을 잊지 마십시오