2009-12-07 9 views
9
public static bool TruncateTable(string dbAlias, string tableName) 
{ 
    string sqlStatement = string.Format("TRUNCATE TABLE {0}", tableName); 
    return ExecuteNonQuery(dbAlias, sqlStatement) > 0; 
}
+2

quién está autorizado a llamar TruncateTable? – FrustratedWithFormsDesigner

+1

No, en absoluto. Necesitas usar consultas parametrizadas para estar seguro. http://www.c-sharpcorner.com/UploadFile/puranindia/ParameterizedQuerySQLInjectionAttacks08102009011903AM/ParameterizedQuerySQLInjectionAttacks.aspx –

+1

¡No permitiría, en general, que una interfaz de usuario llame a la tabla truncada! Si necesita hacer esto, es muy probable que tenga un defecto de diseño serio. – HLGEM

Respuesta

22

La recomendación más común para combatir la inyección SQL es utilizar un parámetro de consulta SQL (varias personas en este hilo lo han sugerido).

Esta es la respuesta incorrecta en este caso. No puede usar un parámetro de consulta SQL para un nombre de tabla en una declaración DDL.

Los parámetros de consulta SQL solo se pueden usar en lugar de un valor literal en una expresión SQL. Esto es estándar en cada implementación de SQL.

Mi recomendación para proteger contra la inyección de SQL cuando tienes un nombre de tabla es validar la cadena de entrada con una lista de nombres de tabla conocidos.

Usted puede obtener una lista de nombres de tabla válidos desde el INFORMATION_SCHEMA:

SELECT table_name 
FROM INFORMATION_SCHEMA.Tables 
WHERE table_type = 'BASE TABLE' 
    AND table_name = @tableName 

Ahora usted puede pasar su variable de entrada a esta consulta como un parámetro de SQL. Si la consulta no devuelve filas, sabrá que la entrada no es válida para usar como tabla. Si la consulta devuelve una fila, coincide, por lo que tiene más seguridad de que puede usarla de manera segura.

También puede validar el nombre de la tabla con una lista de tablas específicas que defina como correctas para que su aplicación se trunque, como @John Buchanan suggests.

Incluso después de validar que tableName existe como un nombre de tabla en su RDBMS, también sugiero que se delimite el nombre de la tabla, en caso de que utilice nombres de tabla con espacios o caracteres especiales. En Microsoft SQL Server, los delimitadores de identificador por defecto están entre corchetes:

string sqlStatement = string.Format("TRUNCATE TABLE [{0}]", tableName); 

Ahora sólo estás en riesgo de inyección de SQL si tableName coincide con una mesa real, y en realidad se utilizan corchetes en los nombres de sus tablas!

+2

Validar en contra de conocer posibles entradas. +1 – Greg

+0

Creo que mucha gente olvidó que no puede usar consultas parametrizadas con este tipo de consulta. Buena observación. –

+1

El OP también debería considerar la posibilidad de que dos o más tablas tengan el mismo nombre pero pertenezcan a diferentes propietarios/esquemas. – MartW

1

Usar consultas parametrizadas.

+3

¿De un nombre de tabla? ¿Tienes algunos enlaces para apoyar esto? –

+1

Una respuesta extrañamente correcta pero pobre. Un pequeño ejemplo basado en el código OP sería mucho mejor. – AnthonyWJones

+0

Es cierto, pero la gente realmente debería entender los peligros de dejar pasar CUALQUIER cadena en una consulta sin usar consultas parametrizadas. No tuve tiempo para escribir un ejemplo de código, pero él debería saber sobre ellos. –

2

Utilice un procedimiento almacenado. Cualquier biblioteca db decente (MS Enterprise Library es lo que uso) manejará escapando los parámetros de cadena correctamente.

Además, re: consultas parametrizadas: prefiero NO tener que volver a implementar mi aplicación para solucionar un problema de base de datos. Almacenar consultas como cadenas literales en su fuente aumenta la complejidad del mantenimiento.

+0

Si no desea volver a implementarlo, hágalo correctamente en primer lugar y pruébelo. –

+4

¿Por qué no pensé en eso? Mientras estoy en eso, dejaré de poner todos esos estúpidos errores que he codificado durante todos estos años. Además, genius, * deploy * puede significar muchas cosas, como pasar de una caja local a un servidor de desarrollo. Interrumpir a otros desarrolladores por rebuild/redploy to dev puede ser una gran interrupción. –

+1

También puede ser perturbador implementar una nueva revisión de un procedimiento almacenado. –

-2

Puede usar SQLParameter para pasar el valor de tableName. Por lo que sé y he probado, SQLParameter se ocupa de la verificación de todos los parámetros y, por lo tanto, deshabilita la posibilidad de inyección.

-4

Si no puede usar las consultas parametrizadas (y debería hacerlo) ... una simple sustitución de todas las instancias de 'con' 'debería funcionar.

string sqlStatement = string.Format("TRUNCATE TABLE {0}", tableName.Replace("'", "''")); 
+1

difícilmente, ¿qué pasa con '-' – CaffGeek

+0

tienes razón. en realidad, hay una serie de cosas que necesitan ser reemplazadas (ej. '; -,/* */xp_, etc ...) y por lo tanto mi recomendación para usar una consulta parametrizada (o cualquier otra opción válida, por ejemplo, proc almacenado, ORM, etc ...). aún, junto con restringir la longitud de la cadena "tableName" ... esta solución probablemente funcionaría el 100% del tiempo. – wgpubs

6

Por lo que yo sé, no se puede utilizar para llevar a cabo consultas con parámetros sentencias DDL/especificar nombres de tablas, al menos no en Oracle o SQL Server. Lo que haría, si tuviera que tener una función TruncateTable loca, que tuviera que estar seguro de la inyección sql sería hacer un procedimiento almacenado que compruebe que la entrada es una tabla que es segura de truncar.


-- Sql Server specific! 
CREATE TABLE TruncableTables (TableName varchar(50)) 
Insert into TruncableTables values ('MyTable') 

go 

CREATE PROCEDURE MyTrunc @tableName varchar(50) 
AS 
BEGIN 

declare @IsValidTable int 
declare @SqlString nvarchar(50) 
select @IsValidTable = Count(*) from TruncableTables where TableName = @tableName 

if @IsValidTable > 0 
begin 
select @SqlString = 'truncate table ' + @tableName 
EXECUTE sp_executesql @SqlString 
end 
END 
1

Hay algunos otros mensajes que ayudarán con la inyección de SQL, así que voy a Upvote esos, pero otra cosa a considerar es cómo va a ser el manejo de permisos para ello. Si le concede a los usuarios funciones db + owner o db_ddladmin para que puedan truncar tablas, entonces simplemente evitar los ataques estándar de inyección de SQL no es suficiente. Un pirata informático puede enviar otros nombres de tabla que podrían ser válidos, pero que no le gustaría truncar.

Si le otorga permisos ALTER TABLE a los usuarios en las tablas específicas que permitirá que se trunquen, entonces estará en una mejor forma, pero aún así es más de lo que me gustaría permitir en un entorno normal.

Normalmente TRUNCATE TABLE no se usa en el uso diario normal de la aplicación. Se usa para escenarios de ETL o durante el mantenimiento de la base de datos. La única situación en la que podría imaginar que se usaría en una aplicación frontal sería si permitía que los usuarios cargaran una tabla que es específica para ese usuario con fines de carga, pero incluso entonces probablemente usaría una solución diferente.

Por supuesto, sin conocer los detalles sobre por qué lo está usando, no puedo decir categóricamente que debe rediseñar, pero si recibo una solicitud para esto como un DBA le estaría pidiendo mucho al desarrollador de preguntas

3

Si permite que la entrada definida por el usuario entre en esta función a través de la variable de nombre de tabla, no creo que la inyección SQL sea su único problema.

Una mejor opción sería ejecutar este comando a través de su propia conexión segura y no otorgarle ningún derecho de SELECCIÓN. Todo lo que TRUNCATE necesita para ejecutarse es el permiso ALTER TABLE. Si está en SQL 2005 en adelante, también puede intentar usar un procedimiento almacenado con EXECUTE AS adentro.

0

En este ejemplo concreto, necesita protección contra la inyección de SQL solo si el nombre de la tabla proviene de una fuente externa.

¿Por qué permites que esto suceda? Si está permitiendo que una entidad externa (usuario final, otro sistema, ¿qué?) para nombrar una tabla para descartar, ¿por qué no solo le dará derechos de administrador?

Si está creando y eliminando tablas para proporcionar alguna funcionalidad para el usuario final, no les permite proporcionar nombres para los objetos de la base de datos directamente. Además de la inyección SQL, tendrá problemas con los conflictos de nombres, etc. En su lugar, genere nombres de tablas reales (por ejemplo, DYNTABLE_00001, DYNTABLE_00002, ...) y conserve una tabla que los conecte con los nombres proporcionados por el usuario.


Algunas notas sobre la generación de SQL dinámico para operaciones DDL:

  • En la mayoría de los RDBMS-s que tendrá que utilizar SQL dinámico e insertar los nombres de tabla como texto. Tenga mucho cuidado.

  • Utilice los identificadores entre comillas ([] en el servidor MS SQL, "" en todos los RDBMS que cumplan con ANSI). Esto hará que sea más fácil evitar los errores causados ​​por nombres inválidos.

  • Hágalo en procedimientos almacenados y verifique si todos los objetos a los que se hace referencia son válidos.

  • No haga nada irreversible. P.ej. no deje tablas automáticamente Puede señalar que se eliminen y enviar un correo electrónico a su DBA. Los soltará después de la copia de seguridad.

  • Evítalo si puedes. Si no puede, haga lo que pueda para minimizar los derechos a otras tablas (no dinámicas) que tendrán los usuarios normales.

3
CREATE OR REPLACE PROCEDURE truncate(ptbl_name IN VARCHAR2) IS 
    stmt VARCHAR2(100); 
BEGIN 
    stmt := 'TRUNCATE TABLE '||DBMS_ASSERT.SIMPLE_SQL_NAME(ptbl_name); 
    dbms_output.put_line('<'||stmt||'>'); 
    EXECUTE IMMEDIATE stmt; 
END; 
Cuestiones relacionadas