Haruskah format tanggal ditentukan dalam pernyataan SQL?

8

Saya melihat kode dari pengembang menggunakan konversi tanggal implisit. Saya ingin jawaban yang pasti mengapa mereka tidak melakukan ini.

SELECT * from dba_objects WHERE Created >= '06-MAR-2012';
Leigh Riffel
sumber
1
Apakah Anda punya beberapa contoh?
FrustratedWithFormsDesigner
1
@Frustrated Menambahkan contoh.
Leigh Riffel
Saya bahkan akan melangkah lebih jauh sehingga Anda tidak boleh menggunakan nama bulan yang disingkat baik kecuali jika parameter NLS_DATEussalam digunakan juga dalam panggilan
to_date

Jawaban:

15

Karena '2012/12/1'di AS 11 bulan setelah tanggal string yang sama di Eropa.

Mengizinkan konversi tersirat berarti Anda berada di bawah kendali pengaturan lokasi.

Jika Anda dapat menyebutkan nama bisnis di mana 11 bulan merupakan margin kesalahan yang dapat diterima, saya akan terkesan.

JNK
sumber
6
Memang, '01 / 01/11 'bisa jadi 10 tahun lagi. +1
Leigh Riffel
@LeighRiffel: Atau bahkan 110 tahun lagi ...
ypercubeᵀᴹ
+1, seseorang tidak boleh mengandalkan konversi DATE implisit (atau casting tipe data implisit apa pun itu)
a_horse_with_no_name
2
"beri nama sebuah bisnis di mana 11 bulan adalah margin of error yang dapat diterima" - mesin genealogi cenderung memungkinkan dua tahun di kedua sisi tahun input ketika mencari register.
onedaywhen
1
@oningay ketika jawaban yang bagus - seperti yang dinyatakan, saya terkesan!
JNK
14

Ada masalah yang akan terjadi jika sesi dengan format tanggal berbeda menjalankan kode.

Kegagalan Pernyataan

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

Data Buruk

  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;

Dalam situasi ini karena setiap pernyataan alter / insert dapat dilakukan oleh pengguna yang berbeda. Mereka semua akan menjalankan pernyataan yang sama, tetapi tanggal yang dihasilkan akan sangat berbeda. Pernyataan yang dimasukkan bisa dimakamkan dalam sebuah paket yang hanya secara tidak langsung dipanggil. Karena tidak ada kesalahan yang dikembalikan masalah mungkin tidak ditemukan sampai nanti.

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

Dalam situasi ini seseorang yang jahat dapat mengubah format tanggal sesi di sana sedemikian rupa untuk memberi mereka akses ke data yang biasanya tidak dapat mereka akses.

Leigh Riffel
sumber
1 tapi saya pikir case injeksi SQL cukup sempit.
JNK
1
@ JNK saya setuju, dan itu membuatnya lebih mungkin terlewatkan dalam review kode.
Leigh Riffel
1
Di luar topik, tapi whitepaper injeksi SQL ini brilian: accuvant.com/capability/accuvant-labs/security-research/…
Philᵀᴹ