ruby-on-rails-4 - con - desinfectante
La mejor forma de desinfectar la entrada del usuario en los rieles (2)
Debido a que siempre aprecio cuando encuentro la fuente de conocimiento y el código en cualquier respuesta SO, lo proporcionaré para esta pregunta.
Tanto ActiveRecord como ActionController proporcionan métodos para desinfectar la entrada de SQL.
Específicamente desde ActiveRecord::Sanitization::ClassMethods
tiene sanitize_sql_for_conditions y sus otros dos alias : sanitize_conditions y sanitize_sql . Los tres hacen literalmente exactamente lo mismo.
sanitize_sql_for_conditions
Acepta una matriz, hash o cadena de condiciones SQL y las desinfecta en un fragmento SQL válido para una cláusula WHERE .
Sin embargo, en ActiveRecord también tiene
sanitize_sql_for_assignment
que
Acepta una matriz, hash o cadena de condiciones de SQL y las desinfecta en un fragmento SQL válido para una cláusula SET .
- Tenga en cuenta que estos métodos están incluidos en ActiveRecord :: Base y, por lo tanto, están incluidos por defecto en cualquier modelo de ActiveRecord .
Por otro lado, en ActionController tienes ActionController::Parameters
que te permite
elegir qué atributos deben incluirse en la lista blanca para la actualización masiva y así evitar la exposición accidental de lo que no debe exponerse. Proporciona dos métodos para este propósito: requerir y permitir .
params = ActionController::Parameters.new(user: { name: ''Bryan'', age: 21 })
req = params.require(:user) # will throw exception if user not present
opt = params.permit(:name) # name parameter is optional, returns nil if not present
user = params.require(:user).permit(:name, :age) # user hash is required while `name` and `age` keys are optional
Los parámetros magic se llaman Strong Parameters, docs aquí .
Espero que eso ayude a cualquiera, ¡solo para aprender y desmitificar a Rails! :)
He leído mucho sobre esto y sé que hay muchas preguntas relacionadas aquí, pero no pude encontrar una guía definitiva sobre cómo desinfectar todo. Una opción es desinfectar la inserción, por ejemplo, tengo lo siguiente en mi modelo
before_validation :sanitize_content, :on => :create
def sanitize_content
self.content = ActionController::Base.helpers.sanitize(self.content)
end
¿Debo ejecutar esto en cada campo en cada modelo? Supongo que: on =>: create también debería eliminarse para que se ejecute cuando las actualizaciones también?
La otra opción es desinfectar cuando los datos se muestran en vistas, usando simple_format, o .html_safe o sanitize (fieldname). ¿Debería desinfectar todos mis puntos de vista para cada campo, así como en el inserto? Tener que hacer esto manualmente en todas partes no parece muy complicado
Gracias por cualquier ayuda
TL; DR
Con respecto a las consultas y las consultas de los usuarios: asegúrese de usar siempre los métodos de consulta de registros activos (como .where
) y evite pasar parámetros usando la interpolación de cadenas; pasarlos como valores de parámetros hash, o como sentencias parametrizadas.
En cuanto a la representación de contenido html / javascript potencialmente inseguro generado por el usuario: a partir de Rails 3, el texto html / javascript se escapa automáticamente para que aparezca como texto sin formato en la página, en lugar de interpretarse como html / javascript, por lo que no necesita para desinfectar explícitamente (o use <%= h(potentially_unsafe_user_generated_content)
%>
Si lo entiendo correctamente, no necesita preocuparse por desinfectar los datos de esta manera, siempre y cuando utilice los métodos de consulta de registros activos correctamente. Por ejemplo:
Digamos que nuestro mapa de parámetros se ve así, como resultado de que un usuario malintencionado ingrese la siguiente cadena en el campo user_name
:
:user_name => "(select user_name from users limit 1)"
La mala manera (no hagas esto):
Users.where("user_name = #{params[:id}") # string interpolation is bad here
La consulta resultante se vería así:
SELECT `users`.* FROM `users` WHERE (user_name = (select user_name from users limit 1))
La interpolación directa de cadenas de esta manera colocará los contenidos literales del valor del parámetro con la clave :user_name
en la consulta sin desinfección. Como probablemente sepa, la entrada del usuario malicioso se trata como simple ''SQL y el peligro es bastante claro.
El buen camino (haz esto):
Users.where(id: params[:id]) # hash parameters
O
Users.where("id = ?", params[:id]) # parameterized statement
La consulta resultante se vería así:
SELECT `users`.* FROM `users` WHERE user_name = ''(select user_name from users limit 1)''
Como puede ver, Rails de hecho lo desinfecta, siempre y cuando pase el parámetro como un hash o parámetro de método (dependiendo del método de consulta que esté usando).
El caso para la desinfección de datos en la creación de nuevos registros de modelo en realidad no se aplica, ya que los métodos new
o create
esperan un hash de valores. Incluso si intentas insertar código SQL inseguro en el hash, los valores del hash se tratan como cadenas simples, por ejemplo:
User.create(:user_name=>"bobby tables); drop table users;")
Resultados en la consulta:
INSERT INTO `users` (`user_name`) VALUES (''bobby tables); drop table users;'')
Entonces, la misma situación que arriba.
Espero que eso ayude. Avíseme si he omitido o entendido mal algo.
Editar Con respecto al escape de html y javascript, la versión corta es que ERB "escapa" el contenido de su cadena por usted para que se trate como texto sin formato. Puede hacer que se trate como html si realmente lo desea, haciendo your_string_content.html_safe
.
Sin embargo, simplemente hacer algo como <%= your_string_content %>
es perfectamente seguro. El contenido se trata como una cadena en la página. De hecho, si examina el DOM con Chrome Developer Tools o Firebug, debería ver las comillas alrededor de esa cadena.