250x250
Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- apache.poi
- Jenkins
- QueryDSL
- spring
- poi
- ci/cd
- DevOps
- 그리드
- 보안
- jqGrid
- 대용량 업로드
- 제이쿼리그리드
- ORM
- 스트림
- Javascript
- 자동빌드
- rabbitmq
- 엑셀 업로드
- MessageQueue
- Stream
- docker
- 자동배포
- mssql
- stream api
- JPA
- mom
- 자바8
- java
- sqlserver
- JQuery
Archives
- Today
- Total
개발 메모장
[보안] Replay Attack 정의 및 대응 본문
728x90
#. Replay Attack 이란?
- 공격자가 이전에 기록된 쿠키 및 세션 정보를 가로채서 악의적으로 재전송하는 네트워크 공격의 한 형태입니다.
- 재생 공격의 목표는 유효한 데이터나 명령이 합법적이고 새로 생성된 것처럼 하여 시스템을 속이며 이러한 유형의 공격은 일부 시스템이 동일한 데이터의 반복 또는 중복 전송으로부터 적절하게 보호하지 못한다는 사실을 이용합니다.
- 사용자의 쿠키 및 세션 인증 정보를 재사용하여 웹 서비스를 별도의 로그인 없이 이용이 가능한 것을 의미합니다.
- 즉, 로그인한 사용자 정보를 쿠키 또는 세션 방식으로 저장하여 인증 확인 시 사용하는데 악성 사용자가 임의의 사용자의 쿠키 및 세션 정보를 가로채 로그인 인증을 우회할 수 있게 됩니다.
#. 대응 방안
- 사용자 인증 및 권한을 체크를 위해 사용하는 값(ID, Auth Code 등)을 GET/POST로 사용한 사용자 입력으로 처리하거나 쿠키에 저장하지 않아야 합니다.
- 입력 값이 사용자 아이디와 같은 파라미터가 들어오거나 쿠키에 사용자 아이디가 암호화되지 않은 평문으로 저장되어 있으면 조작이 가능하기 때문에 공격자가 원하는 아이디로 조작이 가능해집니다. 그렇기에 기본적으로 세션으로 인증 정보를 저장하고 세션 생성 시 클라이언트 IP를 세션 정보에 추가한 뒤 암호화하여 특정 사용자가 서로 다른 IP에서 로그인할 수 없도록 처리해야 합니다.
- 암호화를 한 후 암호화된 값의 변경 유무를 확인할 수 있도록 설정하는 것이 좋습니다.
- 세션 정보의 만료 날짜를 짧게 설정하고 영구적인 값은 설정하지 않는 것이 좋습니다. 또한, 로그아웃 후에는 세션 ID를 invalidate 처리해야 합니다.
#. 처리 방법
- 위 대응 방안 중 2번을 이용하여 처리하였고 처리방법은 생각보다 간단합니다.
- 모든 페이지를 관리하는 Interceptor에 로직을 추가하여 쿠키를 이용해 어떠한 페이지를 접속하여도 걸러질 수 있게 처리하였습니다.
import java.nio.charset.StandardCharsets;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
public class TestInterceptor extends HandlerInterceptorAdaptor {
private static final String AES_ALGORITHM = "AES";
private static final String SECRET_KEY = "testSecKey"; // 16바이트 이하
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession();
String ip = request.getRemoteAddr();
if(session.getAttribute("ip") != null) {
String decIp = decryptIpAddress(session.getAttribute("ip").toString());
if(ip.equals(decIp)) {
} else {
session.invalidate();
response.sendRedirect("/login");
}
} else {
String encIp = encryptIpAddress(request.getRemoteAddr());
session.setAttribute("ip", encIp);
}
}
public static String encryptIpAddress(String ipAddress) {
try {
Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
SecretKey secretKey = new SecretKeySpec(SECRET_KEY.getBytes(StandardCharsets.UTF_8), AES_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] encryptedBytes = cipher.doFinal(ipAddress.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(encryptedBytes);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static String decryptIpAddress(String encryptedIpAddress) {
try {
Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
SecretKey secretKey = new SecretKeySpec(SECRET_KEY.getBytes(StandardCharsets.UTF_8), AES_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] encryptedBytes = Base64.getDecoder().decode(encryptedIpAddress);
byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
return new String(decryptedBytes, StandardCharsets.UTF_8);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
- 위의 내용을 정리하자면 처음 로그인한 사람의 세션에는 ip란 Attribute가 없습니다.
- 첫 번째 else로 빠지게 되어 setAttribute를 이용해 암호화한 ip를 세션에 저장합니다.
- 공격자는 암호화된 ip Attribute가 저장된 쿠키를 이용해 접속하기 때문에 getAttribute("ip") != null에 걸리게 됩니다.
- 이후 세션에 저장된 암호화 ip를 복호화하여 실제 접속한 ip 값과 비교합니다.
- 비교해서 다르다면 세션을 invalidate 하고 최초 페이지로 이동시킵니다.
#. 테스트
- 테스트를 위해 구글 웹스토어에서 editthiscookie를 설치하며 사용은 url입력창 우측에 퍼즐모양을 눌러 사용합니다.
- 아이피가 다른 클라이언트를 준비합니다.
- 아래 내용은 적용 전의 내용이며 위 방법을 적용 후 동일하게 처리해 보시면 되겠습니다.
#. 쿠키 복사하기

#. IP가 다른 클라이언트에서도 editthiscookie를 실행하여 복사한 쿠키를 붙여 넣어줍니다.

#. 이후 접속가능한 아무 url을 입력해 줍니다.

#. 이렇게 접속이 가능한 것을 볼 수 있습니다.
#. 수정 후 위와 같이 다시 테스트를 해보면 세션은 사라지고 리다이렉트를 통해 login 페이지로 이동하게 됩니다.
#. 로그인 시 로그인 정보를 DB에 저장하는 경우엔 DB에 ip를 저장한 뒤 이를 꺼내어 사용하는 것이 더 바람직합니다.
#. 또한 스프링 시큐리티의 maximumSessions를 이용해 간단히 처리가능합니다.
#. 위 내용을 참고하시어 처리하시면 쉽게 처리 가능하실 겁니다.
===========================================================
틀린 내용이 있거나 이견 있으시면 언제든 가감 없이 말씀 부탁드립니다!
===========================================================
728x90
'보안' 카테고리의 다른 글
[CDN] cdn.jsdelivr.net SSL 만료(부트스트랩 오류) (0) | 2024.05.03 |
---|---|
[보안] Jasypt를 이용한 민감정보 암호화 (0) | 2024.03.12 |
[보안] 시큐어 코딩이란? (1) | 2023.12.18 |
[보안] 파일 업로드 시 취약점 사전 대응 방법(Java, Windows) (1) | 2023.11.30 |
[보안-Windows] 방화벽 포트 열기 (1) | 2023.11.27 |