SpringBoot is one of the best frameworks to build RESTful APIs.Data breaches are becoming more common and it is high time for us developers to secure our APIs. It comes with handy ways to secure the services by applying some of the principles we will be discussing today on how to secure your Spring Boot Maven APIs and prevent SQL injection.
SQL Injection Explained is an attack where an attacker introduces a malicious SQL code to a database query that grants them access/modify the data in the DB. This usually happens when input is not correctly validated before implementing the query
SQL Injection Prevention
Use Prepared Statements
Prepared statements are a parameterized query that separates the SQL code from the user input. This prevents the user input from being interpreted as SQL code. Prepared statements can be used with JDBC or JPA.
Here’s an example of using a prepared statement with JDBC:
String sql = "SELECT * FROM users WHERE username =? AND password = ?";
PreparedStatement statement = connection.prepareStatement(SQL);
statement.setString(1, username);
statement.setString(2, password);
ResultSet result = statement.executeQuery();
Implement Object-Relational Mapping (ORM)
ORM frameworks like Hibernate and Spring Data JPA provide a way to map Java objects to database tables. the SQL code will not be written manually hence eliminating the risk of SQL injection due to fewer human interactions.
Here’s an example of using Spring Data JPA:
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
User findByUsernameAndPassword(String username, String password);
}
3. User Input validation
Sanitizing user input involves removing or encoding characters that can be interpreted as SQL code. an example is using the libraries like OWASPJava Encoder or ESAPI.
OWASP Java Encoder Example:
String encodedUsername = ESAPI.encoder().encodeForSQL(new MySQLCodec(MySQLCodec.Mode.STANDARD), username);
String encodedPassword = ESAPI.encoder().encodeForSQL(new MySQLCodec(MySQLCodec.Mode.STANDARD), password);
4. Remove unrequired Database Permissions
Limiting database permissions reduces the impact of a successful SQL injection attack. It’s essential to give each user only the necessary permissions to perform their tasks. For example, users who only need to read data from a table should not have write permissions.
How to Secure Spring Boot Maven APIs?
1.Use HTTPS
HTTPS encrypts data in transit, preventing attackers from intercepting sensitive information. we can make use of the self-signed certificate provided by Springboot another alternative is to use one from a trusted authority.
Here’s an example of enabling HTTPS in Spring Boot:
```properties
server.ssl.key-store-type=PKCS12
server.ssl.key-store=classpath:keystore.p12
server.ssl.key-store-password=changeit
server.ssl.key-alias=tomcat
2.Use Authentication and Authorization
Authentication allows us to verify user identity, whereas authorization refers to what actions the user is allowed to perform. Spring Security provides the most reliable options to implement Authorization and authentication
using Spring Security example:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/user/**").hasAnyRole("USER", "ADMIN")
.anyRequest().authenticated()
.and().formLogin();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
3.Usage Rate Limiting
Rate limiting limits the number of requests a user can make within a certain period of time. This prevents attackers from overwhelming your API with requests and helps maintain the availability of your API.
Here’s an example of using Spring Boot Rate Limit:
@Configuration
public class RateLimitConfig {
@Bean
public RateLimiter rateLimiter() {
return RateLimiter.of("user", 10, Duration.ofMinutes(1));
}
@Bean
public KeyResolver keyResolver() {
return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
}
@Bean
public RedisRateLimiter redisRateLimiter(RedisConnectionFactory connectionFactory) {
return new RedisRateLimiter(rateLimiter(), keyResolver(), connectionFactory);
}
}
Conclusion
By using prepared statements, ORM frameworks, sanitizing user input, limiting database permissions, HTTPS, authentication and authorization, and rate limiting, you can significantly reduce the risk of a successful attack.
Leave a Reply