Sollten Datumsformate in SQL-Anweisungen angegeben werden?

8

Ich sehe Code von Entwicklern, die implizite Datumskonvertierung verwenden. Ich hätte gerne eine endgültige Antwort darauf, warum sie das nicht tun sollten.

SELECT * from dba_objects WHERE Created >= '06-MAR-2012';
Leigh Riffel
quelle
1
Haben Sie einige Beispiele?
FrustratedWithFormsDesigner
1
@Frustrated Ein Beispiel wurde hinzugefügt.
Leigh Riffel
Ich würde sogar so weit gehen, dass Sie auch keine abgekürzten Monatsnamen verwenden sollten, es sei denn, der Parameter NLS_DATE_LANGUAGE wird auch in einem Aufruf von to_date () verwendet
a_horse_with_no_name

Antworten:

15

Denn '2012/12/1'in den USA ist 11 Monate nach dem gleichen Saitendatum in Europa.

Wenn Sie implizite Konvertierungen zulassen, sind Sie den Standorteinstellungen ausgeliefert.

Wenn Sie ein Unternehmen nennen können, bei dem 11 Monate eine akzeptable Fehlerquote darstellen, bin ich beeindruckt.

JNK
quelle
6
In der Tat könnte '01 / 01/11 '10 Jahre frei sein. +1
Leigh Riffel
@LeighRiffel: Oder sogar 110 Jahre frei ...
ypercubeᵀᴹ
+1, man sollte sich niemals auf implizite DATE-Konvertierung (oder implizites Casting von Datentypen) verlassen
a_horse_with_no_name
2
"Nennen Sie ein Unternehmen, bei dem 11 Monate eine akzeptable Fehlerquote darstellen" - Genealogie-Engines erlauben bei der Suche nach Registern in der Regel zwei Jahre zu beiden Seiten des Eingabejahres.
Tag, wenn
1
@onedaywhen gute Antwort - wie gesagt, ich bin beeindruckt!
JNK
14

Es treten Probleme auf, wenn der Code in einer Sitzung mit einem anderen Datumsformat ausgeführt wird.

Anweisungsfehler

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

Schlechte Daten

  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;

In dieser Situation, weil jede der alter / insert-Anweisungen von verschiedenen Benutzern ausgeführt werden kann. Sie würden alle die gleichen Anweisungen ausführen, aber die resultierenden Daten wären völlig unterschiedlich. Die insert-Anweisungen können in einem Paket vergraben sein, das nur indirekt aufgerufen wird. Da kein Fehler zurückgegeben wurde, wird das Problem möglicherweise erst viel später gefunden.

SQL-Injektion

  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();

In dieser Situation kann eine böswillige Person das Datumsformat der Sitzungen so ändern, dass sie Zugriff auf Daten erhält, auf die sie normalerweise keinen Zugriff haben.

Leigh Riffel
quelle
+1, aber ich denke, der SQL-Injection-Fall ist ziemlich eng.
JNK
1
@JNK Ich stimme zu, und das macht es umso wahrscheinlicher, dass es bei einer Codeüberprüfung übersehen wird.
Leigh Riffel
1
Off-Topic, aber dieses Whitepaper zur SQL-Injektion ist brillant: accuvant.com/capability/accuvant-labs/security-research/…
Philᵀᴹ