# Gibt es eine Alternative zu SQL Strings im Prorammcode?



## Alibi086 (28. Jan 2012)

Hi Folks !

Ich habe mal eine Fragean euch. Gibt es eigentlich eine Möglichkeit, diese SQL String zu umgehen und das irgendwie anders in seinem Programmcode umzusetzen bzw. sind diese SQL Strings überhaupt eine gute Wahl, oder sollte man sie vermeiden? Hier ein Beispiel:


```
Dim strSql as String

strSql = "SELECT tab1.FeldA, tab2.FeldA, tab2.FeldB " & _
         "FROM tab1 INNER JOIN tab2 " & _
         "ON tab1.FeldX = tab2.FeldX"
```

Der Syntax ist hier VB. Wie ist so etwas zu bewerten und sollte man das evtl. anders gestalten?

Greetz
Felix


----------



## maki (28. Jan 2012)

Vielleicht sollte man bei VB spezifischen Fragen nicht in einem Javaforum fragen?

Sorry, aber was erwartest du hier für antworten?


----------



## Alibi086 (28. Jan 2012)

Es ist doch völlig egal, um welche Sprache es hier geht (es handelte sich bei meinem Post lediglich um ein exemplarisches Ausgangsbeispiel), sondern um den technisch möglichen / unmöglichen Sachverhalt.


----------



## maki (28. Jan 2012)

Das ist nur deine Meinung


----------



## Cola_Colin (28. Jan 2012)

Bei Java könnte man z.B. Hibernate verwenden.


----------



## maki (28. Jan 2012)

Oder EclipseLink, oder MyBatis, Oder JDBC mit PreparedStatements


----------



## ARadauer (29. Jan 2012)

jo JPA


----------



## AmunRa (29. Jan 2012)

Ja man sollte reine SQL-Strings vermeiden und eher auf so was wie PreparedStatements oder ähnliches setzen. 

(Gilt aber nur im allgemeinen Fall und nicht in irgendwelchen speziellen)

PreparedStatements gibts eigentlich in fast jeder Sprache.


----------



## MasterK (30. Jan 2012)

maki hat gesagt.:


> Das ist nur deine Meinung



Nein. Denn wilde zusammengehackte SQL Statements habe ich bisher in allen möglichen Sprachen gesehen. VB, Java, C, C++, C#, Python, ECMAScript usw.

OR-Mapper sind idR nicht wirklich die Lösung für diese Frage. Einen wilden Join über dutzende Tabellen will keiner aufdröseln um ihn mittels JPA zu ersetzen. PreparedStatements helfen den Wildwuchs zu bekämpfen. Aber das ist, wie schon gesagt wurde, absolut nichts Java-spezifisches.

Daher ist die Frage in der Form absolut legitim.


----------



## anonymuss (2. Feb 2012)

maki hat gesagt.:


> Das ist nur deine Meinung





			
				Forum hat gesagt.:
			
		

> Softwareentwicklung
> Allgemeine Softwareentwicklung - Andere Programmiersprachen, Regex, OOP, Design Patterns



???:L


----------



## faetzminator (2. Feb 2012)

Es geht doch gar nicht darum, dass diese Query ein Join beinhaltet? Sondern dass sie nicht 1:1 so im Quellcode stehen soll. Und das kann man mit den oben geposteten Tools durchaus erreichen.


----------



## Evil-Devil (6. Feb 2012)

Spätestens bei den Joins steht das SQL wieder direkt im Source.

ActiveSet, JPA und Co sind ja schön und gut für das einzelne Objekt oder eine Liste der Objekte, aber bei Joins ist die Optimierung in sehr vielen Fällen alles andere als optimal. Vor allem bei jenen Joins die über drei und mehr Tabellen gehen.


----------



## turtle (6. Feb 2012)

Häh, verstehe ich nicht. Ich kann doch ein Prepared-Statement komplett mit Joins über n Tabellen schreiben, da steht nix im Source.

Ich stimme zu was Optimierungen angeht, daher bevorzuge ich myBATIS


----------



## Evil-Devil (6. Feb 2012)

ich kenne die Prepared Statements an sich nur von MySQLi in PHP und hab mir vorher extra die JPA angeschaut.

Sowohl in PHP als auch in JPA erschließt sich mit der Sinn nur schlecht. Bei Java würde ich zustimmen das durch die einmalige Laufzeit Erzeugung ein Vorteil entsteht. Dieser wäre bei PHP nicht gegeben. Denn das Prepared Statement wird jedes Mal neu erzeugt.

Denn wann benutzt man ein einzelnes Statement mehr als einmal pro Seite?

Vielleicht kann mich jemand erleuchten?


----------



## schalentier (6. Feb 2012)

Also zumindest Hibernate (als JPA) schickt immer Prepared Statements zur Datenbank. Das kann man meines Wissen nach, auch nicht abschalten.

Der Sinn ist, dass die DB dann gleiche Statements erkennt und nur noch die Variablen binden muss. D.h. das Parsen des Statements passiert nur noch einmal. Ob daraus tatsaechlich ein messbarer Performancegewinn entstehen kann, haengt von der Groesse, der Komplexitaet und der Anzahl der Statements ab.


----------



## Evil-Devil (6. Feb 2012)

Ja ok. Das leuchtet mir ein, allerdings scheint das stark vom DBMS abhängig zu sein.

Wir verwenden hier MySQL und das kann zb. bis 5.1.x den Cache nicht über Prepared Statements nutzen.


D.h. ein wirklicher Performance Gewinn kann erst bei ausreichend hoher Frequenz erzielt bzw. bemerkt werden. Sehe ich das richtig?


----------



## turtle (6. Feb 2012)

Ich sehe den grossen Vorteil von Prepared-Statements darin, dass die Applikation immun gegen SQL-Injection Angriffe ist.


----------



## AmunRa (6. Feb 2012)

Ich dachte auch immer das PreparedStatements die Möglichkeit von SQLInjection unterbindet oder bin ich da falsch informiert?


Edit: 





> Ich sehe den grossen Vorteil von Prepared-Statements darin, dass die Applikation immun gegen SQL-Injection Angriffe ist.



Damit hat sich meine Frage erübrigt.


----------



## MrWhite (6. Feb 2012)

Mein Gott, alle gleich so konkret.



			
				OP hat gesagt.:
			
		

> Es ist doch völlig egal, um welche Sprache es hier geht (es handelte sich bei meinem Post lediglich um ein exemplarisches Ausgangsbeispiel), sondern um den technisch möglichen / unmöglichen Sachverhalt.



Geht auch allgemeiner.

Ich poste hier einfach mal ein paar Links vom guten alten Martin Fowler:

P of EAA: Table Data Gateway
P of EAA: Row Data Gateway
P of EAA: Data Mapper
P of EAA: Active Record

Jetzt lies dann durch, dann biste heller. Ist *fast* universell anwendbar, *fast* sprachunabhängig.


----------



## Evil-Devil (7. Feb 2012)

turtle hat gesagt.:


> Ich sehe den grossen Vorteil von Prepared-Statements darin, dass die Applikation immun gegen SQL-Injection Angriffe ist.



Gibt es unter Java sowas wie mysql_real_escape() nicht? Ansonsten noch die GET/POST/COOKIE Daten escapen und prüfen und es wird zu keiner SQL Injection kommen.

Das Prepared Statements zu 100% gegen SQL Injection helfen sollen kann ich mir nur sehr schwer vorstellen, will es aber mal glauben.


----------



## tfa (7. Feb 2012)

> Gibt es unter Java sowas wie mysql_real_escape() nicht?


Nö, es gibt doch Prepared Statements. Da braucht man diesen elenden Frickelkram nicht


----------



## turtle (7. Feb 2012)

> Gibt es unter Java sowas wie mysql_real_escape() nicht?



Nein, braucht man auch nicht, weil Prepared-Statements zu 100% SQL Injection sicher sind 

Daneben halte ich das Escapen von SQL-Strings für einen Code-Smell. Man kann sich leider nicht sicher sein, ob ALLE SQL-Commands geeignet escaped werden und wenn nicht hat man ein GROSSES Sicherheitsproblem. Leider findet man diese erst zur Laufzeit und nicht durch einfaches Code-Review.


----------



## Evil-Devil (7. Feb 2012)

turtle hat gesagt.:


> Daneben halte ich das Escapen von SQL-Strings für einen Code-Smell. Man kann sich leider nicht sicher sein, ob ALLE SQL-Commands geeignet escaped werden und wenn nicht hat man ein GROSSES Sicherheitsproblem. Leider findet man diese erst zur Laufzeit und nicht durch einfaches Code-Review.



Ob geeignet oder nicht ist bei Typenlosen Sprachen wie PHP eine Frage des Aufwands. Wenn man erwartet das eine Variable eine Zahl und nicht ein String ist, dann kann man sie entsprechend escapen und übergeben.

zb.


```
$val = isset($_REQUEST['val']) && isNumeric($_REQUEST['val']) ? $_REQUEST['val'] : null;

// bei NULL abrechen....
// ...

$queryString = "select mycolumn from mytable where mycolumn = ".sqlEscape($val);
```

sqlEscape würde nun noch auf Numeric und String prüfen und bei einem String diesen für SQL entsprechend escapen.
Das man die Request Variablen noch mehr prüfen und manipulierne kann wie zb. Slashes hinzufügen oder entfernen ist mir klar, aber sollte jetzt nicht Bestandteil des Beispiels sein und wird erst bei LIKE Abfragen interessant.

Für mich kann ich also festhalten, Prepared Statements sind bei Java in erster Linie als Injection Schutz zu sehen und danach als Performance Gewinn.

Allerdings würde es mich interessieren wann der Injection Schutz auftritt. Prüft JPA auf eine mögliche Injection oder wie läuft das ab? Weil wenn man nur Blind Variablen übergibt kann imho weiterhin eine Injection auftreten.


----------



## XHelp (7. Feb 2012)

Evil-Devil hat gesagt.:


> Das Prepared Statements zu 100% gegen SQL Injection helfen sollen kann ich mir nur sehr schwer vorstellen


Zu 100% kannst du dich gegen SQL Injection absichern, in dem du auf die Verwendung von SQL verzichtest.
Aber PreparedStatements hilft besser gegen Injection als "vllt irgendwo irgendwann irgendwelche Daten mal unnütziger weise escapen oder dann ja vllt doch irgendwo vergessen, aber k.a. mehr wo, der Code ist mir jetzt zu lang"

P.S. Oh... es gab ja eine zweite Seite...


----------



## Gast2 (7. Feb 2012)

Nur mal so am Rande: Guckt euch mal alle Threads von diesem Flix2000 an und ob er nochmal antwortet. Ich würde sagen das er mit sehr großer Wahrscheinlichkeit ein Troll ist...


----------



## turtle (7. Feb 2012)

> Weil wenn man nur Blind Variablen übergibt kann imho weiterhin eine Injection auftreten



Nein, eben nicht.

Es werden ja keine Variablen in den SQL-Befehl irgendwie reingemixt, sondern es werden Variablen-*werte* an die Parameter *gebunden*.

Also wenn Dein SQL-Statement

```
select name, telefon from kunde where name=?
```
und beim Aufruf bindest Du den Parameter

```
preparedStatement.setString(1, "'1'; drop table kunde;");
```
wird das dennoch NICHT die Tabelle löschen.


----------



## Evil-Devil (7. Feb 2012)

Also muss man für nahezu jeden möglichen Parameterwert ein prepared Statement erzeugen oder wie läuft das zb. in einem Freitext Suchformular dann ab?

zb.:
[sql]
select vorname, nachname, strasse, hausnummer, ort
from adressaten
where vorname like '%evil%'
or nachname like '%devil%'
or ort like '%java-forum%'
[/sql]

Wie würde sowas mit einem Prepared Statement ausschauen?


----------



## tfa (7. Feb 2012)

Evil-Devil hat gesagt.:


> Wie würde sowas mit einem Prepared Statement ausschauen?



[sql]
select vorname, nachname, strasse, hausnummer, ort
from adressaten
where vorname like ?
or nachname like ?
or ort like ?
[/sql]

Die Parameter werden entsprechend gesetzt. Keine Injection möglich.


----------



## Evil-Devil (7. Feb 2012)

Ok, dann müsste ich mittels einer SChleife die Variablen 1 bis 3 befüllen, oder?
Entsprechend kann man dann auch dynamisch Queries zusammenkleben?



turtle hat gesagt.:


> Also wenn Dein SQL-Statement
> 
> ```
> select name, telefon from kunde where name=?
> ...


Ok, ein PS führt somit nur EIN Statement aus, anstatt der zwei die du da an sich hättest.


----------



## tfa (7. Feb 2012)

> Ok, dann müsste ich mittels einer SChleife die Variablen 1 bis 3 befüllen, oder?


Oder einfach 3 setParameter-Aufrufe hintereinander...



> Ok, ein PS führt somit nur EIN Statement aus, anstatt der zwei die du da an sich hättest.


Versteh ich nicht. Welche 2 Statements?


----------



## Evil-Devil (7. Feb 2012)

tfa hat gesagt.:


> Oder einfach 3 setParameter-Aufrufe hintereinander...


ja, wenn die Suche statisch ist.



tfa hat gesagt.:


> Versteh ich nicht. Welche 2 Statements?



Das bezog sich auf Turtles Beispiel.


turtle hat gesagt.:


> ```
> select name, telefon from kunde where name=?
> ```
> 
> ...



Das sind effektiv 2 Statements. Doch er schreibt ja das Drop Table nicht ausgeführt wird.


----------



## turtle (7. Feb 2012)

Schau Dir doch mal mein Lieblings-JDBC-Framework an: myBATIS

Damit können unter dem Stichwort Dynamic SQL sehr schön beispielsweise where-Klauseln eingefügt werden wenn bestimmte Inhalte in den zugrundeliegenden Java-Beans gefüllt sind.

Beispielsweise selektiert folgendes Statement all Blogs, wenn kein Titel angegeben wurde oder es gibt nur die Blogs mit dem angegeben Titel zurück.
[XML]<select id="findActiveBlogWithTitleLike" parameterType="Blog" resultType="Blog">
	SELECT * FROM BLOG WHERE state = 'ACTIVE'
	<if test="title != null">
		AND title like #{title}
	</if>
</select>[/XML]
Oder eine in-Klausel:
[XML]    <select id="selectPostIn" resultType="Group" parameterType="List">
		SELECT ADDRESS, PHONE FROM GROUPS G WHERE ADDRESS in
			<foreach item="item" index="index" collection="list" open="(" separator="," close=")">
				#{item}
			</foreach>
	</select>[/XML]
Aufruf via

```
sqlSession.selectList("Group.selectPostIn", Arrays.asList(new String[] {"T1", "T2"}));
```


----------



## tfa (7. Feb 2012)

> Das sind effektiv 2 Statements. Doch er schreibt ja das Drop Table nicht ausgeführt wird.


Ich denke, das war nur ein Beispiel für eine besonders böse SQL-Injection.


----------



## Evil-Devil (7. Feb 2012)

@myBatis: SChaue ich mir mal an. Hab zwar noch keine DB unter Java genutzt, was nicht ist kann ja noch werden.

@tfa: Ja, die ist böse nur für einen Angreifer nutzlos. Interessant sind Injections imho überall wo mehrere Statements mit nur einer Abfrage ausgelöst werden können.


----------



## Gast2 (7. Feb 2012)

Evil-Devil hat gesagt.:


> Gibt es unter Java sowas wie mysql_real_escape() nicht? Ansonsten noch die GET/POST/COOKIE Daten escapen und prüfen und es wird zu keiner SQL Injection kommen.
> 
> Das Prepared Statements zu 100% gegen SQL Injection helfen sollen kann ich mir nur sehr schwer vorstellen, will es aber mal glauben.



Sind sie... Bind Parameter können NIEMALS den Query aufbrechen. Ein mysql_real_escape() kann dagegen gefährlich werden da sich drauf verlassen wird das schon alle Möglichkeiten den Query zu brechen abgeprüft werden.


----------



## Gast2 (7. Feb 2012)

Whoops... much too late...


----------



## bronks (11. Feb 2012)

Evil-Devil hat gesagt.:


> ... zb.:
> [sql]
> select vorname, nachname, strasse, hausnummer, ort
> from adressaten
> ...


Ja, moment mal. Würden eure Datenbanken wirklich etwas ausführen, wenn in o.g. SQL statt 'evil' ein 'drop table kunde;' stehen würde?


----------



## tfa (11. Feb 2012)

> wenn in o.g. SQL statt 'evil' ein 'drop table kunde;' stehen würde?


Probier's mal mit [c]'; drop table kunde; --[/c]


----------



## bronks (11. Feb 2012)

tfa hat gesagt.:


> Probier's mal mit [c]'; drop table kunde; --[/c]


Ja, logisch. Echt raffiniert den Rest wegzukommentieren.


----------



## _Andi91 (13. Feb 2012)

Ín PHP gibt es übrigens auch preparedStatements. Ich glaub die Klasse um preparedStatements zu erzeugen heist PDO.


----------



## HimBromBeere (14. Feb 2012)

> Ansonsten noch die GET/POST/COOKIE Daten escapen und prüfen und es wird zu keiner SQL Injection kommen.


Prinzipiell richtig, im Detail aber manchmal ganz schön hakelig... das Problem ist weniger das Escapen als vielmehr das Auffinden "böser" Zeichenketten. Denn sowas wie ein einfaches Einführungszeichen oder ein doppeltes kann man auch einfach ASCII-Zeichen kodieren (z.B. %20 für Leerzeichen oder was auch immer). Wie auch immer... das Verwenden von PreparedSatements ist tatsächlich die einzige effektive Methode gegen Injection... habe zumindest bisher noch kein Schlupfloch finden können...


----------



## Evil-Devil (14. Feb 2012)

HimBromBeere hat gesagt.:


> Prinzipiell richtig, im Detail aber manchmal ganz schön hakelig... das Problem ist weniger das Escapen als vielmehr das Auffinden "böser" Zeichenketten. Denn sowas wie ein einfaches Einführungszeichen oder ein doppeltes kann man auch einfach ASCII-Zeichen kodieren (z.B. %20 für Leerzeichen oder was auch immer). Wie auch immer... das Verwenden von PreparedSatements ist tatsächlich die einzige effektive Methode gegen Injection... habe zumindest bisher noch kein Schlupfloch finden können...


Für %20 und Co gibt es Encode und RawEncode. Also kein Argument 

@PDO: PDO ist eine Extension die DBMS Zugriffe vereinfacht und abstrahiert. Die Prepared Statements werden für MySQL unter PHP nur über die MySQLi Extension unterstützt.


----------

