2015-01-09 3 views
3

SQL 인젝션의 동수 경고 :레일 내 모델의 범위를 가지고

scope :assigned_to_user, ->(user) { 
task_table = UserTask.table_name 

    joins("INNER JOIN #{task_table} 
      ON #{task_table}.user_id = #{user.id} 
      AND (#{task_table}.type_id = #{table_name}.type_id) 
      AND (#{task_table}.manager_id = #{table_name}.manager_id) 
     ") 
} 

그래서 나는이 경고를 동수 보고서를 실행 한 후 :

assigned_to_user | SQL Injection | Possible 

그래서 나는 다음과 같은 시도 :

scope :assigned_to_user, ->(user) { 
    task_table = UserTask.table_name 

     joins(ActiveRecord::Base::sanitize("INNER JOIN #{task_table} 
       ON #{task_table}.user_id = #{user.id} 
       AND (#{task_table}.type_id = #{table_name}.type_id) 
       AND (#{task_table}.manager_id = #{table_name}.manager_id) 
      ")) 
    } 

SQL 앞면과 뒷면에 ' (아포스트로피)을 추가했기 때문에이 기능이 작동하지 않습니다. 그래서 이것을 일부 결과를 반환하는 쿼리의 일부로 사용하고이 범위를 적용하면 잘못된 SQL이 생성됩니다.

scope :assigned_to_user, ->(user) { 
    task_table = UserTask.table_name 

     joins("INNER JOIN #{task_table} 
       ON #{task_table}.user_id = ? 
       AND (#{task_table}.type_id = #{table_name}.type_id) 
       AND (#{task_table}.manager_id = #{table_name}.manager_id) 
      ", user.id) 
    } 

도 문을 작성하지 않습니다 :

나는이 시도했다. 그리고 작동하지 않았고 언급 할 가치조차없는 다른 것들을 시도해 보았습니다. 아무도이 문제를 해결하는 방법을 알고 있습니까?

+0

,이 경우 동수 경고가 될 것입니다 거짓 긍정적 인 :

그냥 그냥 변수에 쿼리를 움직일 수 동수를 종료합니다 귀하의 연구에 감사드립니다. https://github.com/presidentbeef/brakeman/pull/634 – Justin

답변

3

여기에 몇 가지 연구가 끝나면 내가 사용할 것입니다. 우리가이 메서드에 테이블 이름을 전달하려는 경우

sanitize_sql_array(['user_id = :user_id', user_id: 5]) 
# => "user_id = 5" 

을 : 이라는 방법 sanitize_sql_array (ref), 당신이 좋아하는 그에게 SQL 문자열과 교체 값을 전달하여 문을 탈출하는 데 사용할 수 있습니다 또한 그것을 피할 수 있지만 ActiveRecord::Base.connection 개체의 quote 메서드를 값에 적용합니다.이 개체는 변수를 이스케이프 처리하지만 테이블 이름은 이스케이프 처리하지 않습니다. 때때로 작동 할 수도 있지만, PostgreSQL을 사용할 때 quote 메서드가 작은 따옴표를 사용하기 때문에 실패했을 수도 있지만 PostgreSQL에서는 테이블 이름에 큰 따옴표가 필요합니다.

sanitize_sql_array([ 
    'INNER JOIN :table_name ON :table_name.user_id = :user_id', 
    { table_name: 'users', user_id: 5 } 
]) 
# => "INNER JOIN 'users' ON 'users'.user_id = 5" 

connection 객체는 그들이 + 탈출 사용자 ID에 대한 sanitize_sql_array를 사용하고 있는지 확인하기 위해 별도 테이블 이름에 적용 할 수있는 방법 quote_table_name을 가지고 있습니다.

scope :assigned_to_user, -> (user) { 
    task_table = connection.quote_table_name(UserTask.table_name) 
    current_table = connection.quote_table_name(table_name) 
    sanitized_sql = sanitize_sql_array([ 
    "INNER JOIN #{task_table} 
    ON #{task_table}.user_id = :user_id 
    AND (#{task_table}.type_id = #{current_table}.type_id) 
    AND (#{task_table}.manager_id = #{current_table}.manager_id)", 
    { user_id: user.id } 
    ]) 
    joins(sanitized_sql) 
} 

또는 당신은 실제로 단지 대신 sanitize_sql_array 메소드 호출 (#{sanitize(user.id)})에있는 모든 포장의 user.idsanitize를 사용할 수 있습니다.

그런데 Brakeman은 쿼리가 변수로 옮겨 졌기 때문에 경고를 표시하지 않습니다. Brakeman은 그대로 코드를 파싱하고 변수에 대해 알지 못하므로 내용이 풍부합니다. 그래서이 모든 일은 모든 일이 도망 가고 있음을 확신시키는 것입니다. 이 선택한 답변에 따라 값을 소독하는 것이 좋다 동안

scope :assigned_to_user, -> (user) { 
    task_table = UserTask.table_name 
    query = "INNER JOIN #{task_table} 
      ON #{task_table}.user_id = #{user.id} 
      AND (#{task_table}.type_id = #{table_name}.type_id) 
      AND (#{task_table}.manager_id = #{table_name}.manager_id)" 
    joins(query) 
} 
+1

다른 모든 것은 마지막 것을 제외하고는 모두 작동했습니다. 제군은 여전히 ​​그걸 발견했습니다. 그러나 문자열을''% Q {.. query here ..}''안에 저장하면 경고를 건너 뜁니다. –