Seite 1 von 2

UPDATE mit Bedingung

Verfasst: Fr, 30. Jul 2021 11:43
von Manfred
ich habe folgenden Befehl

Code: Alles auswählen

UPDATE arbeitsauftrag_verteilt
SET datumende = '{#datumende#}',
    zeitende = '{#zeitende#}',
    kmstand={#kilometerstand#},
    textrep='{#creptext#}'
WHERE id='{#idauftrag#}'
der klappt, aber er müßte anderes klappen.
alle Felder werden upgedatet, aber Kilometerstand darf nur ersetzt werden, wenn der neue Wert über dem aktuell eingetragenen liegt. Gibt es dann eine IF Abfrage in dem SET Bereich?

Re: UPDATE mit Bedingung

Verfasst: Fr, 30. Jul 2021 12:27
von Marcus Herz

Code: Alles auswählen

UPDATE arbeitsauftrag_verteilt
SET datumende = '{#datumende#}',
    zeitende = '{#zeitende#}',
    kmstand= iif( {#kilometerstand#} > kmstand,{#kilometerstand#}, kmstand),
    textrep='{#creptext#}'
WHERE id='{#idauftrag#}'
Das mit den geschweiftern Klammern versteh ich nicht

Re: UPDATE mit Bedingung

Verfasst: Fr, 30. Jul 2021 12:30
von Manfred
Das sind Platzhalter. Die werden ausgetauscht.

Re: UPDATE mit Bedingung

Verfasst: Fr, 30. Jul 2021 14:09
von nightcrawler
Hallo Manfred,
ich würde aber lieber mit Parametern arbeiten statt mit Makros ... SQL Injection droht.

Re: UPDATE mit Bedingung

Verfasst: Fr, 30. Jul 2021 14:30
von Manfred
Kläre mich auf, Joachim.

Re: UPDATE mit Bedingung

Verfasst: Fr, 30. Jul 2021 14:30
von Martin Altmann
Vortrag in Regensburg!

Viele Grüße,
Martin

Re: UPDATE mit Bedingung

Verfasst: Fr, 30. Jul 2021 14:31
von Tom
Ich denke, er ersetzt die Platzhalter, bevor das SELECT abgesetzt wird. Das ist sozusagen nur das Template für die eigentliche Abfrage, die er baut.

Manfreds Anforderung müsste eigentlich mit einem Subselect lösbar sein, was eine der Sachen ist, die ich an SQL nicht mag - es ist sehr schwer zu debuggen, und beim Schreiben verknotet sich das Hirn. Ich löse lieber zwei Statements nacheinander aus, allerdings riskiert man dann einen Moment der nichtvorhandenen Datenbankintegrität.

Re: UPDATE mit Bedingung

Verfasst: Fr, 30. Jul 2021 14:33
von Manfred
richtig, ich habe so gut wie alle SQL Befehle als Text vorliegen und lade sie nach. Dann werden die Platzhalter in Echtzeit ersetzt.
Das kann gefährlich werden? macht mich jetzt nicht schwach....

Re: UPDATE mit Bedingung

Verfasst: Fr, 30. Jul 2021 14:38
von Marcus Herz
Das kann nur gefährlich werden, wenn die Werte für die Platzhalter aus einer Eingabe Maske kommen. Solange du dich nur in deinem PRG bewegts und die Kontrolle über die Daten hast, kann das nicht passieren.

Re: UPDATE mit Bedingung

Verfasst: Fr, 30. Jul 2021 14:42
von Manfred
also die Werte für die Felder kommen schon aus einer Maske. Aber wie soll man das anders lösen? Die müssen doch sowieso in den Befehl eingebaut werden.

Re: UPDATE mit Bedingung

Verfasst: Fr, 30. Jul 2021 14:44
von Tom
Das kann gefährlich werden?
Eher nicht, würde ich sagen. Injection droht, wenn Du z.B. Feld-/Nutzereingaben in Statements verarbeitest, und nicht prüfst, ob die Feldeingaben möglicherweise selbst Statements sind - oder Bestandteile davon. Das ist der Nachteil davon, wie SQL in Kommunikation mit dem Server arbeitet. Die Information, die sozusagen in einem Feld steht oder in Deinem Programm, das ja Zugriff auf die Datenbank hat, ist eigentlich ein Befehl oder Befehlsbestandteil (der in Deine Statements "injiziert" wird), und dadurch droht Ungemach. Ob das wirklich so ist, hängt nicht nur davon ab, wie Du Feldinhalte verarbeitest, sondern natürlich in der Hauptsache von der Topologie, in der Deine Anwendung läuft. Kommt jemand ran, der Böses wollen würde? Wenn das bis eben noch eine DBF-basierte Anwendung war, ist dieses Thema belanglos. Dann bist Du von einer offenen Scheune zu etwas sehr viel sicherem gewechselt, sagen wir: Einem gut gegen Einbrüche gesicherten Standard-Einfamilienhaus in einem bewachten Vorort. Wenn Dein Zeug kritisch ist und in einer kritischen Umgebung läuft, solltest Du Dich mit dieser Thematik befassen. In gewisser Weise geht das auch in Xbase++ mit Makros, aber sehr eingeschränkt.

Re: UPDATE mit Bedingung

Verfasst: Fr, 30. Jul 2021 14:47
von Marcus Herz

Code: Alles auswählen

UPDATE arbeitsauftrag_verteilt
SET datumende = :datumende,
    zeitende = :zeitende,
    kmstand= iif( :kilometerstand > kmstand,:kilometerstand, kmstand),
    textrep= :creptext
WHERE id= :idauftrag
Die Wörter mit dem Doppelpunkt davor sind SQL Parameter, welche extra übergeben werden.
Das kannst du im ARC testen, dieser frägt dich nach den Werten für die Parameter und merkt die sich auch fürs nächste mal.
Falls du mit AdsClass arbeitest ist das dann so:

Code: Alles auswählen

oDic:QuickExec(cSql,,,,{;
{":datumende"	,date()},;   // im nativen Datenformat !!
{":kilometerstand"	, 99999}})  // immer Pärchen: { Parametername, Wert }
Das hat auch den Vorteil, dass in einem Text ein einzelnes ' vorkommen darf, welches bei erstzen einen SQL Syntax Fehler auslöst.
Wie das mit der ADSDBE geht, weiß ich nicht.

Re: UPDATE mit Bedingung

Verfasst: Fr, 30. Jul 2021 14:50
von Manfred
Hi marcus,
klar arbeite ich mit ADSClass im MOment. Ich denke, wir müssen uns doch nochmal unterhalten, was da so alles an Überraschung drin ist. :badgrin:

Re: UPDATE mit Bedingung

Verfasst: Fr, 30. Jul 2021 16:07
von ramses
Du kannst einfach die Strings mit der Funktion pg_escape_string() bearbeiten. Das formatiert den String korrekt und verhindet SQl-Injection über ein Textfeld.

Re: UPDATE mit Bedingung

Verfasst: Fr, 30. Jul 2021 16:33
von Manfred
bevor wir jetz hier wieder in Glaubenskriege verfallen:
SQL Script als Datei

Code: Alles auswählen

UPDATE arbeitsauftrag_verteilt
SET datumende = '{#datumende#}',
    zeitende = '{#zeitende#}',
    kmstand={#kilometerstand#},
    textrep='{#creptext#}'
WHERE id='{#idauftrag#}'
Programmcode, der sie einliest und dann austauscht

Code: Alles auswählen

cSqlStmt := MemoRead("sqlscripte\auftrag_beenden_auftrag_erledigt.sql")
                cSQLStmt := StrTran(cSQLStmt,"{#datumende#}",TransDateToSql(Date()))
                cSQLStmt := StrTran(cSQLStmt,"{#zeitende#}",Time())
                cSQLStmt := StrTran(cSQLStmt,"{#kilometerstand#}",cKilometerstand)
                cSQLStmt := StrTran(cSQLStmt,"{#creptext#}",cRepText)
                cSQLStmt := StrTran(cSQLStmt,"{#idauftrag#}",cIdAuftrag)
                oAdsServer:ExecSql(cSqlStmt)
cReptext und cKilometerstand werde in einer Maske eingegeben. cIdAuftrag ist nur dem System bekannt und wird nirgendwo eingegeben
Sowas kann gefährlich werden?

Re: UPDATE mit Bedingung

Verfasst: Fr, 30. Jul 2021 18:32
von nightcrawler
ja, kann gefährlich werden. Wenn zB jemand in cRepText folgendes eingibt:

Code: Alles auswählen

-leer-'; SELECT * FROM arbeitsauftrag_verteilt --
dann wird aus Deinem Statement so was wie

Code: Alles auswählen

UPDATE arbeitsauftrag_verteilt
SET datumende = '2021-10-20',
    zeitende = '19:30',
    kmstand=123456,
    textrep='-leer-'; SELECT * FROM arbeitsauftrag_verteilt --'
WHERE id='123456'
Ausgeführt wird damit jede Zeile in Deiner Tabelle überschrieben. Ein ganz pöser könnte das noch mit einem

Code: Alles auswählen

-leer-'; DROP TABLE arbeitsauftrag_verteilt; SELECT * FROM arbeitsauftrag_verteilt --
garnieren. Das -- sorgt übrigens dafür, dass bis zum Zeilenende alles Kommentar ist und somit das zweite Anführungszeichen ignoriert wird.

Re: UPDATE mit Bedingung

Verfasst: Fr, 30. Jul 2021 18:34
von Manfred
ok,
und wie umgeht man das dann?

Re: UPDATE mit Bedingung

Verfasst: Fr, 30. Jul 2021 18:55
von ramses
Manfred hat geschrieben: Fr, 30. Jul 2021 18:34 ok,
und wie umgeht man das dann?
mit pg_escape_string()
der macht z.B. aus

Code: Alles auswählen

-leer-'; SELECT * FROM arbeitsauftrag_verteilt --
einen geescapten String

Code: Alles auswählen

-leer-''; SELECT * FROM arbeitsauftrag_verteilt --
und der ist nicht mehr gefährlich

Re: UPDATE mit Bedingung

Verfasst: Fr, 30. Jul 2021 18:58
von Manfred
die Funktion kenne ich nicht. Wo ist die her?

Re: UPDATE mit Bedingung

Verfasst: Fr, 30. Jul 2021 19:24
von HaPe
Hallo Zusammen !
pg_escape_string()
die Funktion kenne ich nicht. Wo ist die her?
Die ist für PostGreSQL, Manfred arbeitet hier aber mit dem ADS :wink:

Re: UPDATE mit Bedingung

Verfasst: Fr, 30. Jul 2021 19:31
von Manfred
wobei meine Eingangsfrage aber erstmal generell SQL ansprechen sollte.

Re: UPDATE mit Bedingung

Verfasst: Fr, 30. Jul 2021 21:24
von Werner_Bayern
HaPe hat geschrieben: Fr, 30. Jul 2021 19:24 Die ist vom PostGreSQL, Manfred arbeitet hier aber mit dem ADS :wink:
Nein, kommt m. W. n. eigentlich von PHP. Gibt's nicht unter PostgreSQL.

Re: UPDATE mit Bedingung

Verfasst: Sa, 31. Jul 2021 8:56
von Manfred
ramses hat geschrieben: Fr, 30. Jul 2021 18:55
Manfred hat geschrieben: Fr, 30. Jul 2021 18:34 ok,
und wie umgeht man das dann?
mit pg_escape_string()
der macht z.B. aus

Code: Alles auswählen

-leer-'; SELECT * FROM arbeitsauftrag_verteilt --
einen geescapten String

Code: Alles auswählen

-leer-''; SELECT * FROM arbeitsauftrag_verteilt --
und der ist nicht mehr gefährlich
öhm,
das ist ja alles schön und gut, aber woher will der Angreifer wissen, wie die einzelnen Tabellen heißen?

Re: UPDATE mit Bedingung

Verfasst: Sa, 31. Jul 2021 9:01
von Martin Altmann
Denke mal nach - auf die selbe Art! Erstmal wird ein Select * auf die Systemtabelle mit den Tabellennamen gemacht, um alle zu erhalten, die vorhanden sind.

Viele Grüße,
Martin

Re: UPDATE mit Bedingung

Verfasst: Sa, 31. Jul 2021 9:02
von Martin Altmann
Unter Postgres:

Code: Alles auswählen

 SELECT
    table_schema || '.' || table_name
FROM
    information_schema.tables
WHERE
    table_type = 'BASE TABLE'
AND
    table_schema NOT IN ('pg_catalog', 'information_schema')
Viele Grüße,
Martin