부트모아 11

[V3] 캐싱을 통한 쿼리 줄이기

로그를 살펴 보던 중, 글을 등록, 수정, 삭제 할때 마다 Principal을 통해 인증 정보를 가져오기 위해 query가 발생하는 것을 확인할 수 있었다. 수정 빈도가 매우 적은 user 정보를 매번 db에 요청하는 것은 불필요한 부하라는 생각이 들어 user 정보를 캐싱하고 성능 개선이 어느정도 되었는지를 부하 테스트 해보기로 하였다. 캐싱 전 테스트 테스트 종류: 1) Smoke 테스트 VUser: 1 ~ 2 최소의 부하로 시나리오를 검증한다. 2) Load 테스트 평소 트래픽과 최대 트래픽일 때 VUser를 계산 후 시나리오를 검증한다. 3) Stress 테스트 최대 사용자 혹은 최대 처리량인 경우의 한계점을 확인하는 테스트이다. 점진적으로 부하를 증가시켜본다. 테스트 이후 시스템이 수동 개입 없..

부트모아 2024.01.15

[V3] 부하 테스트 세팅

부트모아 사이트의 부하를 테스트 해보고 테스트 바탕으로 성능 개선을 하고자 nGrinder를 사용해 보기로 하였다. https://github.com/naver/ngrinder/releases Releases · naver/ngrinder enterprise level performance testing solution. Contribute to naver/ngrinder development by creating an account on GitHub. github.com 최신 버전의 controller를 다운 받고 java -jar ngrinder-controller-{version}.war --port=8300 실행시켜 주었다. 그 다음, localhost:8300으로 접속해 초기 id, passwo..

부트모아 2024.01.13

[V2] Vault를 사용한 보안 강화

웹 애플리케이션 취약점 중에서 빈도가 많이 발생하는 10가지를 선정한 문서인 OWASP TOP 10을 보던 중 misconfiguration에 대해 알게 되었다. 내 프로젝트에도 보안상 취약한 설정이 있나 살펴보던 중 DB 접근 정보가 github에 그대로 노출 되어있는 것을 확인하였다. 이와 같은 "시크릿"을 어떻게 안전하게 저장할 수 있을까를 살펴보던 중 Hashicorp vault를 알게돼 내 프로젝트에 적용해 보기로 하였다. Hashicorp vault란? vault를 이해하기 전, "시크릿"이라는 개념에 대한 이해가 필요하다. 시크릿은 시스템에 접속할 때 필요한 인증과 인가 정보를 부여하는 모든 것을 의미한다. 대표적인 예시로 계정 비밀번호, DB 인증정보, TLS 인증서가 있다. 이러한 "시크..

부트모아 2024.01.12

[V2] Spring Security CSRF

부트모아 취약점을 분석 중 대표적인 클라이언트 사이드 취약점인 CSRF를 발견하였다. CSRF 사용자가 자신의 의지와는 상관없이 공격자가 의도한 수정, 삭제, 등록 행위 등 특정 웹사이트에 요청하게 하는 공격 공격자가 위와 같은 스크립트가 포함된 게시글을 작성했을때 위와 같은 게시글이 작성되었다. 관리자는 해당 버튼이 홈페이지 링크인줄 알고 확인차 눌렀더니 관리자의 의도와 상관없이 관리자 이름으로 공지사항이 작성되었다. 대응 요청에 대한 검증을 하기 위해 CSRF 토큰을 직접 만들려 했으나, Spring Security 문서를 읽던 중 관련 기능이 이미 구현되어 있다는 것을 알고 프로젝트에 적용해 보기로 하였다. tokenRepository.loadToken(request) 요청 세션에서 CSRF Tok..

부트모아 2024.01.11

[V2] 부트모아 사이트 XSS 필터링

부트모아 취약점을 분석 중 대표적인 클라이언트 사이드 취약점인 XSS를 발견하였다. XSS 공격자가 웹 리소스에 악성 스크립트를 삽입해 이용자의 웹 브라우저에서 해당 스크립트를 실행하는 취약점 위 같은 게시글을 공격자가 작성한다고 하였을 떄, 게시글 목록에서 방금 작성한 게시글을 열람하면 스크립트가 실행되는 것을 확인할 수 있었다. 대응 특수문자를 그대로 응답해 발생하는 문제이므로, Response객체에서 특정 특수문자를 html 엔티티로 치환해주기로 하였다. public static String xssFilter(String str) { String result = ""; result = str; result = result.replaceAll("", ">"); return result; } 필터링을 ..

부트모아 2024.01.10

[V2] JPA는 sql injection에 무조건 안전한가?

SQL Injection 공격자가 입력이 가능한 폼에 조작된 질의문 삽입하여 디비 정보 열람 및 정보를 조작하는 공격 JPA는 sql injection에 무조건 안전한가? JPA는 내부적으로 Prepared Statement를 사용하고 있어 sql injection에 안전하지만, 입력값을 바로 대입하는 방식의 native query는 안전하지 않다. String queryString = "SELECT u FROM User u WHERE u.username = '" + userInput + "'"; Query query = entityManager.createQuery(queryString); List users = query.getResultList(); Prepared Statement 사용하면 안전한..

부트모아 2024.01.09

[V1] 셀프 조인을 통한 대댓글 구현

게시글의 댓글 기능을 단순히 후기만을 올리는 것이 아니라 사용자 간의 질문 및 정보 공유 바탕으로 상호작용하게 하고 싶었다. 그러기 위해서는 대댓글 기능이 필요할것 같다는 생각이 들었고 이를 구현해 보았다. 먼저 위 같이 댓글의 관계를 그림으로 표현한 후, 이를 어떻게 구현할지 고민하다가 데이터베이스 수업시간에 배운 self join을 이용해 보기로 했다. public class ArticleComment { ``` @Setter private Long parentCommentId; @ToString.Exclude @OrderBy("createdAt ASC") @OneToMany(mappedBy = "parentCommentId", cascade = CascadeType.ALL) private Set c..

부트모아 2024.01.07

[V1] 사용자 인증 구현

Spring Security 공식 문서 Spring Security without the WebSecurityConfigurerAdapter를 참고하여 인증 구현을 진행하였습니다. UserDetails spring security에서 사용자의 정보를 담는 인터페이스 CustomUserDetails(Principal) 대부분의 경우 spring security의 기본 UserDetails로는 실무에서 필요한 정보를 모두 담을 수 없기에 Principal을 구현하여 사용한다. @Setter @Getter public class BootPrincipal implements UserDetails { private String username; private String password; Collection

부트모아 2024.01.05

[V1] 수정기능 구현시 쿼리수 줄이기

public void updateArticle(ArticleDto dto) { Article article = articleRepository.findById(dto.id()); article.setTitle("updated title"); articleRepository.save(article); } 맨 처음 게시글 제목을 수정하는 코드를 다음과 같이 작성하였는데, 로그를 확인해보니 Hibernate: select article0_.id as id1_0_0_, article0_.title as title2_0_0_ from article article0_ where article0_.id=? Hibernate: insert into article (article_id, title) values (?, ..

부트모아 2024.01.02

[V1] 엔티티에 기본 생성자가 반드시 필요한 이유

게시글 entity를 만들던 중 다음과 같은 오류를 만났다. Article 클래스는 [public, protected] 기본 생성자가 필요하다는 오류였는데, 사용하지 않을 생성자가 왜 반드시 필요한지 궁금하여 이유를 찾아보았다. 엔티티에 기본 생성자가 필요한 이유 JPA는 엔티티에 기본 생성자를 만드는 것을 강제하고 있는데 그 이유는 DB에서 데이터를 조회해 온 뒤 객체를 생성할 때 Reflection을 사용하기 때문이다. Reflection은 클래스 이름만 알면 생성자, 필드, 메서드 등 클래스의 모든 정보에 접근이 가능하다는 특징이 있다. 하지만 생성자의 매개변수 정보는 가져오지 못해 기본 생성자로 객체를 생성하고 필드 값을 매핑하는 특징이 있다. 그렇다면 Reflection을 사용하는 이유가 무엇인..

부트모아 2023.12.31