| | 554 | |
| | 555 | == Security == |
| | 556 | |
| | 557 | === 1. Password Security (BCrypt) === |
| | 558 | User passwords are encrypted before being stored in the database using {{{BCryptPasswordEncoder}}}. This ensures that even in the event of a database breach, plain-text passwords remain unreadable and are protected against brute-force and dictionary attacks. Authentication is securely handled by verifying the raw input against the stored BCrypt hash within the {{{UserService}}}. |
| | 559 | |
| | 560 | Implementation in {{{UserService.java}}}: |
| | 561 | {{{#!java |
| | 562 | private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); |
| | 563 | |
| | 564 | @Transactional(readOnly = true) |
| | 565 | public User authenticate(String username, String password) { |
| | 566 | User user = userRepository.findByUsername(username).orElse(null); |
| | 567 | if (user != null && passwordEncoder.matches(password, user.getPassword())) { |
| | 568 | return user; |
| | 569 | } |
| | 570 | return null; |
| | 571 | } |
| | 572 | |
| | 573 | @Transactional |
| | 574 | public User registerUser(String username, String password, String firstName, String lastName, String email, String role) { |
| | 575 | // ... |
| | 576 | newUser.setUsername(username); |
| | 577 | newUser.setPassword(passwordEncoder.encode(password)); |
| | 578 | newUser.setFirstName(firstName); |
| | 579 | // ... |
| | 580 | } |
| | 581 | }}} |
| | 582 | |
| | 583 | === 2. SQL Injection Prevention === |
| | 584 | The application utilizes '''Spring Data JPA''' for all database interactions. By relying on JPA's built in repository methods, all user inputs are automatically treated as parameters rather than executable SQL strings. This protects the application from SQL Injection attacks. |
| | 585 | |
| | 586 | Example of safe repository usage in {{{UserService.java}}}: |
| | 587 | {{{#!java |
| | 588 | @Transactional(readOnly = true) |
| | 589 | public User authenticate(String username, String password) { |
| | 590 | User user = userRepository.findByUsername(username).orElse(null); |
| | 591 | // ... |
| | 592 | } |
| | 593 | }}} |
| | 594 | |
| | 595 | === 3. Role based access control (RBAC) === |
| | 596 | The application implements strict endpoint protection based on user roles (Admin, PetOwner, PetSitter). Controller routes verify the identity and specific subtype of the authenticated user via the {{{HttpSession}}}. If an unauthorized role attempts to access restricted areas, they are immediately redirected, preventing privilege escalation. |
| | 597 | |
| | 598 | Implementation example in {{{AdminController.java}}}: |
| | 599 | {{{#!java |
| | 600 | @GetMapping("/admin/users") |
| | 601 | public String showAllUsers(HttpSession session, Model model) { |
| | 602 | User user = (User) session.getAttribute("loggedInUser"); |
| | 603 | |
| | 604 | if (user == null || user instanceof PetOwner || user instanceof PetSitter) { |
| | 605 | return "redirect:/dashboard"; |
| | 606 | } |
| | 607 | |
| | 608 | List<User> users = userRepository.findAll(); |
| | 609 | model.addAttribute("users", users); |
| | 610 | // ... |
| | 611 | return "admin-users"; |
| | 612 | } |
| | 613 | }}} |
| | 614 | |
| | 615 | ---- |
| | 616 | |
| | 617 | == Not applicable == |
| | 618 | |
| | 619 | During the security analysis phase, two common web security measures were evaluated but found to be inapplicable for our specific architecture: |
| | 620 | |
| | 621 | === JWTs === |
| | 622 | '''JSON Web Tokens''' are designed for Stateless REST APIs (for example, when using a completely separate React/Vue frontend). |
| | 623 | |
| | 624 | Because our application uses a '''Server Side Rendering - SSR ''' architecture returning HTML views directly from controllers, we manage state using the built-in {{{HttpSession}}}. Session based authentication is the standard for this specific architecture and provides excellent security. Implementing JWTs would require an unnecessary and highly complex rewrite of our entire authentication system, moving away from SSR best practices. |
| | 625 | |
| | 626 | === CORS === |
| | 627 | |
| | 628 | Because our frontend and backend are served together from the exact same Spring Boot instance, they share the exact same origin. Therefore, cross origin requests do not occur, making CORS configuration unnecessary for our application. |