im running Checkmarx on my code and im getting an sql injection vulnerability.
this is the simplified method im using
public String assignRole(String userId, String roleId) {
Optional<RoleEntity> roleEntity = roleRepository.findById(roleId)
if (roleEntity.isPresent()) {
UserEntity user = UserEntity.builder().userId(userId).role(roleEntity.get()).build();
userRepository.save(user);
return "SUCCESS";
} else {
throw new ServiceException("ERROR");
}}
and the analysis of checkmax says:
The application's assignRole method executes an SQL query with save, at line xx of
src/Service.java. The application
constructs this SQL query by embedding an untrusted string into the query without proper sanitization. The
concatenated string is submitted to the database, where it is parsed and executed accordingly.
An attacker would be able to inject arbitrary syntax and data into the SQL query, by crafting a malicious
payload and providing it via the input roleId;
This may enable an SQL Injection attack.
im a little bit confused because im not building a native query or concatenating strings in a query, or maybe im missing something.
any ideas for fix this? or maybe is a false positive.
This sounds like a false positive.
If your Java code uses Spring, I recommend configuring your scan (Settings > Scan Settings > Preset Manager) with the SQL_Injection and Second_Order_SQL_Injection items under the Java section disabled (unchecked) to avoid false positives from these items.
If your code persists data to the database exclusively via the Spring save action, it is not at risk of SQL injection exploitation. That’s because Spring saves (inserts or updates) to the database using an object mapped to your db (the ORM approach) which does not allow additional sql to be maliciously forced in.
Nonetheless, from what I’ve seen, Checkmarx marks Spring save actions, falsely, as high severity SQL Injection vulnerabilities (SQL_Injection and/or Second_Order_SQL_Injection). Given this, disabling those rules seems to me valid and in fact the only viable way around this.
But if you do take this approach, make sure your code does not for some reason also use some other some other sql approach such as a String containing SQL that’s not sanitized via the use of PreparedStatement. Those statements are vulnerable to sql injection exploits and I believe are what the Checkmarx SQL injection rules are intending to identify.
Related
I have a requirement to capture changes to certain data. I am looking to capture the following details:
Table Name the change occurred in
Column Changed
Previous Value
Updated Value
I suggested to our Technical lead that this can be accomplished easily with DB Triggers. I was told we do not control the DB and do not have a way of adding Triggers.
I am currently using Spring AspectJ with a custom annotation and wrapping my services to try and capture the generated SQL (I figure parsing SQL is much easier that trying to capture with Objects) that's executed after the 'save' method is called, however I have not found a way to trap the generated SQL.
I tried p6Spy and was able to view the SQL and print it to the console, but was told we cannot wrap our db drivers in our PROD environment.
Is there a Spring class I am missing to make this easier?
EDIT : We're using Spring Repositories to save the data.
EDIT 2: I'm looking into EventListeners, however I cannot seem to get them to listen to my events.
#Component
public class EventListner implements PreInserEventListener, PreUpdateEventListener {
#Override
#EventListener
public boolean onPreUpdate(PreUpdateEvent event){
// do something
return false;
}
#Override
#EventListener
public boolean onPreInsert(PreUpdateEvent event){
// do something
}
return false
}
I have break points around my Listener, however they're never reached.
This question looks like it might address my issue
If you are absolutely sure that every insert/update/delete is done through JPA without any bulk SQL then you should take a look at envers
With that you can use #Audited on the entities(all column) OR columns of entities you wish to keep history.
This will create 1 revision table with timestamp change (and other data you want like uid of the user that made the change), and 1 table per entity with the old value of the modified data.
For every data you can then retrieve the history and previous value.
one other way is to add instrument on your DB like a Change Data Capture (CDC) tools and push those event to another data repository.
On the + side everything will be detected (even native SQL run directly on the DB). Drawback, your DB need to support this kind of tools correctly. For instance tools like kafka-connect can work like you want, but some implementations are too simple (like with SAP hana for instance where the process is to do a select * from xxx).
I finally settled on using Hibernate interceptors to do the trick. Works perfectly!
public class TableInterceptor extends EmptyInterceptor {
#Override
public boolean onFlushDirty(Object entity, Serializable id,
Object[] currentState, Object[] previousState,
String[] propertyNames, Type[] types){
// do comparison logic on fields and save to DB
}
}
I bootstrapped the interceptor injecting it into my LocalContainerEntityManagerFactoryBean
This question already has answers here:
How to prevent SQL Injection with JPA and Hibernate?
(5 answers)
Closed 5 years ago.
I'm Using Struts2 Framework and Hibernate, I'm Enhancing a System that I didn't started, I enhanced some features of the system and implement it on the prod. But when they scan it using Acunetix, Somewhere in Login Module, there are some threats(alerts) that are detected in the System wherein the alert says:
Alert: SQL injection
Severity: High
Description: This script is possibly vulnerable to SQL Injection attacks.
Recommendation: Your script should filter metacharacters from user input. Check detailed information for more information about fixing
this vulnerability.
And then, I checked the Script that would be the fault on that alert. The Old Developer uses Hibernate to create a query.
List<UserBean> users = session.createQuery("from UserBean where username =?")
.setParameter(0,username)
.list();
My Question is:
-Is this Query using Hibernate can't Avoid SQL Injection?
-Is .setParameter should be .setString to be more specific to avoid SQL Injection?
or None of the Above ?
Thanks for the time.
If you use the Hibernate query parameter binding like this you are safe from SQL injection attacks.
In opposite to string concatenation, setParameter will fill the placeholders of the query after creating the prepared statement and before execution of the query, and the query processing engine knows which (probably malicious) chars should be escaped.
This is the common way to go.
setString is the non-generic pendant to setParameter. setParameter detects the datatype automatically.
A small improvement would be to use named parameter binding, e.g.:
List<UserBean> users = session.createQuery("from UserBean where username = :username")
.setParameter("username", username)
.list();
This way you will not get more problems with more parameters in the future.
I have been facing the second order SQL injection in this following code
if(subjectId!=null){Query query= sessionFactory
.getCurrentSession()
.createSQLQuery(HubQueryConstants.GET_QUERY)
.setParameter(MyConstants.SUBJECT_ID, subjectId)
.setFirstResult(offset)
.setMaxResults(limit)
.setResultTransformer(
Transformers.aliasToBean(MyClass.class));}
My Constant file is :
Constant file is Final class
GET_QUERY="Select * from MyClass where id=:id ";
though it is in static query by default still my security report is giving it as Second order SQL injection
Should we declare constants in interface? to avoid Security issue?
A SQL injection occurs, when a placeholder is replaced with a SQL term that alters the original SQL string so that the SQL does something different than intened.
You can find more details at SQL_injection
SQL injection happens when the placeholder of the parameters are replaced. So declaring constants instead of reading the SQL from a properties file does not help. The injection happens later, independently from where the SQL string was obtained.
The easiest way to prevent SQL injection is by using prepared statements.
When a prepared statement is executed, the SQL string and the parameters are handled completely seperate by the SQL server, making SQL injection impossible.
With JPA you can use the annotation javax.persistence.NamedNativeQuery; to declare a SQL query that will be executed as prepared statement.
You find a tutorial using NamedNativeQuers at the end of jpa-native-queries
I have a system that uses a Oracle database, with a schema that is different from the application user. The schema name itself is not known in advance, so we can't just hardcode it. It's a system property.
Most of the data access is through Hibernate, which can specify the default schema on connection so this is not a problem in those cases.
However, there are a few places where plain SQL queries are used (using spring jdbcTemplate). So right now we have something that boils down to:
Map<String,Object> result = jdbcTemplate.queryForMap("SELECT A, B, C FROM "+schema+".TABLE WHERE blablablah");
And this, of course, is an open SQL injection vulnerability. We're planning security audits and this will be flagged for sure.
So the question is: How do I specify the schema on the query, be it with jdbcTemplate, another Sprint data access utility, or even plain jdbc?
Thank you,
JGN
You can use Connection.setSchema to specify the schema for a JDBC connection. This should be done before you create the Statement to execute a SQL command.
With Spring JPA is there an easy way to use native queries but maintaining database independence, for example by using the query which fits best?
At the moment I do this by checking the currently set Dialect from the Environment and call the proper method of my Repository:
public Foo fetchFoo() {
if (POSTGRES_DIALECT.equals(env.getRequiredProperty("hibernate.dialect"))) {
return repo.postgresOptimizedGetFoo();
}
return repo.getFoo();
}
This works but I have the feeling that there is a better way or that I am missing something. Especially because (Spring) JPA allows it to use native queries quite easily but that breaks one of its big advantages: database independence.
As per my understanding, this can be achieved simply by using #Transactional(readOnly=false) and then instead of calling session.createQuery, one can use session.createSQLQuery, as provided in this example.
Your sql can be any of your native query.
Hope this works for you. :)
#Override
#Transactional(readOnly = false)
public Long getSeqVal() {
Session session = entityManager.unwrap(Session.class);
String sql = "SELECT nextval('seqName')";
Query query = session.createSQLQuery(sql);
BigInteger big = (BigInteger) query.list().get(0);
return big.longValue();
}
This is just an idea: I do not know whether it works or not:
My idea would be having subinterfaces, one normal Spring-Data-JPA-interface with all methods for one entiy (without native query hints). Than I would crate a subinterface for every database, that "override" the database specific native statements. (This intrface would be empty if there are no DB specific statements). Then I would try configure Spring-JPA with some profiles to load the right specific interface (for example by a class-name or package-name-pattern)
This seems like a way to complicated way to get queries to work.
If you really want to use optimized queries make it at least transparant for your code. I suggest using named queries and create an orm.xml per database (much like Spring Boot uses to load the schema.xml for a different database).
In your code you can simply do
public interface YourRepository extends JpaRepository<YourEntity, Long> {
List<YourEntity> yourQueryMethod();
}
This will look for a named query with the name YourEntity.yourQueryMethod. Now in your orm.xml add the named query (the default one and in another one the optimized one).
Then you need to configure your LocalContainerEntityManagerFactory to load the specific one needed. Assuming you have a property defining which database you use, lets name it database.type you could do something like the following
<bean class="LocalContainerEntityManagerFactoryBean">
<property name="mappingResources" value="classpath:META-INF/orm-${database.type}.xml" />
... other config ...
</bean>
This way you can keep your code clean of the if/then/else construct and apply where needed. Cleans your code nicely imho.