Hallo,
ich halte es derzeit so, dass ich von meiner CDI Bean "Such-Objekte" in meinen EJB Container weitergebe, die die Parameter und deren Value für meine WHERE Clause Abfrage enthält. Ich möchte nicht für jede einzelne Query, die ich irgendwann mal benötige eine eigene Funktion erstellen....
-> Zunächst muss ich sagen, dass das funktioniert und meine Queries auch immer das richtige Ergebnis zurückgeben.
Allerdings bin ich mir nicht sicher, ob ich hierdurch mir eventuell Sicherheitslücken baue? Ggf. buse ich auch etwas an Performance ein?
Wie es mir scheint, wäre hierdurch dann SQL Injection möglich?
Hierzu habe ich dann eine Klasse "ObjectForSearchList":
Beispiel:
CDI Bean:
EJB
Hier habe ich eine Methode, die mir die WHERE Clause zusammenbastelt:
Und die Methode zum Suchen sieht eben so aus:
-> Hier ist dann der Aufruf von createQuery(searchList), welches mir die WHERE Clause als String zurückgibt...
Wie könnte ich das anderst lösen? Primär geht es mir um Sicherheit. Funktionieren tut es ja...
Zudem suche ich hierüber nicht immer nur Attribute ab, sondern ich habe zB auch sowas:
searchList.add(new ObjectForSearchList("findMyUsers", 1));
-> Hiermit baue ich ich dann in der createQuery() mir ein SubSelect user.id = (Select.... FROM UserClass u WHERE i.id = o.getSearchValue())
Leider habe ich mein ganzes Projekt mittlerweile so aufgebaut - und das über 100 Klassen, die ich dann anpassen müsste...
Danke für die Hilfe...
ich halte es derzeit so, dass ich von meiner CDI Bean "Such-Objekte" in meinen EJB Container weitergebe, die die Parameter und deren Value für meine WHERE Clause Abfrage enthält. Ich möchte nicht für jede einzelne Query, die ich irgendwann mal benötige eine eigene Funktion erstellen....
-> Zunächst muss ich sagen, dass das funktioniert und meine Queries auch immer das richtige Ergebnis zurückgeben.
Allerdings bin ich mir nicht sicher, ob ich hierdurch mir eventuell Sicherheitslücken baue? Ggf. buse ich auch etwas an Performance ein?
Wie es mir scheint, wäre hierdurch dann SQL Injection möglich?
Hierzu habe ich dann eine Klasse "ObjectForSearchList":
Java:
public class ObjectForSearchList {
private String searchName;
private String searchValue;
private Date searchValueDate;
private List<String> searchValueStringList;
private double searchNameNumber;
private double searchValueNumber;
private String dataType;
public ObjectForSearchList(String searchName, String searchValue) {
super();
this.searchName = searchName;
this.searchValue = searchValue;
}
public ObjectForSearchList() {
super();
}
public ObjectForSearchList(String searchName, double searchValueNumber) {
super();
this.searchName = searchName;
this.searchValueNumber = searchValueNumber;
}
public ObjectForSearchList(String searchName, String searchValue, String dataType) {
super();
this.searchName = searchName;
this.searchValue = searchValue;
this.dataType = dataType;
}
public ObjectForSearchList(double searchNameNumber, double searchValueNumber) {
super();
this.searchNameNumber = searchNameNumber;
this.searchValueNumber = searchValueNumber;
}
public Date getSearchValueDate() {
return searchValueDate;
}
public void setSearchValueDate(Date searchValueDate) {
this.searchValueDate = searchValueDate;
}
public double getSearchNameNumber() {
return searchNameNumber;
}
public void setSearchNameNumber(double searchNameNumber) {
this.searchNameNumber = searchNameNumber;
}
public String getSearchName() {
return searchName;
}
public void setSearchName(String searchName) {
this.searchName = searchName;
}
public String getSearchValue() {
return searchValue;
}
public void setSearchValue(String searchValue) {
this.searchValue = searchValue;
}
public String getDataType() {
return dataType;
}
public void setDataType(String dataType) {
this.dataType = dataType;
}
public double getSearchValueNumber() {
return searchValueNumber;
}
public void setSearchValueNumber(double searchValueNumber) {
this.searchValueNumber = searchValueNumber;
}
public List<String> getSearchValueStringList() {
return searchValueStringList;
}
public void setSearchValueStringList(List<String> searchValueStringList) {
this.searchValueStringList = searchValueStringList;
}
@Override
public String toString() {
return "ObjectForSearchList [searchName=" + searchName + ", searchValue=" + searchValue + ", searchValueDate="
+ searchValueDate + ", searchValueStringList=" + searchValueStringList + ", searchNameNumber="
+ searchNameNumber + ", searchValueNumber=" + searchValueNumber + ", dataType=" + dataType + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((dataType == null) ? 0 : dataType.hashCode());
result = prime * result + ((searchName == null) ? 0 : searchName.hashCode());
long temp;
temp = Double.doubleToLongBits(searchNameNumber);
result = prime * result + (int) (temp ^ (temp >>> 32));
result = prime * result + ((searchValue == null) ? 0 : searchValue.hashCode());
result = prime * result + ((searchValueDate == null) ? 0 : searchValueDate.hashCode());
temp = Double.doubleToLongBits(searchValueNumber);
result = prime * result + (int) (temp ^ (temp >>> 32));
result = prime * result + ((searchValueStringList == null) ? 0 : searchValueStringList.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ObjectForSearchList other = (ObjectForSearchList) obj;
if (dataType == null) {
if (other.dataType != null)
return false;
} else if (!dataType.equals(other.dataType))
return false;
if (searchName == null) {
if (other.searchName != null)
return false;
} else if (!searchName.equals(other.searchName))
return false;
if (Double.doubleToLongBits(searchNameNumber) != Double.doubleToLongBits(other.searchNameNumber))
return false;
if (searchValue == null) {
if (other.searchValue != null)
return false;
} else if (!searchValue.equals(other.searchValue))
return false;
if (searchValueDate == null) {
if (other.searchValueDate != null)
return false;
} else if (!searchValueDate.equals(other.searchValueDate))
return false;
if (Double.doubleToLongBits(searchValueNumber) != Double.doubleToLongBits(other.searchValueNumber))
return false;
if (searchValueStringList == null) {
if (other.searchValueStringList != null)
return false;
} else if (!searchValueStringList.equals(other.searchValueStringList))
return false;
return true;
}
}
Beispiel:
CDI Bean:
Java:
List<ObjectForSearchList> searchList = new ArrayList<ObjectForSearchList>();
searchList = new ArrayList<ObjectForSearchList>();
searchList.add(new ObjectForSearchList("idHash", chatUserId));
chatUser = chatUserService.findChatUserByQuery(searchList);
EJB
Hier habe ich eine Methode, die mir die WHERE Clause zusammenbastelt:
Java:
/**
* Query erstellen
*
* @param searchList
* @return
*/
private StringBuilder createQuery(List<ObjectForSearchList> searchList) {
StringBuilder where = new StringBuilder();
// Search
int andValues = 0;
for (ObjectForSearchList o : searchList) {
if (andValues == 0)
where.append(" WHERE ");
if (o.getSearchName().equals("idHash") && o.getSearchValue() != null) {
if (andValues != 0)
where.append(" AND ");
where.append(" m.idHash = '" + o.getSearchValue() + "'");
andValues++;
}
// Where löschen, wenn nichts in WHERE - Clause
if (andValues == 0) {
where = new StringBuilder();
}
}
return where;
}
Und die Methode zum Suchen sieht eben so aus:
-> Hier ist dann der Aufruf von createQuery(searchList), welches mir die WHERE Clause als String zurückgibt...
Java:
/**
* Filtern
*/
public ChatUser findChatUserByQuery(List<ObjectForSearchList> searchList) {
LOGGER.debug("START findChatUserByQuery");
ChatUser chatUser = null;
try {
StringBuilder queryCount = new StringBuilder("SELECT m FROM ChatUser m");
StringBuilder where = new StringBuilder();
StringBuilder orderBy = new StringBuilder(" ORDER BY m.id ASC");
String theQuery = "";
theQuery = queryCount.toString();
// WHERE Clause
where = createQuery(searchList);
queryCount.append((where == null ? "" : where));
queryCount.append((orderBy == null ? "" : orderBy));
theQuery = queryCount.toString();
LOGGER.debug("QUERY: " + theQuery);
Query q = entityManager.createQuery(theQuery);
chatUser = (ChatUser) q.getSingleResult();
if (chatUser == null)
return null;
} catch (Exception e) {
return null;
}
LOGGER.debug("Find ChatUser with ID: " + chatUser.getId());
LOGGER.debug("END findChatUserByQuery");
return chatUser;
}
Wie könnte ich das anderst lösen? Primär geht es mir um Sicherheit. Funktionieren tut es ja...
Zudem suche ich hierüber nicht immer nur Attribute ab, sondern ich habe zB auch sowas:
searchList.add(new ObjectForSearchList("findMyUsers", 1));
-> Hiermit baue ich ich dann in der createQuery() mir ein SubSelect user.id = (Select.... FROM UserClass u WHERE i.id = o.getSearchValue())
Leider habe ich mein ganzes Projekt mittlerweile so aufgebaut - und das über 100 Klassen, die ich dann anpassen müsste...
Danke für die Hilfe...