오늘의 술상 (http://drinkoftoday.shop)
술자리 혹은 혼술(혼자 마시는 술) 관련 사진을 공유하고 소통하는 커뮤니티 웹사이트입니다.
2021년 8월 9일 ~ 현재까지 새로운 기능 개발 중
글자 수와 이미 사용되고 있는 id, 닉네님 이메일을 체크하며 이메일란과 이메일 확인란이 동일한지 체크합니다.
회원가입 후 토큰을 포함한 링크를 통해 이메일을 인증합니다.
로그인 시 회원의 닉네임을 우측 상단에 표시하며 글쓰기 버튼을 화면에 노출시킵니다.
글과 사진을 올릴 수 있습니다. 사진의 경우 서버내에서 이름을 uuid로 변경하여 저장합니다.
게시물에 사진이 있다면 첫번째 사진을 썸네일으로 사용하며 사진이 없을 경우 더미 이미지를 썸네일로 보여줍니다. 원하는 게시물을 클릭하여 열람가능합니다. 또한 게시물에 대한 권리가 없다면 수정과 삭제 버튼이 화면에 노출되지 않습니다.
미로그인 시 글 쓰기 버튼을 화면에 노출하지 않 글 쓰기 페이지로 url을 통해 접근시 인터셉터를 이용해 제한하고 로그인 페이지로 이동시킵니다.
댓글 등록 후 AJAX를 이용하여 댓글 부분만 갱신을 합니다.
마찬가지로 댓글 삭제 후 AJAX를 이용하여 댓글 부분만 갱신을 합니다. 댓글 삭제는 댓글 작성자만 가능합니다.
1인 개발의 한계로 서버 위주로 개발하였으며 서버 사이드 렌더링을 사용하였습니다.
Spring boot : 2.5.3
Java : 11(jar)
Build tool : Gradle
Dependencies : SpringWeb, Lombok, thymeleaf, lucy-xss-servlet-filter
HTML,css library : bootstrap 5.0.2
RDB : maria DB
ORM : JPA
CD : Jenkins
Cloud : AWS EC2 (micro)
PaaS : heroku
에노테이션 기반으로 짧은 코드를 구현하게 해주는 lombok 라이브러리를 사용하였으며
서버 사이드 렌더링을 위해 Natural Template을 지원하는 thymeleaf를 사용하였습니다.
XSS에 취약한 것을 확인하고 네이버 사의 lucy-xss-servlet-filter라이브러리를 적용했습니다.
html, css는 효율적이고 보기 좋은 결과물을 만들 자신이 없어 bootstrap을 사용하였습니다.
LINE 메신저의 채팅 봇 활용을 위해 heroku PaaS를 사용했습니다.
로컬에서 작업 후 깃허브에 커밋 시 젠킨스가 자동으로 빌드 후 배포하는 형식이며 현재 빌드와 운영 모두 한 클라우드에서 진행하고 있습니다.
테스트 실패 시 디스코드로 알림이 전송되며 새로운 글 등록 시 LINE(채팅 봇)으로 알림이 전송됩니다.
데이터베이스 설계에 대해서 많이 약하다고 생각하고 있으며 최대한 불필요한 연관관계는 지양했습니다.(ex 인증 토큰과 멤버)
uuid 기본 키를 String으로 설정 시 Specified key was too long; max key length is 767 bytes라는 오류가 발생하며 테이블이 생성되지 않는다.
- 이메일 인증 토큰 db에서 기본 키 값을 uuid로 설정하였다.
- ORM에서 객체는 String, DB는 varchar(255)로 저장하였다.
- 로컬 개발 환경(h2 사용)에서는 이상없이 동작한다.
- 오류 로그 확인 (키가 너무 길다. 최대 키 값은 767byte다.)
- utf8은 3바이트이기 때문에 varchar(255)는 최대 값을 넘지 않는다.(3 * 255 = 765)
-> 현재 사용중인 character set은 utf8mb4였으며 이것은 개당 4바이트이다. (문제 발견)
utf8mb4 : uft8에서 이모티콘을 표현하기 위해 mysql에서 지원하는 character set
- db 스토리지에 따라 최대 키 값의 크기를 설정 할 수도 있다.
- 시스템 설정을 가급적이면 바꾸지 않기를 원하며 확장성을 위해 선택하지 않았다.
새로운 문제점 발견
- uuid의 경우 32개의 문자와 4개의 하이픈이 필요하므로 최소 36개가 강제되므로 메모리 낭비가 심하다.
- 길이가 길기 때문에 정렬에 따른 퍼포먼스 이슈가 있을 수 있다.
- 잘못 된 크기 설정 시 db에 따라 RPAD , LPAD를 처리하므로 조회 시 문제가 생길 수 있다.
- uuid는 총 32개의 16진수 숫자이므로(하이픈 제외) 16 바이트로 표현 가능하다.
- ORM에서 객체의 클래스를 UUID로 지정했고 columnDefinition을 통해 binary(16)으로 테이블 정의를 하였다.
- 반대로 조회 시에는 String을 binary로 변환하는 과정이 필요하였기 때문에 따로 구현하였다.
유니코드 바이트 할당 문제로 시작한 공부였지만 uuid 를 기본 키로 사용 할 수 있는 방법과 장단점, 그리고 String을 기본 키로 사용 시의 문제점을 알게 되었다.
특히, uuid를 기본 키로 사용하는 것은 조금 더 활용 방안을 고안하여 이후에 다른 테이블에서 적용 할 수 있을 것이라 생각된다.
내 사이트를 이용하는 지인들에게 자주쓰는 암호는 피해달라고 당부했으나 다들 무시하고 사용하던 비밀번호를 사용했다.
최근 나의 실수로 데이터베이스를 몇 번 탈취당한 경험이 있어 이대로 놔두면 안된다고 판단하였다.
- 현재 계정에 저장되는 개인정보는 이메일과 로그인ID, 패스워드이다.
- 그 중 패스워드 만큼은 외부로 노출되면 안된다고 판단했다.
- 암호화라는 개념에 무지했기 때문에 그에 대해 공부하였다.
- 공부하는 중 해싱에 대하여 알게되었고 암호화와 해싱의 차이를 이해하였다.
- 패스워드 저장에는 해싱이 적합하다 판단하여 해싱 처리를 하였고 부가적인 처리를 하였다.
- Java security MessageDigest의 클래스를 이용하여 해싱하였다.
새로운 문제점 발견
- 동일한 메세지는 동일한 다이제스트를 갖는다.
- 그렇기 때문에 브루트포스 기법으로 쉽게 유추할 수 있다.
- 솔팅(Salting) : 특정 문자열을 추가하여 원형을 측정하기 어렵게 하는 것으로 추가되는 특정 문자열을 솔트(salt) 라고 한다.
Message Digest의 update 메소드를 이용해 쉽게 구현하였다. - 키 스트레칭(Key Stretching) : 입력 값으로 다이제스트를 생성하고, 생성된 다이제스트를 입력 값으로 하여 다이제스트를 생성하며 이를 반복하는 방법이다.
for문을 이용하여 반복 해싱을 구현했다.
이번 프로젝트에서 솔트 문자열과 키 스트레칭 반복 횟수는 모두 스프링 프로퍼티에서 받아오며 해당 프로퍼티는 아무도 접근할 수 없게 서버에 보관되어있다.
성공적으로 처리하였으며 해싱은 단방향 암호화이기 떄문에 위의 결과의 값이 노출되어도 상관없다.
사실 이번에 자바 도큐먼트를 대충 읽고 개발에 들어가 상당히 많은 실수를 하였다. 다시 메세지 다이제스트를 다룰 때 같은 실수를 반복하지 않도록 블로그에 글로 남겨놓았다.
링크 : 메세지 다이제스트의 메소드 설명과 테스트
아이폰으로 촬영한 사진을 게시글에 올리면 이미지가 보이지 않는 오류 확인. 아이폰으로 촬영한 사진의 확장자는 HEIC 이라는 파일로 확인했다.
- HEIC 의외의 jpg, gif는 문제없이 보인다.
- HEIC를 지원하는 웹브라우저는 현재 없다.
- 서버 내에서 JPG로 컨버팅을한다.
클라우드 성능을 줄일 예정이라 서버의 부담을 줄이고 싶어서 최대한 기피했다.
- 외부의 API를 이용해서 HEIC를 JPG로 변환한다.
- 아이폰의 라이브 포토는 메신저를 통해 전송할 경우 정지된 이미지로 전달 받은 경험이 있다.
"그러면 라인 메신저로 사진을 전송 후 다시 받아오면 되지않을까?" 라는 생각에서 시작
- 라인 메세지를 받아 줄 채팅 봇을 만들었다. 그 과정에서 heroku와 라인 Notify api를 학습하였다.
텍스트와 이미지를 똑같이 응답하는 것과 보낸 사람의 프로필을 응답하는 채팅 봇의 기능을 확인하였다. 또한 응답하는 이미지는 JPG인 것을 확인하였다.
heroku : 클라우드 기반의 서비스를 제공하는 PaaS이다.
-
라인 Message API 문서를 읽어보고 기본적인 사용법을 익혔으며 스프링 서버 내에서 채팅 봇으로 텍스트 메시지 전송을 확인하였다.
-
스프링 서버내에서 채팅 봇으로 이미지 전송은 계속 400에러를 응답받았다.
새로운 문제 발생
라인 메세징 api에서 이미지는 공개적으로 접근 가능한 서버에 먼저 저장한 후 그 서버의 url을 json으로 제공하는 방식이었다.
또한 HTTPS를 적용한 url만 허용하며 JPG와 PNG만 허용한다. 즉 설계부터 잘못되었기에 실패했다.
현재는 새로운 글 작성 시 채팅 봇을 친구 추가한 사용자에게 알림을 주는 용으로 사용하고있다. 해당 변환 과정에 대해서는 조금 더 조사를 해 볼 예정이다.
- 서버 성능 향상을 위해 어떻게 해야할까?
- Nginx를 적용했으나 현재는 리버스 프록시의 역할만 하고있다. 어떻게 활용해야 할까?
- JPA에서 성능을 향상 시키려면 어떻게 해야할까?
- 멤버와 게시물의 연관 관계 매핑과 그에 맞는 추가 기능 (멤버 별로 게시물 모아보기 등등)
- 검색 기능