Top 10 REST API Security Mistakes and How to Fix Them

REST APIs are the foundation of modern web and mobile applications. However, poor API security can expose sensitive data, making your application vulnerable to attacks like data breaches, unauthorized access, and injection attacks.

In this article, we’ll cover 10 common REST API security mistakes and how to fix them with best practices. To demonstrate each mistake, we will use Java and Spring Boot examples.


1️⃣ Exposing Sensitive Data in API Responses 🔓

Mistake: Returning Passwords, API Keys, or Internal Data

Some developers accidentally expose sensitive information in API responses.

Bad Example:

{
    "id": 1,
    "email": "user@example.com",
    "password": "mypassword123",
    "apiKey": "XYZ-SECRET-123"
}

Risk:

  • Hackers can steal credentials and gain unauthorized access.
  • Exposed API keys can compromise your entire system.

Solution: Use DTOs and Restrict Fields

Use Data Transfer Objects (DTOs) to control what data is returned.

Good Example:

public record UserDTO(Long id, String email) {}
@GetMapping("/users/{id}")
public UserDTO getUser(@PathVariable Long id) {
    User user = userRepository.findById(id).orElseThrow();
    return new UserDTO(user.getId(), user.getEmail());
}

Best Practices:

  • Never return passwords, API keys, or tokens in API responses.
  • Use DTOs to expose only necessary fields.

2️⃣ Lack of Proper Authentication and Authorization 🔑

Mistake: No Authentication

APIs that don’t require authentication are open to anyone, allowing unauthorized users to access private data.

Bad Example:

@GetMapping("/admin/users")
public List<User> getAllUsers() {
    return userService.getAllUsers();  // ❌ No security check
}

Solution: Secure API with JWT or OAuth2

Use OAuth2 or JWT (JSON Web Tokens) for secure authentication.

Good Example (Spring Security with JWT)

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
            .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
        return http.build();
    }
}

Best Practices:

  • Use token-based authentication (JWT/OAuth2).
  • Restrict access using role-based authorization.

3️⃣ Not Using HTTPS (SSL/TLS) 🔐

Mistake: Using HTTP Instead of HTTPS

APIs over HTTP are vulnerable to man-in-the-middle (MITM) attacks where attackers can steal data.

Solution: Enforce HTTPS

Enable HTTPS in Spring Boot

server:
  ssl:
    key-store: classpath:keystore.p12
    key-store-password: changeit
    key-store-type: PKCS12
  port: 8443

Best Practices:

  • Always use HTTPS to encrypt API communication.
  • Redirect HTTP to HTTPS using security policies.

4️⃣ Using Weak API Keys or Static Tokens 🔑

Mistake: Using Hardcoded API Keys

Storing API keys inside the source code is a serious security risk.

Bad Example:

String API_KEY = "my-secret-api-key";  // ❌ Hardcoded API key

Solution: Store API Keys Securely

Best Practices:

  • Use environment variables to store API keys.
  • Rotate API keys periodically.
  • Use secret management tools like AWS Secrets Manager or HashiCorp Vault.

5️⃣ Not Implementing Rate Limiting & Throttling 🚦

Mistake: No Rate Limiting

If an API doesn’t have rate limiting, attackers can flood requests, causing DDoS (Denial-of-Service) attacks.

Solution: Implement Rate Limiting

Good Example (Using Spring Rate Limiting)

@Bean
public RateLimiter rateLimiter() {
    return RateLimiter.create(10.0); // Allows 10 requests per second
}

Best Practices:

  • Use Rate Limiting (e.g., 10 requests per second per IP).
  • Implement API Gateway solutions like Kong, Nginx, or AWS API Gateway.

6️⃣ Improper Input Validation (SQL Injection & XSS) 🛑

Mistake: Accepting Unvalidated Input

@PostMapping("/users")
public ResponseEntity<String> createUser(@RequestBody User user) {
    return ResponseEntity.ok("User Created");
}

Risk:

  • SQL Injection: Attackers can manipulate database queries.
  • Cross-Site Scripting (XSS): Attackers inject malicious JavaScript.

Solution: Use Validation Annotations

Good Example:

public record UserDTO(@NotBlank String name, @Email String email) {}
@PostMapping("/users")
public ResponseEntity<String> createUser(@Valid @RequestBody UserDTO userDTO) {
    return ResponseEntity.ok("User created successfully");
}

Best Practices:

  • Use @Valid annotations for input validation.
  • Sanitize inputs to prevent injection attacks.

7️⃣ Returning Generic Error Messages

Mistake: Exposing Internal Server Errors

@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) {
    return userRepository.findById(id).get(); // ❌ Throws 500 Internal Server Error
}

Solution: Use Global Exception Handling

Good Example:

@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(ResourceNotFoundException.class)
    public ResponseEntity<String> handleNotFound(ResourceNotFoundException ex) {
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ex.getMessage());
    }
}

Best Practices:

  • Do not expose stack traces in API responses.
  • Return meaningful error messages (e.g., User not found instead of NullPointerException).

8️⃣ Exposing API Endpoints Without Authentication 🔓

Mistake: Public API Endpoints

@GetMapping("/admin/data")
public List<User> getAdminData() {
    return adminService.getAllData();  // ❌ No authentication
}

Solution: Secure Endpoints with Role-Based Access Control (RBAC)

@PreAuthorize("hasRole('ADMIN')")
@GetMapping("/admin/data")
public List<User> getAdminData() {
    return adminService.getAllData();
}

Best Practices:

  • Use @PreAuthorize for role-based access control (RBAC).
  • Do not expose sensitive endpoints without authentication.

9️⃣ No Logging or Monitoring 📜

Mistake: No Logging

Without logging, it’s impossible to track suspicious activity.

Solution: Use SLF4J for API Logging

@Slf4j
@RestController
@RequestMapping("/users")
public class UserController {
    @GetMapping("/{id}")
    public ResponseEntity<UserDTO> getUser(@PathVariable Long id) {
        log.info("Fetching user with id: {}", id);
        return ResponseEntity.ok(userService.getUserById(id));
    }
}

Best Practices:

  • Log all API requests & responses.
  • Use monitoring tools like Prometheus & Grafana.

🔟 Not Documenting APIs (No Swagger UI) 📖

Mistake: No API Documentation

Without API documentation, developers struggle to use your API.

Solution: Use Swagger UI

<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
    <version>2.8.3</version>
</dependency>

Best Practices:

  • Use OpenAPI (Swagger) for documentation.
  • Provide clear API usage guidelines.

🎯 Conclusion

Securing REST APIs is critical to prevent unauthorized access, data breaches, and cyber-attacks.

Quick Recap

Use HTTPS for secure communication
Implement JWT/OAuth2 authentication
Validate input to prevent injection attacks
Use role-based authorization (RBAC)
Implement API rate limiting

REST API security, API best practices, Secure API authentication, OAuth2, JWT, Rate limiting, API vulnerabilities, Spring Boot security

Comments

Spring Boot 3 Paid Course Published for Free
on my Java Guides YouTube Channel

Subscribe to my YouTube Channel (165K+ subscribers):
Java Guides Channel

Top 10 My Udemy Courses with Huge Discount:
Udemy Courses - Ramesh Fadatare