로그인 기능은 email, password 2개밖에 없기 때문에 react-hook-form을 사용하지 않고 직접 input과 useState를 활용하여 구현했습니다.
이 부분에서 유효성 검사 하는 부분을 백엔드 분과 소통을 통해 유효성 검사의 정규표현식에 대해 통일하기 위해 대화를 진행했습니다.

이메일 저장은 로그인 성공시 쿠키에 저장하도록 구현했습니다.
왜 저장을 할까?? 또 왜 쿠키에 저장을 하는걸까??
사용자 경험을 향상시키위해 브라우저에 저장하여 반복적인 로그인 작업을 줄여 시간과 노력을 절약해주기 위해 저장을 합니다.
쿠키에 저장하는 이유는 브라우저를 껏다 켜도 쿠키에 저장되어 있으며, 해커가 이메일만으로는 어떻게 할 수 없다고 생각하며, 보안에 큰 문제도 없기 때문에 쿠키에 저장을 했습니다.
그러면 LocalStorage에 저장해도 되는거 아닌가?
물론 보안적인 부분에서 email만으로 해커가 직접적으로 해킹을 할 수 있는것은 아닙니다. 하지만 이메일 주소를 통해 "피싱" 공격이 가능합니다. 피싱은 이메일을 통해 사용자들을 속여 개인 정보나 로그인 자격 증명을 요구하는 가짜 웹 사이트로 유도하는 공격입니다.
따라서 삭제하는 코드가 없다면 영구적으로 저장되는 LocalStorage에 저장 하는것 보다 만료기간이 있는 쿠키에 저장 하는것이 더 좋다고 생각하여 쿠키에 저장했습니다.
아래의 코드에서 사용자가 check를 할 경우 cookie에 email을 저장하고,
useEffect를 통해 페이지가 처음 렌더링 될때 값이 존재한다면 email state를 cookie에서 가져와 바꿔줍니다.
그리고 email input의 value값으로 email을 지정해주면 됩니다.

아래의 사진과 같이 잘 저장된 것을 볼 수 있습니다.

로그인을 유지하는 방법은 크게 2가지 방법이 존재합니다.

세션을 사용하는 경우 장점
세션을 사용하는 경우 단점
세션ID를 브라우저에 저장하면 보안에 취약하기 때문에 JWT(JSON Web Token)을 통해
세션 방식의 일부 한계를 보완하기 위해 도입된 인증 방식입니다.
이때 Access Token은 유효기간이 짧게 지정해둡니다.
why? 유효기간을 짧게해 보안을 강화하고, 권한을 관리하기 위해서 입니다.

저는 JWT를 활용한 방식이 세션 방식보다 보안적인 측면에서 좋다고 생각하고, 서버측 성능적인 부분을 고려 했을때도 더 좋다고 생각하여 JWT 방식을 사용했습니다.
사용자의 정보를 다루는 부분이기 때문에 보안도 신경을 써야됩니다.
웹 어플리케이션 보안 취약점 중 유저 인증에서 보편적으로 이용되는 취약점은 크게 2가지가 있습니다.
Cross-Site Scripting으로서 악의적인 사용자가 공격하려는 사이트에 악성 스크립트를 삽입하여 사용자의 브라우저에서 실행되도록 하는 것을 목표로 합니다.
공격에 성공하면 사이트에 접속한 사용자는 삽입된 코드를 실행하게 되며, 보통 의도치 않은 행동을 수행시키거나 쿠키나 세션, 토큰 등의 민감한 정보를 탈취합니다.
XSS 공격은 크게 세 가지 형태로 나타납니다.
1. Stored XSS (저장형 XSS)
2. Reflected XSS (반사형 XSS)
3. DOM-based XSS (DOM 기반 XSS)
공격자가 악성 스크립트를 서버에 저장하여 해당 스크립트가 사용자에게 돌아갈 때 실행되도록 하는 형태입니다. 예를 들어, 게시판이나 댓글 기능에서 악의적인 스크립트를 게시하여 다른 사용자가 해당 게시물을 열거나 댓글을 확인할 때 실행되게 할 수 있습니다.
사용자가 악성 스크립트가 포함된 링크를 클릭하거나, 악성 스크립트가 포함된 데이터를 서버로 전송하면, 해당 스크립트가 서버에서 처리되어 응답으로 반환됩니다. 이 응답은 사용자의 브라우저에서 실행되며, 악성 스크립트가 실행될 수 있습니다. 주로 검색 결과나 이메일의 링크 등에서 발생할 수 있습니다. 그러나 브라우저 자체에서 차단하는 경우가 많아 상대적으로 공격을 성공시키기가 어렵습니다.
아래와 같이 URL에 악성코드를 작성하여 공격을 합니다.
https://example.com/search?query=<script>alert('XSS Attack!');</script>
DOM(Document Object Model) 기반 XSS는 클라이언트 측에서 발생하는 XSS 공격입니다. 악성 스크립트가 웹 페이지에서 자바스크립트를 사용하여 동적으로 DOM을 수정하고 조작함으로써 발생합니다. 이는 주로 클라이언트 측 스크립팅 언어를 사용하는 웹 애플리케이션에서 발생합니다.
CSRF (Cross-Site Request Forgery)는 웹 애플리케이션에서 발생하는 보안 취약점 중 하나로, 인증된 사용자의 의지와 무관하게 공격자가 웹 애플리케이션을 통해 악성 요청을 전송하는 공격입니다. 이러한 공격은 사용자의 브라우저가 신뢰하는 도메인에서 공격을 수행하므로, 인증된 사용자의 권한으로 악용될 수 있습니다.
그러나 인증된 사용자의 권한으로 악용되기 때문에 아래와 같은 조건을 만족시켜야 합니다.
1. 위조 요청을 전송하는 서비스에 희생자가 로그인 상태
2. 희생자는 공격자가 만든 피싱 사이트에 접속
세션 id나 accessToken 같은 인증정보를 서버에서 주면 값을 어디다 저장할까요??
보통 LocalStorage 또는 쿠키에 저장합니다. 페이지를 리프레시 하거나 창을 닫고 다시 접속할 때도 로그인 정보가 이어지도록 둘 다 브라우저에 저장하는 방식입니다. 하지만 두 방식은 브라우저에 정보를 저장하기 때문에 XSS와 CSRF 공격에 취약할 수 있습니다.
저는 JWT 방식을 사용했고, Refresh-Token은 쿠키에, Access-Token은 로컬에 저장하여 XSS와 CSRF 공격에 대한 보안을 강화했습니다
쿠키에 저장하면 보안에 취약하다면서요?
그래서 저는 쿠키에 저장하되, HTTPOnly, secure 플래그를 적용하여 자바스크립트에서 접근하지 못하도록 했습니다. 이를 통해 CSRF 취약점 공격을 방어하고, XSS 취약점 공격으로 저장된 유저 정보 읽기는 막을 수 있습니다.
하지만 XSS 취약점을 통해 API 콜을 보낼 때는 무방비하기 때문에 XSS 자체를 막기 위해 서버와 클라이언트 모두 이를 막기위해서 노력을 해야합니다.
클라이언트측 처리하기



새로고침시 로컬에 저장해뒀던 AccessToken이 없어지는 문제가 발생합니다.
왜 why? 아래의 코드를 통해 axiosInstance를 통해 HTTP 요청을 보낼때 마다 Header에 accessToken을 보내도록 설정을 해줬습니다.
즉 Access-Token값을 저장하지 않았으므로 새로고침시 초기화되어 사라지는것입니다.
axiosInstance.defaults.headers.common['Authorization'] = `Bearer ${accessToken}`;
따라서 App컴포넌트에 아래의 코드를 실행시켜주면 됩니다.
왜 이게 되지?
새로고침시 header에 저장된 값은 날라가지만, 쿠키에 Refresh-Token을 저장해뒀기 때문에 이것을 통해 Access-Token을 재발급 받아 로그인 유지가 가능합니다.
