Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Parameterverwendung bei DB-, Feld- und Tabellennamen (https://www.delphipraxis.net/187909-parameterverwendung-bei-db-feld-und-tabellennamen.html)

freejay 14. Jan 2016 11:01

Datenbank: MySQL • Version: 5.x • Zugriff über: MyDac

Parameterverwendung bei DB-, Feld- und Tabellennamen
 
Hallo zusammen,

ich habe früher meine SQL-Statements immer über den Formatbefehl zusammengesetzt, z.B.:
Code:
MyQuery.SQL.Text := format('SELECT * FROM `%s`;',[Tabellenname]);
Da dies Methode ziemlich unsicher ist, wenn der Tabellenname beispielsweise von einem User eingetippt werden kann (Stichwort "SQL-Injection"), möchte ich künftig lieber sauber mit Parametern arbeiten. Bei Values - z.B. in Where-Bedingungen - ist das auch gar kein Problem. Aber bei Feld-, DB- und Tabellennamen funktioniert das scheinbar nicht. Beispiel:
Code:
MyQuery.SQL.Text := 'SELECT * FROM :TabName;';
MyQuery.ParamByName('TabName').AsString := TabellenName;
MyQuery.Open;
Das führt zu einem Fehler, da der Tabellenname offenbar mit führendem und schließendem Hochkomma in das SQL-Staement eingebaut wird.
:TabName in die bei Feld- und Tabellennamen üblichen Hochkommas zusetzen (`:TabName`), hilft auch nicht...

Übersehe ich da was oder funktionieren DB-, Tabellen- und Feldnamen einfach nicht über Parameter?

Danke im Voraus!

Freejay

Uwe Raabe 14. Jan 2016 11:09

AW: Parameterverwendung bei DB-, Feld- und Tabellennamen
 
Nimm ein Makro: https://www.devart.com/mydac/docs/?work_macros.htm

DeddyH 14. Jan 2016 11:10

AW: Parameterverwendung bei DB-, Feld- und Tabellennamen
 
Du kannst lediglich Werte parametrisieren, aber keine (Tabellen-, Feld- oder sonstigen) Bezeichner, das hast Du richtig erkannt.

freejay 14. Jan 2016 11:51

AW: Parameterverwendung bei DB-, Feld- und Tabellennamen
 
"Macro" ist ja dafür ein komischer Name, aber das ist genau das, was ich brauche! ;-)

Dank Euch!

mkinzler 14. Jan 2016 11:52

AW: Parameterverwendung bei DB-, Feld- und Tabellennamen
 
Warum komisch, es ist ja eine Makroersetzung innerhalb der Clientkomponenten.

freejay 14. Jan 2016 12:03

AW: Parameterverwendung bei DB-, Feld- und Tabellennamen
 
Ich verstehe und einem Makro ungefähr folgendes:
Zitat:

Ein Makro ist in der Softwareentwicklung eine unter einer bestimmten Bezeichnung zusammengefasste Folge von Anweisungen oder Deklarationen, um diese ... mit nur einem einfachen Aufruf ausführen zu können.
[Quelle: Wikipedia]

Für mich hat das Ersetzen von bestimmten kleinen Strings in einem größeren String durch andere kleine Strings mit dem wie oben verstandenen Begriff "Makro" nicht viel zu tun.

Aber das darf natürlich jeder beliebig anders sehen! ;-)

joachimd 14. Jan 2016 13:15

AW: Parameterverwendung bei DB-, Feld- und Tabellennamen
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1326989)

Ääähhhh, sorry für meine Unwissenheit, aber wenn auf der Clientseite der Tabellenname mit einem Macro ersetzt wird, kann es doch trotzdem noch zu SQL Injection kommen!? Oder ist die Macro-Funktion schlau genug, das zu erkennen?
Falls nicht würde ich den eingegebenen Text anhand von System-Tabellen verifizieren
(gibt es eine Tabelle, dessen Text gleich ist wie der eingegebene) und es dann wie im Usprungspost selbst ersetzen.

Uwe Raabe 14. Jan 2016 14:16

AW: Parameterverwendung bei DB-, Feld- und Tabellennamen
 
Zitat:

Zitat von joachimd (Beitrag 1327015)
Ääähhhh, sorry für meine Unwissenheit, aber wenn auf der Clientseite der Tabellenname mit einem Macro ersetzt wird, kann es doch trotzdem noch zu SQL Injection kommen!? Oder ist die Macro-Funktion schlau genug, das zu erkennen?

Das kann ich aufgrund fehlender Einblicke in die MyDAC-Sourcen nicht beurteilen (also ebenso unwissend), aber der Einwand ist natürlich durchaus berechtigt. Zumindest kann man vorher überprüfen, ob der in das Makro einzusetzende Wert die Vorgaben für einen validen Bezeichner erfüllt.

freejay 14. Jan 2016 14:36

AW: Parameterverwendung bei DB-, Feld- und Tabellennamen
 
Zitat:

Zitat von joachimd (Beitrag 1327015)
Ääähhhh, sorry für meine Unwissenheit, aber wenn auf der Clientseite der Tabellenname mit einem Macro ersetzt wird, kann es doch trotzdem noch zu SQL Injection kommen!?

Ja, davon gehe ich aus. Aber erstens war das mit dem Tabellennamen nur ein in meiner Praxis nicht vorkommendes Beispiel und zweitens ging es mir zusätzlich um einen "objektmäßigeren" Code - also nicht immer diese String-/Format-Pfriemeleien - auch wenn SQL natürlich per se eher textlastig is... ;-)

Die Benutzung von Parametern verhindert allerdings meines Wissens nach sicher SQL-Injections.

mkinzler 14. Jan 2016 14:47

AW: Parameterverwendung bei DB-, Feld- und Tabellennamen
 
Wenn diese vom DBMS direkt unterstützt werden und nicht von der Zugriffsschicht emuliert werden.

Jumpy 14. Jan 2016 16:23

AW: Parameterverwendung bei DB-, Feld- und Tabellennamen
 
Zitat:

Zitat von freejay (Beitrag 1327037)
Zitat:

Zitat von joachimd (Beitrag 1327015)
Ääähhhh, sorry für meine Unwissenheit, aber wenn auf der Clientseite der Tabellenname mit einem Macro ersetzt wird, kann es doch trotzdem noch zu SQL Injection kommen!?

Ja, davon gehe ich aus. Aber erstens war das mit dem Tabellennamen nur ein in meiner Praxis nicht vorkommendes Beispiel und zweitens ging es mir zusätzlich um einen "objektmäßigeren" Code - also nicht immer diese String-/Format-Pfriemeleien - auch wenn SQL natürlich per se eher textlastig is... ;-)

Die Benutzung von Parametern verhindert allerdings meines Wissens nach sicher SQL-Injections.

Wir haben und da mal eine Klasse TSQL gebastelt, mit der man auf Basis einer Stringliste SQL-Statements zusammen bauen konnte. "Add" wurde als Property realisiert, damit man auf die Klammern verzichten konnte, das machte das im Quelltext lesbarer. Gleichzeitig gab es diverse Hilfsfunktionen für verschiedene Datenbanken. Dabei ging es hauptsächlich um das angenehme, lesbare zusammenbauen der SQL-Statements, ein paar Sachen waren drin um SQL-Injektion zu verhindern, es wurde aber trotzdem auch mit Parametern gearbeitet:

Delphi-Quellcode:
function SQL_Beispiel:String;
var s:TSQL;
begin
  s:=TSQL.Create;
  s.Add := 'Select';
  s.Add := ' Wert1,';
  s.Add := ' Wert2,';
  s.Add := ' Wert3';
  s.Add := 'From';
  s.Add := ' Tabelle';
  s.Add := 'Where';
  s.Add := ' Wert4 = ' + s.oracleStr('Suchstring'); // sowas wie QuotedStr
  s.Add := ' and Wert5 > ' + s.oracleDateOfStr('01.12.2015'); // würde zu To_Date('01.12.2015','dd.mm.yyyy')
  Result:=s.Text;
  //s.Show //zum Anzeigen des Statements in einem Memo eines kleinen Popup-Forms.
  s.Free;
end;

Uwe Raabe 14. Jan 2016 16:57

AW: Parameterverwendung bei DB-, Feld- und Tabellennamen
 
Zitat:

Zitat von Jumpy (Beitrag 1327062)
Wir haben und da mal eine Klasse TSQL gebastelt, mit der man auf Basis einer Stringliste SQL-Statements zusammen bauen konnte. "Add" wurde als Property realisiert, damit man auf die Klammern verzichten konnte, das machte das im Quelltext lesbarer.

Das würde man heute auch mit einer bordeigenen TStringList vielleicht sogar noch etwas eleganter hinkriegen:
Delphi-Quellcode:
type
  TOracleHelper = class helper for TStrings
  public
    function oracleStr(const value: string): string;
    function oracleDateOfStr(const value: string): string;
  end;

function SQL_Beispiel: String;
var
  s: TStringList;
begin
  s := TStringList.Create;
  try
    s.AddStrings([
       'Select',
       ' Wert1,',
       ' Wert2,',
       ' Wert3',
       'From',
       ' Tabelle',
       'Where',
       ' Wert4 = ' + s.oracleStr('Suchstring'),
       ' and Wert5 > ' + s.oracleDateOfStr('01.12.2015')
       ]);
    Result := s.Text;
  finally
    s.Free;
  end;
end;

Jumpy 15. Jan 2016 10:12

AW: Parameterverwendung bei DB-, Feld- und Tabellennamen
 
Im alten D6 geht das so glaub ich leider noch nicht. Auch fehlen der Stringlist ja die schönen Umwandelfunktionen. Wobei man die in dem Beispiel gezeigten ja auch nicht wirklich braucht, wenn man stattdessen mit Parametern arbeitet, insofern kann man sich bei neueren Delphis durchaus die Mühe einer eigenen Klasse sparen.

Nur aus Neugier:
Wie funktiert das eigentlich mit dem Datum als Parameter, wenn man das gewohnte deutsche Datumsformat im String hat "15.03.2013" die Datenbank aber intern mit US-Schema arbeitet?

Mavarik 15. Jan 2016 10:37

AW: Parameterverwendung bei DB-, Feld- und Tabellennamen
 
Zitat:

Zitat von Jumpy (Beitrag 1327113)
Nur aus Neugier:
Wie funktiert das eigentlich mit dem Datum als Parameter, wenn man das gewohnte deutsche Datumsformat im String hat "15.03.2013" die Datenbank aber intern mit US-Schema arbeitet?

Überlass doch der Datenbank die Speicherung...

Zitat:

Zitat von freejay (Beitrag 1326985)
Code:
MyQuery.SQL.Text := 'SELECT * FROM :TabName;';
MyQuery.ParamByName('TabName').AsString := TabellenName;
MyQuery.Open;

Fast... Beispiel INSERT mit Datum

Delphi-Quellcode:
MyQuery.SQL.Text := 'INSERT INTO FooTable (FooDate,FooStr,FooInt) VALUES (:1,:2,:3);';
MyQuery.Params[0].AsDateTime := NOW; // Funktioniert nur, wenn FooDate in der Datenbank ein DateTime-Feld ist.
MyQuery.Params[1].AsString  := 'Die Frage aller Fragen:';
MyQuery.Params[2].AsInteger := 42;

Mavarik

Oder war das nicht die Frage?

Uwe Raabe 15. Jan 2016 10:58

AW: Parameterverwendung bei DB-, Feld- und Tabellennamen
 
Zitat:

Zitat von Jumpy (Beitrag 1327113)
Im alten D6 geht das so glaub ich leider noch nicht.

Das wir die eigentliche Intention meines Beitrags :twisted:

Zitat:

Zitat von Jumpy (Beitrag 1327113)
Auch fehlen der Stringlist ja die schönen Umwandelfunktionen.

Das wiederum wollte ich mit dem Class helper demonstrieren.

Jumpy 15. Jan 2016 13:17

AW: Parameterverwendung bei DB-, Feld- und Tabellennamen
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1327121)
Zitat:

Zitat von Jumpy (Beitrag 1327113)
Auch fehlen der Stringlist ja die schönen Umwandelfunktionen.

Das wiederum wollte ich mit dem Class helper demonstrieren.

Aua. Den Teil deines Beitrages habe einfach überlesen und bei "function SQL_Beispiel: String;" angefangen den Code zu lesen. So macht das natürlich mehr Sinn, sorry.

Uwe Raabe 15. Jan 2016 13:19

AW: Parameterverwendung bei DB-, Feld- und Tabellennamen
 
Zitat:

Zitat von Jumpy (Beitrag 1327145)
sorry.

Im Gegenteil! Das gab mir die Gelegenheit, das nochmal herauszustellen :-D

Jumpy 15. Jan 2016 13:24

AW: Parameterverwendung bei DB-, Feld- und Tabellennamen
 
Zitat:

Zitat von Mavarik (Beitrag 1327116)
Oder war das nicht die Frage?

Doch, nur machst du es dir mit NOW() einfach. Wie sieht es bei einem Datum, dass mir im Programm als String vorliegt aus? Muss da Delphi die Umwandlung machen?

Delphi-Quellcode:
MyQuery.Params[0].AsDateTime := StrToDatetime('15.03.2013'); //?? Da müssen aber die FormatSettingspassen oder?

MyQuery.Params[0].AsString := '15.03.2013'; //Was müsste wo eingestellt werden, damit das klappt?

Uwe Raabe 15. Jan 2016 13:34

AW: Parameterverwendung bei DB-, Feld- und Tabellennamen
 
Zitat:

Zitat von Jumpy (Beitrag 1327147)
Delphi-Quellcode:
MyQuery.Params[0].AsDateTime := StrToDatetime('15.03.2013'); //?? Da müssen aber die FormatSettingspassen oder?

MyQuery.Params[0].AsString := '15.03.2013'; //Was müsste wo eingestellt werden, damit das klappt?

Mit der Zuweisung
Delphi-Quellcode:
As<Type>
wird der Datentyp des Parameters festgelegt. Mit
Delphi-Quellcode:
AsString
wird also ein (Wide-)String-Parameter gesetzt, was hier aber wohl nicht gewünscht ist.
Delphi-Quellcode:
AsDateTime
wäre hier der korrekte Ansatz.

Was die FormatSettings anbelangt: Die können bei einem aktuelleren Delphi als zweiter Parameter an StrToDateTime mitgegeben werden (TFormatSettings.Invariant).

Wenn das Datum nicht als String, sondern als Werte für Tag, Monat und Jahr vorliegt, geht auch ein EncodeDate.

Mavarik 15. Jan 2016 13:58

AW: Parameterverwendung bei DB-, Feld- und Tabellennamen
 
Delphi-Quellcode:
MyQuery.Params[0].AsDateTime := '20.01.2016'
Geht übrigens nicht.

himitsu 15. Jan 2016 14:43

AW: Parameterverwendung bei DB-, Feld- und Tabellennamen
 
Makros werden oft direkt "ersetzt", aber man kann ja vor Zuweisung an das Makro die Escape-Funktion für Bezeichner darauf anwenden.

bei PgDAC z.B. TPgTextConverter.EscapeString
quote_ident in der DB

Und eventuell wird dir auch eine Typkonvertierung angeboten

SQL-Code:
SELECT * FROM 'table'::regtype -- SELECT * FROM CAST('table' AS regtype)
SELECT * FROM :table::regtype -- SELECT * FROM CAST(:table AS regtype)


Alle Zeitangaben in WEZ +1. Es ist jetzt 12:13 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz