일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- C/C++
- protobuf-c
- 자바스크립트
- M8200
- plcrashreporter
- Font
- ClickOnce
- docker
- 크래시로그
- API
- VS2008
- 데이터 전달
- PDA
- Antialiasing
- phpmailer
- EUC-KR
- GDI
- 한 번만 실행
- MFC
- .net
- 기념일관리
- 설치제거
- net
- 와이브로
- crashlog
- JavaScript
- self-signed ssl
- 블루투스 헤드셋
- php
- C#
- Today
- Total
~☆~ 우하하!!~ 개발블로그
[연재] Spring Boot diary : 접근보안 (feat. Postman) 본문
원문은 Spring Boot: study.diary 접근보안 (feat. Postman) 을 참고하세요.
Spring Boot 를 이용해서 학습차원에서 개발해보고 있는 diary 프로그램이 프로그램으로서의 기본 골격은 갖추었다고 생각했어.
그런데, A 라는 사용자가 로그인해서 B 사용자가 작성한 일기를 볼 수 있다거나, 편집할 수 있는 허점이 있어. 그리고 일단 사용자로 등록한 후에 비밀번호를 변경하는 작업 역시 불가능한 상태야.
이런 보안상 허점이라거나 미진한 기능들을 한꺼번에 모아서 처리해볼께.
일기 작성자 확인하기
사용자를 한 명 더 추가해봤어. 추가된 사용자의 이메일주소는 klist02@naver.com 이야.
이 사용자로 로그인해서 작성한 일기 데이터는 고유값 id 가 19 번 하나야.
기억날지 모르지만 Rest API 로 /diary/{id} 를 사용하면 고유값 {id} 에 해당하는 일기 데이터를 불러올 수 있도록 작성했었지.
klist02@naver.com 사용자가 작성한 것이 아닌 id 고유값 18 번의 데이터를 가지고와볼께. klist02@naver.com 으로 로그인한 상태인 것을 잊지마.
로그아웃된 상태에서 웹브라우저에 http://localhost:8080/diary/18 를 입력하면 로그인되지 않은 상태이기 때문에 로그인화면이 표시가 돼.
여기에 로그인하면 다시 http://localhost:8080/diary/18 주소값으로 이동해서 데이터가 보이게 되지.
큰일이네. klist02@naver.com 이 로그인해서 주소를 직접 입력하는 방식으로 다른 사람의 일기를 훔쳐볼 수 있다니.
그래서 일기데이터를 읽고, update 하고, delete 할 때마다 해당 일기 데이터에 저장된 이메일 주소와 현재 로그인한 사용자의 이메일 주소를 비교해서 일치하는 경우에만 action 이 가능해지도록 수정하려고 해.
기존에 로그인한 정보를 가져오는 로직을 작성한 곳이 DiaryService 였으니까 이번에도 여기를 수정해볼께.
우선 일기 데이터를 읽어와서 현재 로그인한 사용자의 email 주소와 일치하는지를 확인할거야.
DiaryService.java
@Service
public class DiaryService {
...
public Diary GetDiary(Integer id) {
String email = SecurityContextHolder.getContext().getAuthentication().getName();
Diary diary = diaryMapper.GetDiary(id);
if (!diary.getEmail().equals(email)) {
throw new DiaryException("작성자가 아닙니다.");
}
return diary;
}
...
}
새로 등장한 DiaryException 을 아래와 같이 정의해주면 돼.
DiaryException.java
package com.woohahaapps.study.diary.exception;
public class DiaryException extends RuntimeException {
public DiaryException() {}
public DiaryException(String message) {
super(message);
}
}
이제 앞에서처럼 http://localhost:8080/diary/18 로 이동해서 klist02@naver.com 으로 로그인하게 되면 아래처럼 예외가 표시될거야.
대신 klist02@naver.com 이 작성한 id 고유값 19 번은 정상적으로 읽어와지지.
DiaryService 의 GetDiary 에 작성한 로직을 UpdateDiary 와 DeleteDiary 에도 작성해주면 되겠네.
@Service
public class DiaryService {
...
public void UpdateDiary(Integer id, String diary_date, String diary_content) {
String email = SecurityContextHolder.getContext().getAuthentication().getName();
Diary diary = diaryMapper.GetDiary(id);
if (!diary.getEmail().equals(email)) {
throw new DiaryException("작성자가 아닙니다.");
}
diaryMapper.UpdateDiary(id, diary_date, diary_content);
}
public void DeleteDiary(Integer id) {
String email = SecurityContextHolder.getContext().getAuthentication().getName();
Diary diary = diaryMapper.GetDiary(id);
if (!diary.getEmail().equals(email)) {
throw new DiaryException("작성자가 아닙니다.");
}
diaryMapper.DeleteDiary(id);
}
...
}
이제 수정한 로직을 테스트해볼건데, Postman 이라는 앱을 이용해보려고 해. PUT 이나 DELETE 메소드는 웹브라우저만으로는 테스트하기가 어렵기 때문이야. Postman 앱은 https://www.postman.com/downloads/ 에서 다운로드받을 수 있어.
Postman
우선 로그인을 해야만 diary 프로그램을 사용할 수 있기 때문에 Postman 에서 로그인폼을 호출해볼께.
로그인폼 URL 은 http://localhost:8080/login 인데, GET 방식으로 호출하면 돼.
"Send" 버튼을 클릭하면 아래쪽에 결과가 표시가 되지.
결과는 로그인폼의 소스인데, 조금 스크롤해보면 form 태그 안에 name="_csrf" 가 보여. 그 값을 일단 복사해둘께. 이 값은 로그인처리를 하는 URL 에 그대로 전송시켜야 하거든.
이번에는 실제 로그인을 처리해보자. URL 에 http://localhost:8080/process_login 을 입력하고 method 를 POST 로 변경시켜보자.
전달할 파라미터를 입력하기 위해서 Body 탭을 선택하고 email, password, _csrf 를 추가해줘. _csrf 키의 값으로 조금 전에 복사해둔 값을 입력한 다음에 "Send" 버튼을 눌러보자.
아래쪽 결과를 실제 웹페이지처럼 보고 싶으면 Preview 탭을 선택해주면 돼.
이제 woohaha@gmail.com 으로 로그인한 상황이 되었어.
이 상태에서 klist02@naver.com 이 작성한 일기 고유번호 19 번을 Update 하는 시도를 해볼께. 일단 일기수정 폼을 호출해보자.
GET 방식으로 http://localhost:8080/diary/edit/19 URL 을 호출하면 아래와 같이 작성자가 아닙니다 라는 오류 메시지가 리턴되는걸 확인할 수 있어.
일기데이터 수정은 edit 폼에서 PUT method 로 http://localhost:8080/diary/19 를 호출해야 하는데, 여기에서부터 막혔으니까 잠시 가능하도록 풀어줄께.
@Service
public class DiaryService {
...
public Diary GetDiary(Integer id) {
String email = SecurityContextHolder.getContext().getAuthentication().getName();
Diary diary = diaryMapper.GetDiary(id);
if (!diary.getEmail().equals(email)) {
//throw new DiaryException("작성자가 아닙니다.");
}
return diary;
}
...
}
코드를 수정했으니, 프로그램을 재실행해서 로그인 과정부터 다시 수행해야 해. 그리고 일기수정 폼까지 무리없이 진행되는걸 확인할 수 있을거야.
PUT method 를 테스트하기 전에 일기수정 폼에 들어있는 _csrf 의 속성값을 사용해야 해.
리턴된 결과에서 DiaryService 의 UpdateDiary 에서 Exception 이 발생했다는걸 확인할 수가 있어.
이어서 DELETE method 도 테스트해보자.
일기데이터 수정 폼을 호출해서 _csrf 속성값을 가져와서
DELETE method 의 Header 에 X-CSRF-TOKEN 키를 추가하고 값으로 설정하면 돼.
그리고나서 "Send" 버튼을 클릭하면 Exception 내용을 확인할 수가 있어.
'SpringBoot' 카테고리의 다른 글
[SpringBoot] diary - Sign in with Google (0) | 2024.11.13 |
---|---|
[SpringBoot] AWS SES 를 이용하여 메일 발송 테스트 (0) | 2024.11.01 |
[연재] Spring Boot diary : 로그인정보 조회 (0) | 2024.04.29 |
[연재] Spring Boot diary : study.diary 멤버 가입 (0) | 2024.04.29 |
[연재] SpringBoot diary : 설정파일 분리 (IntelliJ, Jenkins) (0) | 2024.04.09 |