Os formatos de data devem ser especificados nas instruções SQL?

8

Vejo o código dos desenvolvedores usando a conversão implícita de datas. Eu gostaria de uma resposta definitiva para por que eles não deveriam fazer isso.

SELECT * from dba_objects WHERE Created >= '06-MAR-2012';
Leigh Riffel
fonte
11
Você tem alguns exemplos?
FrustratedWithFormsDesigner
11
@Frustrated Adicionado um exemplo.
Leigh Riffel
Eu mesmo ir tão longe que você não deve usar os nomes dos meses abreviados quer a menos que o parâmetro NLS_DATE_LANGUAGE é usado como bem em um to_date () chamada
a_horse_with_no_name

Respostas:

15

Porque '2012/12/1'nos EUA 11 meses após a mesma data na Europa.

Permitir conversões implícitas significa que você está à mercê das configurações de localização.

Se você pode nomear uma empresa em que 11 meses é uma margem de erro aceitável, ficarei impressionado.

JNK
fonte
6
De fato, '01 / 01/11 'pode demorar 10 anos. +1
Leigh Riffel
@LeighRiffel: Ou até mesmo 110 anos fora ...
ypercubeᵀᴹ
+1, nunca se deve confiar na conversão de data implícita (ou qualquer tipo de dados conversão implícita que é)
a_horse_with_no_name
2
"nomear uma empresa em que 11 meses é uma margem de erro aceitável" - os mecanismos de genealogia tendem a permitir dois anos em ambos os lados do ano de entrada ao pesquisar registros.
precisa saber é o seguinte
11
@onedaywhen boa resposta - como afirmado, estou impressionado!
JNK
14

Existem problemas que ocorrerão se uma sessão com um formato de data diferente executar o código.

Falha na instrução

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

Dados inválidos

  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;

Nesta situação, porque cada uma das instruções alter / insert pode ser feita por diferentes usuários. Todos eles executariam as mesmas instruções, mas as datas resultantes seriam completamente diferentes. As instruções de inserção podem estar ocultas em um pacote que está sendo chamado apenas indiretamente. Como nenhum erro foi retornado, o problema pode não ser encontrado até muito mais tarde.

Injeção 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();

Nessa situação, um indivíduo mal-intencionado pode alterar o formato da data das sessões de forma a fornecer acesso a dados aos quais normalmente não teriam acesso.

Leigh Riffel
fonte
+1, mas acho que o caso de injeção de SQL é bem restrito.
JNK
11
@JNK Eu concordo, e isso aumenta a probabilidade de ser esquecido em uma revisão de código.
Leigh Riffel
11
Off-topic, mas esta injeção SQL whitepaper é brilhante: accuvant.com/capability/accuvant-labs/security-research/...
Philᵀᴹ