Full Stack • Java • System Design • Cloud • AI Engineering

Java Application Security Fundamentals

Learn Java Application Security fundamentals with Spring Boot, authentication, authorization, password hashing, secure API design, input validation, logging, secrets management, and production security best practices.

Introduction

Security is one of the most important parts of modern Java application development.

A Java application may have clean code, good performance, and scalable architecture, but if it is not secure, attackers can exploit it.

Common security issues include:

  • Weak authentication
  • Broken authorization
  • Plain text passwords
  • SQL injection
  • Exposed secrets
  • Insecure APIs
  • Sensitive data in logs
  • Missing HTTPS
  • Poor error handling
  • Missing input validation

This article explains Java application security fundamentals step by step with diagrams and Spring Boot implementation examples.


1. What is Application Security?

Application Security means protecting software from unauthorized access, data leaks, attacks, and misuse.

flowchart TB

User["User / Client"]
--> App["Java Application"]

App --> Auth["Authentication"]
App --> Authz["Authorization"]
App --> Validation["Input Validation"]
App --> Data["Secure Data Access"]
App --> Logs["Secure Logging"]
App --> Secrets["Secrets Management"]

Application security protects:

  • Users
  • APIs
  • Business logic
  • Databases
  • Files
  • Secrets
  • Logs
  • Infrastructure

2. Why Security Matters in Java Applications

Imagine a banking application.

Users can:

  • Login
  • View accounts
  • Transfer money
  • Download statements
  • Update profile

If security is weak:

flowchart LR

Attacker["Attacker"]
--> WeakLogin["Weak Login"]
--> AccountData["Customer Account Data"]
--> Loss["Financial / Data Loss"]

A secure application must prevent:

  • Unauthorized login
  • Access to another user's data
  • Password theft
  • API abuse
  • Data tampering
  • Sensitive data exposure

3. Core Security Concepts

Every Java developer should understand these concepts:

mindmap
  root((Java Security))
    Authentication
    Authorization
    Password Hashing
    Input Validation
    Secure APIs
    Data Protection
    Secrets Management
    Secure Logging
    Error Handling
    Monitoring

4. Authentication

Authentication answers this question:

Who are you?

Example:

Username: venu
Password: ********

If credentials are valid, the user is authenticated.

sequenceDiagram

participant User
participant App
participant Database

User->>App: Submit username/password
App->>Database: Find user by username
Database-->>App: User record
App->>App: Verify password
App-->>User: Login success/failure

5. Authorization

Authorization answers this question:

What are you allowed to do?

Example:

Role Permission
USER View own profile
ADMIN Manage users
AUDITOR Read reports
flowchart LR

User["Authenticated User"]
--> Role["Role"]
--> Permission["Permission"]
--> Resource["Protected API"]

Authentication happens first.

Authorization happens after authentication.


6. Authentication vs Authorization

Concept Meaning Example
Authentication Verify identity Login with username/password
Authorization Verify access USER cannot access ADMIN API
flowchart TB

A["Login Request"]
--> B["Authentication"]

B --> C["User Verified"]

C --> D["Authorization"]

D --> E["Allow or Deny Access"]

7. Security Flow in Java Web Application

sequenceDiagram

participant Client
participant SecurityFilter
participant Controller
participant Service
participant Database

Client->>SecurityFilter: HTTP Request
SecurityFilter->>SecurityFilter: Validate Authentication
SecurityFilter->>SecurityFilter: Check Authorization
SecurityFilter->>Controller: Forward Request
Controller->>Service: Call Business Logic
Service->>Database: Secure Data Access
Database-->>Service: Data
Service-->>Controller: Response
Controller-->>Client: JSON Response

In Spring Boot, this security flow is usually handled by Spring Security filters.


8. Common Security Layers

flowchart TB

Client["Client"]
--> HTTPS["HTTPS / TLS"]
--> Auth["Authentication"]
--> Authz["Authorization"]
--> Validation["Input Validation"]
--> Service["Business Logic"]
--> DB["Database Security"]
--> Logs["Secure Logging"]

A production Java application should secure every layer.


9. Spring Boot Project Setup

Maven Dependencies

<dependencies>

    <!-- Spring Web for REST APIs -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- Spring Security for authentication and authorization -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>

    <!-- Validation for request validation -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>

</dependencies>

Dependency Explanation

Dependency Purpose
spring-boot-starter-web Build REST APIs
spring-boot-starter-security Add security filters
spring-boot-starter-validation Validate request objects

10. Project Structure

java-security-demo
└── src
    └── main
        └── java
            └── com.codewithvenu.security
                ├── controller
                │   └── UserController.java
                ├── dto
                │   └── UserRequest.java
                ├── security
                │   └── SecurityConfig.java
                ├── service
                │   └── UserService.java
                └── JavaSecurityDemoApplication.java

11. Basic Spring Security Configuration

package com.codewithvenu.security.security;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {

        http
            .csrf(csrf -> csrf.disable())
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/api/public/**").permitAll()
                .requestMatchers("/api/admin/**").hasRole("ADMIN")
                .requestMatchers("/api/user/**").hasAnyRole("USER", "ADMIN")
                .anyRequest().authenticated()
            )
            .httpBasic(Customizer.withDefaults());

        return http.build();
    }
}

Code Explanation

@Configuration

Marks this class as a Spring configuration class.

@Bean

Registers SecurityFilterChain as a Spring bean.

csrf(csrf -> csrf.disable())

Disables CSRF protection for stateless REST API examples.

For browser-based apps, CSRF should usually be enabled.

requestMatchers("/api/public/**").permitAll()

Allows public APIs without login.

requestMatchers("/api/admin/**").hasRole("ADMIN")

Only users with ADMIN role can access admin APIs.

anyRequest().authenticated()

All other APIs require authentication.

httpBasic()

Enables Basic Authentication for learning purposes.

In production, JWT or OAuth2 is commonly used.


12. API Access Flow

flowchart TB

Request["HTTP Request"]
--> Filter["Spring Security Filter"]

Filter --> PublicCheck{"Public API?"}

PublicCheck -- Yes --> Allow["Allow Request"]

PublicCheck -- No --> AuthCheck{"Authenticated?"}

AuthCheck -- No --> Reject["401 Unauthorized"]

AuthCheck -- Yes --> RoleCheck{"Has Required Role?"}

RoleCheck -- No --> Forbidden["403 Forbidden"]

RoleCheck -- Yes --> Controller["Controller"]

13. Create Sample REST Controller

package com.codewithvenu.security.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    @GetMapping("/api/public/health")
    public String publicHealth() {
        return "Application is running";
    }

    @GetMapping("/api/user/profile")
    public String userProfile() {
        return "User profile data";
    }

    @GetMapping("/api/admin/dashboard")
    public String adminDashboard() {
        return "Admin dashboard data";
    }
}

API Behavior

API Access
/api/public/health No login required
/api/user/profile USER or ADMIN
/api/admin/dashboard ADMIN only

14. Configure In-Memory Users

package com.codewithvenu.security.security;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

@Configuration
public class UserConfig {

    @Bean
    public UserDetailsService userDetailsService() {

        var user = User.withUsername("venu")
            .password("{noop}password123")
            .roles("USER")
            .build();

        var admin = User.withUsername("admin")
            .password("{noop}admin123")
            .roles("ADMIN")
            .build();

        return new InMemoryUserDetailsManager(user, admin);
    }
}

Important Note

{noop} means no password encoding.

This is only for learning.

Never use {noop} in production.


15. Test APIs

Public API

curl http://localhost:8080/api/public/health

Expected response:

Application is running

User API

curl -u venu:password123 http://localhost:8080/api/user/profile

Expected response:

User profile data

Admin API

curl -u admin:admin123 http://localhost:8080/api/admin/dashboard

Expected response:

Admin dashboard data

Forbidden Example

curl -u venu:password123 http://localhost:8080/api/admin/dashboard

Expected response:

403 Forbidden

16. Secure Password Hashing

Passwords should never be stored as plain text.

Bad:

password123

Good:

$2a$10$Xk3...

Use BCrypt.

flowchart LR

Password["Plain Password"]
--> BCrypt["BCrypt Hashing"]
--> Hash["Stored Hash"]

17. BCrypt Password Encoder

package com.codewithvenu.security.security;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
public class PasswordConfig {

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

Explanation

PasswordEncoder is an interface used by Spring Security.

BCryptPasswordEncoder hashes passwords using BCrypt.

BCrypt automatically adds salt and makes password cracking harder.


18. Update User Configuration with BCrypt

@Bean
public UserDetailsService userDetailsService(PasswordEncoder passwordEncoder) {

    var user = User.withUsername("venu")
        .password(passwordEncoder.encode("password123"))
        .roles("USER")
        .build();

    var admin = User.withUsername("admin")
        .password(passwordEncoder.encode("admin123"))
        .roles("ADMIN")
        .build();

    return new InMemoryUserDetailsManager(user, admin);
}

Now passwords are stored securely in memory.


19. Input Validation

Never trust user input.

Attackers may send:

  • Empty values
  • Long strings
  • Malicious scripts
  • SQL injection payloads
  • Invalid email formats
flowchart LR

ClientInput["Client Input"]
--> Validation["Validation Layer"]
--> Service["Service Layer"]
--> Database["Database"]

20. Request DTO Validation

package com.codewithvenu.security.dto;

import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;

public record UserRequest(

    @NotBlank(message = "Name is required")
    @Size(min = 2, max = 50, message = "Name must be between 2 and 50 characters")
    String name,

    @NotBlank(message = "Email is required")
    @Email(message = "Invalid email format")
    String email,

    @NotBlank(message = "Password is required")
    @Size(min = 8, max = 100, message = "Password must be at least 8 characters")
    String password

) {
}

21. Controller with Validation

package com.codewithvenu.security.controller;

import com.codewithvenu.security.dto.UserRequest;
import jakarta.validation.Valid;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/public/users")
public class RegistrationController {

    @PostMapping("/register")
    public String registerUser(@Valid @RequestBody UserRequest request) {
        return "User registered successfully: " + request.email();
    }
}

Explanation

@Valid

Triggers validation rules defined in UserRequest.

@RequestBody

Converts JSON request body to Java object.


22. Global Exception Handling

package com.codewithvenu.security.controller;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Map<String, String> handleValidationErrors(MethodArgumentNotValidException exception) {

        Map<String, String> errors = new HashMap<>();

        exception.getBindingResult()
            .getFieldErrors()
            .forEach(error -> errors.put(error.getField(), error.getDefaultMessage()));

        return errors;
    }
}

This returns clean validation errors instead of exposing internal stack traces.


23. Secure Error Response Flow

flowchart TB

InvalidRequest["Invalid Request"]
--> Validation["Validation Fails"]
--> ExceptionHandler["Global Exception Handler"]
--> CleanResponse["Clean Error Response"]

24. Secrets Management

Never store secrets in source code.

Bad:

String password = "dbPassword123";
String apiKey = "my-secret-api-key";

Good:

spring:
  datasource:
    password: ${DB_PASSWORD}

Use:

  • Environment variables
  • AWS Secrets Manager
  • HashiCorp Vault
  • Kubernetes Secrets
flowchart LR

SpringBoot["Spring Boot App"]
--> Env["Environment Variables"]
--> Secrets["Secrets Manager / Vault"]

25. Secure Logging

Do not log sensitive information.

Avoid logging:

  • Passwords
  • Access tokens
  • Refresh tokens
  • Credit card numbers
  • SSN
  • API keys
  • Authorization headers

Bad:

log.info("User login request: {}", request);

Good:

log.info("Login attempt for email: {}", request.email());
flowchart LR

Request["Request"]
--> Logger["Logger"]
--> Masking["Mask Sensitive Data"]
--> Logs["Application Logs"]

26. HTTPS / TLS

Always use HTTPS in production.

HTTP:

flowchart LR

Client --> PlainText["Plain Text Data"] --> Server

HTTPS:

flowchart LR

Client --> Encrypted["Encrypted Data"] --> Server

HTTPS protects:

  • Login credentials
  • Tokens
  • Personal data
  • API requests
  • Session data

27. SQL Injection Prevention

Bad approach:

String query = "select * from users where email = '" + email + "'";

This is vulnerable to SQL injection.

Good approach:

Use JPA repositories or prepared statements.

public interface UserRepository extends JpaRepository<User, Long> {

    Optional<User> findByEmail(String email);
}
flowchart LR

UserInput["User Input"]
--> Repository["JPA Repository"]
--> PreparedQuery["Prepared Query"]
--> Database["Database"]

28. Secure API Design Checklist

Every API should answer:

  • Is this API public or private?
  • Who can access this API?
  • What role is required?
  • Is input validated?
  • Are errors safe?
  • Is data filtered by logged-in user?
  • Are logs safe?
  • Is rate limiting required?
mindmap
  root((Secure API))
    Authentication
    Authorization
    Validation
    Error Handling
    Logging
    Rate Limiting
    Data Filtering

29. Real-World Banking Example

Requirement

A banking customer should only view their own account.

Bad design:

GET /api/accounts/1001

If user changes 1001 to 1002, they may access another account.

Secure design:

GET /api/accounts/me

Backend finds accounts using logged-in user identity.

sequenceDiagram

participant Customer
participant API
participant SecurityContext
participant Database

Customer->>API: GET /api/accounts/me
API->>SecurityContext: Get logged-in user
SecurityContext-->>API: userId = 501
API->>Database: Find accounts by userId
Database-->>API: User's own accounts
API-->>Customer: Account response

30. Production Security Checklist

Before deploying a Java application:

  • Use HTTPS
  • Enable Spring Security
  • Use BCrypt for passwords
  • Validate all input
  • Protect admin APIs
  • Use roles and permissions
  • Do not expose stack traces
  • Do not hardcode secrets
  • Do not log sensitive data
  • Use secure headers
  • Use rate limiting
  • Use dependency scanning
  • Use least privilege access
  • Monitor logs and alerts

31. Common Mistakes

Mistake Risk
Plain text passwords Password theft
Hardcoded secrets Credential leakage
Missing validation Injection attacks
Admin APIs without protection Privilege abuse
Exposing stack traces Internal details leak
Logging tokens Account takeover
No HTTPS Data interception

32. Interview Questions

Q1. What is application security?

Application security protects software from unauthorized access, attacks, data leaks, and misuse.

Q2. What is authentication?

Authentication verifies who the user is.

Q3. What is authorization?

Authorization verifies what the user is allowed to access.

Q4. Why should passwords be hashed?

Because stored passwords should not be readable even if the database is compromised.

Q5. Why is BCrypt preferred?

BCrypt is slow, salted, and designed to resist brute-force attacks.

Q6. What is input validation?

Input validation checks whether user input is safe and valid before processing it.

Q7. Why should secrets not be stored in code?

Because source code may be exposed through GitHub, logs, build artifacts, or developer machines.

Q8. What is SQL injection?

SQL injection happens when attackers manipulate SQL queries using malicious input.

Q9. Why is HTTPS important?

HTTPS encrypts communication between client and server.

Q10. What is secure logging?

Secure logging means recording useful events without exposing sensitive data.


33. Key Takeaways

  • Security must be designed from the beginning.
  • Authentication verifies identity.
  • Authorization controls access.
  • Passwords must be hashed using BCrypt.
  • Input validation prevents bad data and attacks.
  • Never hardcode secrets.
  • Never log sensitive information.
  • HTTPS is mandatory in production.
  • Secure APIs must check user identity and permissions.
  • Spring Security provides strong security foundations for Java applications.

Next Article

➡️ Authentication vs Authorization in Java