Должны ли форматы даты быть указаны в инструкциях SQL?

8

Я вижу код от разработчиков, использующих неявное преобразование даты. Я хотел бы получить окончательный ответ на вопрос, почему они не должны этого делать.

SELECT * from dba_objects WHERE Created >= '06-MAR-2012';
Ли Риффель
источник
1
У вас есть примеры?
FrustratedWithFormsDesigner
1
@Frustrated Добавил пример.
Ли Риффель
Я бы даже зашел так далеко, что вы не должны использовать сокращенные названия месяцев, если только параметр NLS_DATE_LANGUAGE не используется также в вызове to_date ()
a_horse_with_no_name

Ответы:

15

Потому что '2012/12/1'в США это 11 месяцев после той же строковой даты в Европе.

Разрешение неявных преобразований означает, что вы находитесь в зависимости от настроек местоположения.

Если вы можете назвать компанию, где допустимая погрешность составляет 11 месяцев, я буду впечатлен.

JNK
источник
6
Действительно, «01/01/11» может быть 10 лет. +1
Ли Риффель
@LeighRiffel: Или даже 110 лет отдыха ...
ypercubeᵀᴹ
+1, никогда не следует полагаться на неявное преобразование DATE (или любое неявное приведение типов данных)
a_horse_with_no_name
2
«Назовите компанию, где допустимым пределом погрешности является 11 месяцев» - механизмы поиска по генеалогии, как правило, дают два года по обе стороны от входного года при поиске регистров.
понедельник,
1
@onedaywhen хороший ответ - как заявлено, я впечатлен!
JNK
14

Существуют проблемы, которые могут возникнуть, если код запускается в сеансе с другим форматом даты.

Сбой заявления

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

Плохие данные

  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;

В этой ситуации, потому что каждый из операторов изменения / вставки может быть сделан разными пользователями. Все они будут использовать одни и те же утверждения, но итоговые даты будут совершенно другими. Операторы вставки могут быть похоронены в пакете, который вызывается только косвенно. Поскольку никакая ошибка не была возвращена, проблема не может быть найдена намного позже.

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

В этой ситуации злоумышленник может изменить формат даты сеанса таким образом, чтобы предоставить им доступ к данным, к которым он обычно не имеет доступа.

Ли Риффель
источник
+1, но я думаю, что случай внедрения SQL довольно узок.
JNK
1
@JNK Я согласен, и это повышает вероятность того, что его упустят в обзоре кода.
Ли Риффель
1
Не по теме, но этот технический документ по SQL-инъекциям великолепен: accuvant.com/capability/accuvant-labs/security-research/…
Philᵀᴹ