1. 개요
2. 트러블슈팅
3. 해결방안
개요
사내 백오피스 어드민 페이지에서 사용중 갑자기 csrf token mismatch 오류가 발생했다는 이슈가 있었다.
이상한점은 페이지 이동 및 검색, 모달 창 띄우기 까지는 잘 작동하는데 특정 버튼 클릭시 이슈가 발생한다는 것이다. 그리고 일정 시간이 지나도 로그아웃이 안되고 계속 로그인 상태라고 한다.
들어보니 session 과 csrf token 관련된 이슈인것 같았다. 그리고 이 이슈는 내가 담당하게 되어 그 트러블슈팅 과정을 나열해보고자 한다.
우선 클라이언트는 vue 를 사용하여 만든 SPA 웹 어드민 이고 SPA 와 통신하는 api 서버는 라라벨로 구축되어 있다. 그리고 라라벨의 경우 쿠키, 세션, cors, csrf token 등.. 기본적인 웹 보안과 관련된 기능을 미들웨어로 제공해준다.
트러블슈팅
이슈 내용을 보면 라라벨에서 제공해주는 미들웨어쪽을 살펴보면 될거같은데 확인 해야될 사항은 아래와 같다.
- .env 에 SESSION_LIFETIME 확인
- csrf token 미들웨어가 사용되는 라우트 리스트
- artisan route:list 를 활용하여 라우트에 적용된 미들웨어 확인
- RouteServiceProvider 확인
- routes 디렉토리 밑, route 파일 확인
- Controller 에 따로 미들웨어가 적용되있는지 확인
- csrf token 발급 및 재갱신 시점
- Http/kernel.php 에서 csrf token 처리 관련 미들웨어 찾기 (VerfiyCsrfToken)
- VerfiyCsrfToken 살펴보기
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*
* @throws \Illuminate\Session\TokenMismatchException
*/
public function handle($request, Closure $next)
{
if (
$this->isReading($request) ||
$this->runningUnitTests() ||
$this->inExceptArray($request) ||
$this->tokensMatch($request)
) {
return tap($next($request), function ($response) use ($request) {
if ($this->shouldAddXsrfTokenCookie()) {
$this->addCookieToResponse($request, $response);
}
});
}
throw new TokenMismatchException('CSRF token mismatch.');
}
- 리소스 조회 http 메소드 사용시 ('HEAD', 'GET', 'OPTIONS')
- Unitest
- VerifyCsrfToken 미들웨어 적용 제외 라우트
- request 에 담긴 csrf_token 과 세션에 저장되어 있는 csrf_token 이 일치 할때
💡 이미 로그인 상태이고 csrf_token 이 request header 에 담겨 있는 경우, 기존 세션에 저장된 csrf_token 을 응답 쿠키 값에 넣어주고 쿠키 만료 시간을 재갱신 시켜줌
간단히 이슈를 확인해보기 위해 로그인 이후 서버에 저장된 세션을 삭제하고 페이지를 새로고침 해보았다.
근데 이게 웬걸 로그인이 풀리지 않고 세션도 다시 생성되어있다.
그럼 로그아웃을 하고 다시 로그인 페이지로 돌아가보자.
가만보니 로그인 페이지에서 옵션으로 Remember me 라는 기능을 제공하고 있었다. 그리고 라라벨에선 이와 관련된 기능을 지원해준다.
자 그럼 이제 이슈를 재현해보기 위해서 2개의 테스트 시나리오를 만들어보자.
세션 만료 without Remeber me
- 로그인
- 페이지 이동
- 세션 만료
- 검색
- 모달 창 오픈
위 테스트 시나리오 에선 3번(세션 만료) 이후 4번(검색) 실행시 재로그인이 필요하다. 이미 세션이 만료되어 서버에서 사용자 인증을 요구한다. Remember me 가 없을 경우 예상대로 정상 작동 한다.
세션 만료 with Remeber me (이슈 케이스)
- 로그인
- 페이지 이동
- 세션 만료 (어떠한 이유로 세션이 만료됨, 페이지를 켜놓고 장시간 조작이 없었을 경우 etc..)
- 검색 (GET 요청)
- 모달 창 오픈 (GET 요청)
- 특정 버튼 클릭 (POST 요청)
Remember me 기능을 사용했기 때문에 4번(검색)에선 사용자 인증을 요구(로그인 페이지 리다이렉트) 하지 않는다. 문제는 이때부터 발생하기 시작한다. 세션 만료 이후 다시 세션을 생성하는 경우 csrf_token 값이 바뀐다.
그럼 또 여기서 드는 의문은 왜 4번(검색) 부터 CSRF token mismatch 가 발생하지 않았는가?
왜냐하면 라라벨 미들웨어에선 csrf token 검증은 리소스 조회 (GET, OPTIONS, HEAD) 에대해선 하지 않는다.
애초에 http GET 메소드는 리소스 조회를 명시하기 때문에 csrf token 검증을 따로 하지 않아도 큰 위험이 없다.
그래서 GET 메소드를 이용해 서버에서 자원에 대한 CUD 작업은 하지말라고 한다. 실제 이와 관련된 CSRF 공격 이슈가 있었다.
해결방안
Remember me 제거
- 근본적으로 위와 같은 이슈가 생기지 않음.
- 세션 라이프타임을 늘려 Remember me 와 같은 효과를 느낄수 있게 할수도 있음.
- 백오피스 내부용이기 때문에 세션 라이프타임을 늘림으로써 인해 서버에 늘어나는 부담은 미미함.
우선 발생하고 있던 csrf token mismatch 이슈를 뻐르게 해소하기 위해 위와 같은 방법을 택했다.
'IT > 라라벨' 카테고리의 다른 글
[laravel] 다대다 관계 pivot 테이블 컬럼 업데이트 (0) | 2023.03.05 |
---|---|
[laravel] Model $attributes 필드 접근시 주의점 (0) | 2022.12.28 |
[laravel] 라라벨 테스트 코드 작성 하기 전 알아두면 좋은 것 (0) | 2022.12.25 |
[라라벨] laravel 설치 명령어 에러 해결방법 (0) | 2020.11.14 |
[php] xml 포맷 데이터 배열로 바꾸기 (0) | 2020.08.18 |