티스토리 뷰
1. 로그인 시도 횟수 제한
- 로그인 시도 횟수에 제약을 주지 않는다면 공격자는 툴을 이용하여 무작위 대입 공격을 시도해 사용자의 로그인 정보를 얻을 수 있다.
- 때문에 로그인 시도에 대한 횟수를 체크하여 계정에 대한 보호조치를 취하여 대입공격을 막아야 한다.
- Standalone 서버에서 Singleton Pattern 의 코드를 사용하면 편리하다.
2. Singleton Pattern ?
- 객체를 한번만 생성하고, 그 객체에 접근이 가능하도록 하는 기능
- 객체 생성할 때 실행되는 생성자는 private로 접근을 막는다.
- 기존의 방법으로 생성자를 매번 생성한다면 객체마다 값이 달라지지만 Singleton을 이용하면 값이 같아진다.
3. Singleton Pattern을 이용한 로그인 시도 횟수 제한
LoginStore라는 Class 생성
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 |
package kr.co.hucloud.security.code.example.common;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpSession;
public class LoginStore {
// private static LoginStore loginStore = new LoginStore();
// private static volatile LoginStore loginStore = new LoginStore();
private static volatile LoginStore loginStore;
private Map<String, HttpSession> loginSessions;
private LoginStore() { //private 로 하면 생성자를 호출할 수 없다.
loginSessions = new HashMap<String, HttpSession>();
}
// synchronized 동기화
public static synchronized LoginStore getInstance() { // LoginStore 내부에서 생성자를 만든다.
// static : (메모리를 따로 가져간다.) instance를 만들지 않아도 사용할 수 있다.
// LoginStore loginStore = new LoginStore();
if (loginStore == null) {
loginStore = new LoginStore();
}
return loginStore;
}
public void add( String memberId, HttpSession session ) {
loginSessions.put(memberId, session);
}
public HttpSession get( String memberId ) {
return loginSessions.get(memberId);
}
public void logout( String memberId ) {
if ( loginSessions.containsKey(memberId) ) {
loginSessions.get(memberId).invalidate(); // logout 시키기
loginSessions.remove(memberId);
}
}
}
|
cs |
Controller 부분에서 로그인 횟수 제한에 대한 방어코드를 작성한다.
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47 |
@RequestMapping(value=("/member/login"), method=RequestMethod.POST )
public void login(LoginVO loginVO, HttpSession session, HttpServletResponse response) {
if ( memberService.isAccountLock(loginVO.getId()) ) { //true라면 잠긴 상태
SendMessage.send(response, "OVER");
return;
}
boolean isLoginSuccess = memberService.login(session, loginVO);
// 로그인 횟수 제한 방어코드 작성
if ( isLoginSuccess ) {
/*
* 1. LOGIN_FAIL_COUNT를 0으로 초기화한다.
* 2. IS_ACCOUNT_LOCK 를 'N'으로 초기화한다.
* 3. LATEST_LOGIN_DATE를 현재시간으로 수정한다.
*/
memberService.loginSuccess(loginVO.getId());
// Token 값 생성 및 등록 코드 작성
// 이후 게시판 글 쓰기 페이지에서 Token 값 전달 받아 비교.
String csrfToken = UUID.randomUUID().toString();
session.setAttribute(Session.CSRF_TOKEN, csrfToken);
}
else {
/*
* 1. LOGIN_FAIL_COUNT를 1 증가시킨다.
*/
memberService.plusLoginFailCount(loginVO.getId());
/*
* 1. LOGIN_FAIL_COUNT가 5이상이라면 IS_ACCOUNT_LOCK를 'Y'로 수정한다.
*/
memberService.updateAccountLock(loginVO.getId());
/*
* 1. IS_ACCOUNT_LOCK이 'Y'라면 브라우저에게 'OVER'라고 보낸다.
* OVER를 응답으로 받은 브라우저는 '로그인이 지속 실패하여 계정이 잠겼습니다. 운영자에게 문의하세요.'를 출력한다.
*/
boolean isLock = memberService.isAccountLock(loginVO.getId());
if( isLock ){
SendMessage.send(response, "OVER");
return;
}
}
SendMessage.send(response, isLoginSuccess ? "OK" : "NO");
} |
cs |
'Secure Coding' 카테고리의 다른 글
안전하지 않은 예외처리 (2) | 2016.05.02 |
---|---|
파일 업로드/다운로드 취약점 (0) | 2016.05.02 |
크로스 사이트 요청 위조 [ CSRF ] (0) | 2016.04.29 |
크로스 사이트 스크립팅 [ XSS ] (0) | 2016.04.29 |
패스워드 정책 (0) | 2016.04.28 |
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
TAG
- 예외처리
- mybatis
- servlet
- Baekjoon Online Judege
- INSERT
- java
- sort
- 안드로이드 스튜디오
- indexOf
- Spring
- DP
- order by
- table
- 자바
- RequestMapping
- boj
- BFS
- list
- 안드로이드 비콘
- algorithm
- restfb
- maven
- onBackPressed
- 이클립스
- jsp
- REDIRECT
- controller
- AlertDialog.Builder
- DFS
- onPostExecute
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
글 보관함