flawopen.com/Ruby의 SQL Injection/ActiveRecord where()
Rails where() 문자열 보간은 안전할까요?
참고 페이지
간단한 답변
SQL을 지침은 고정되어 있고 값을 넣는 빈칸이 있는 양식이라고 생각해 보세요. 바인딩 매개변수는 빈칸만 채우지만, Ruby 보간은 Rails가 둘을 구분하기 전에 요청 문자열을 지침에 써 넣습니다. SQL 구조를 고정하고 신뢰할 수 없는 값은 매개변수로 전달하세요.
UNSAFE
User.where(
"id = #{params[:id]}"
)
SAFE
User.where(id: params[:id])
# or, for more complex conditions:
User.where("id = ?", params[:id])
보간이 쿼리를 바꾸는 이유
Active Record가 조건을 받기 전에 Ruby가 #{...}를 평가합니다. 예를 들어 where("id = #{params[:id]}")는 이미 합쳐진 SQL 문자열을 Rails에 전달하므로 요청 입력이 조건식을 바꿀 수 있습니다. Active Record 문서는 이러한 문자열 조립 방식을 안전하지 않다고 설명합니다. 지원되는 동등·범위·부분집합 조건에는 해시를, 그 외 조건에는 ? 자리표시자를 사용하세요. 자리표시자는 값만 바인딩하며 식별자나 SQL 키워드는 바인딩하지 않습니다. 쿼리 구조를 고정하거나 엄격한 허용 목록에서 식별자를 선택하세요.
코드베이스 확인 방법
rg -n 'where\s*\(' app/조건 문자열 안에 요청 데이터가 보간되거나 연결되는 부분이 있는지 검색 결과를 확인하세요. Brakeman은 분석에서 위험한 데이터 흐름을 찾으면 SQL Injection 위험을 보고합니다. 경고가 없다고 모든 쿼리가 안전하다는 뜻은 아닙니다.
자주 묻는 질문
모든 쿼리에 해시 조건을 사용할 수 있나요?
아니요. Rails 해시 조건은 동등, 범위, 부분집합(IN) 검사를 지원합니다. 다른 조건에는 where("price > ?", amount)처럼 SQL 구조를 고정하고 값을 바인딩하세요. 바인딩은 값을 보호하지만 동적 테이블·열 이름이나 SQL 조각을 안전하게 만들지는 않습니다.