¿Deben especificarse los formatos de fecha en las declaraciones SQL?

8

Veo código de desarrolladores que usan conversión de fecha implícita. Me gustaría una respuesta definitiva a por qué no deberían hacer esto.

SELECT * from dba_objects WHERE Created >= '06-MAR-2012';
Leigh Riffel
fuente
1
¿Tienes algunos ejemplos?
FrustratedWithFormsDesigner
1
@ Frustrado Se agregó un ejemplo.
Leigh Riffel
Incluso iría tan lejos que no debería usar nombres de mes abreviados a menos que el parámetro NLS_DATE_LANGUAGE se use también en una llamada to_date ()
a_horse_with_no_name

Respuestas:

15

Porque '2012/12/1'en los Estados Unidos es 11 meses después de la misma fecha de cadena en Europa.

Permitir conversiones implícitas significa que está a merced de la configuración de ubicación.

Si puede nombrar un negocio donde 11 meses es un margen de error aceptable, me impresionará.

JNK
fuente
66
De hecho, '01 / 01/11 'podría tener 10 años de descuento. +1
Leigh Riffel
@LeighRiffel: O incluso 110 años de descanso ...
ypercubeᵀᴹ
+1, uno nunca debe confiar en la conversión de FECHA implícita (o cualquier conversión de tipo de datos implícita que sea)
a_horse_with_no_name
2
"nombrar una empresa donde 11 meses es un margen de error aceptable": los motores de genealogía tienden a permitir dos años a cada lado del año de entrada al buscar registros.
cuando el
1
@onedaywhen buena respuesta - como se dijo, estoy impresionado!
JNK
14

Hay problemas que ocurrirán si una sesión con un formato de fecha diferente ejecuta el código.

Fracaso de la declaración

DROP TABLE t1;
CREATE TABLE t1 AS (SELECT sysdate mydate FROM dual WHERE 1=2);
ALTER SESSION SET NLS_DATE_FORMAT = 'MON-DD-RR';
INSERT INTO t1 VALUES ('01-02-12');
                       *
ERROR at line 1:
ORA-01843: not a valid month

Datos incorrectos

  DROP TABLE t1;
  CREATE TABLE t1 AS (SELECT sysdate mydate FROM dual WHERE 1=2);

  --User 1
  ALTER SESSION SET NLS_DATE_FORMAT = 'MM-DD-RR';
  INSERT INTO t1 VALUES ('01-02-11');

  --User 2
  ALTER SESSION SET NLS_DATE_FORMAT = 'DD-MM-RR';
  INSERT INTO t1 VALUES ('01-02-11');

  --User 3
  ALTER SESSION SET NLS_DATE_FORMAT = 'RR-MM-DD';
  INSERT INTO t1 VALUES ('01-02-11');

  SELECT to_char(mydate,'MM/DD/YYYY') FROM t1;

En esta situación, porque cada una de las declaraciones de alteración / inserción podría ser realizada por diferentes usuarios. Todos estarían ejecutando las mismas declaraciones, pero las fechas resultantes serían completamente diferentes. Las instrucciones de inserción pueden estar enterradas en un paquete que solo se llama indirectamente. Debido a que no se devolvió ningún error, el problema podría no encontrarse hasta mucho más tarde.

Inyección SQL

  CLEAR SCREEN;
  DROP TABLE Secrets;
  CREATE TABLE Secrets (RevealDate Date, Secret Varchar2(200));
  INSERT INTO Secrets VALUES (trunc(sysdate),   '*** Common Knowledge. ***');
  INSERT INTO Secrets VALUES (trunc(sysdate+1), '*** Don''t Let Anyone know this. ***');

  CREATE OR REPLACE PROCEDURE ShowRevealedSecrets IS
     vStatement varchar2(200);
     vOutput Varchar2(1000);
     vDate date:=sysdate;
  begin
  vStatement:='SELECT secret FROM Secrets WHERE RevealDate = ''' || vDate || '''';
  execute immediate vStatement INTO vOutput;
  DBMS_Output.Put_Line(vOutput);
  END;
  /

  --Normal Use.     
  ALTER SESSION SET NLS_DATE_FORMAT = 'DD-MON-YY';
  EXEC ShowRevealedSecrets();

  --Explointing SQL Injection
  ALTER SESSION SET NLS_DATE_FORMAT = '"'' OR RevealDate > sysdate--"';
  EXEC ShowRevealedSecrets();

En esta situación, un individuo malintencionado podría alterar el formato de la fecha de las sesiones de tal manera que les dé acceso a datos a los que normalmente no tendrían acceso.

Leigh Riffel
fuente
+1 pero creo que el caso de inyección SQL es bastante estrecho.
JNK
1
@JNK Estoy de acuerdo, y eso hace que sea más probable que se pierda en una revisión de código.
Leigh Riffel
1
Fuera de tema, pero este documento técnico de inyección SQL es brillante: accuvant.com/capability/accuvant-labs/security-research/…
Philᵀᴹ