메뉴 건너뛰기

app

사용자의 권한을 훔치는 실선 없는 공격: CWE-352 CSRF

suritam92026.01.17 18:59조회 수 0댓글 0

    • 글자 크기

1. CSRF(Cross-Site Request Forgery)의 위험성

CSRF는 사용자가 자신의 의지와는 무관하게 공격자가 의도한 행위(데이터 수정, 삭제, 등록 등)를 특정 웹사이트에 요청하게 만드는 공격입니다. 공격자는 사용자가 로그인된 상태로 브라우저를 사용하고 있다는 점을 악용합니다. 사용자가 공격자가 만든 악성 페이지를 방문하거나 이메일의 링크를 클릭하는 순간, 브라우저에 저장된 세션 쿠키가 자동으로 함께 전송되어 서버는 이를 정당한 사용자의 요청으로 오인하고 실행하게 됩니다. 비밀번호 변경이나 자금 이체와 같은 민감한 기능이 이 공격에 노출될 경우 파괴적인 결과를 초래합니다.

2. 흔히 발생하는 취약한 패턴

가장 대표적인 사례는 모든 요청을 GET 방식으로 처리하거나, POST 방식을 사용하더라도 별도의 검증 수단 없이 세션 쿠키에만 의존하여 사용자를 인증하는 경우입니다. 공격자는 <img src="..."> 태그나 자바스크립트를 이용해 보이지 않는 곳에서 요청을 발생시킬 수 있습니다. 특히 API 설계 시 CSRF 방어 로직이 누락되면, 공격자가 사용자의 권한을 이용해 게시물을 삭제하거나 개인정보를 변경하는 등의 행위가 가능해집니다.

3. 실무적 대응: CSRF 토큰과 SameSite 설정

단순히 세션이 유효한지만 체크해서는 안 되며, 다음과 같은 다중 방어막이 필요합니다.

CSRF 토큰 사용: 매 요청마다 서버에서 발급한 임의의 난수(Token)를 세션에 저장하고, 클라이언트가 전달한 토큰값과 일치하는지 대조합니다. 공격자는 이 토큰값을 알 수 없으므로 위조 요청이 불가능합니다.

SameSite 쿠키 속성: 쿠키 설정 시 SameSite=Strict 또는 Lax 속성을 부여하여, 타 사이트에서 발생하는 요청에는 쿠키가 포함되지 않도록 차단합니다.

재인증 요구: 비밀번호 변경, 결제 등 민감한 기능 실행 직전에 비밀번호를 다시 입력받거나 2차 인증(OTP 등)을 수행합니다.

4. CWE-352 대응 및 안전한 처리 자바 코드 예시

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.security.SecureRandom;
import java.util.Base64;
 
public class CsrfGuard {
    private static final Logger logger = LoggerFactory.getLogger(CsrfGuard.class);
 
    // [CWE-330, CWE-352 조치] 안전한 난수 생성을 통한 CSRF 토큰 발급
    public static String generateToken(HttpSession session) {
        SecureRandom sr = new SecureRandom();
        byte[] tokenBytes = new byte[32];
        sr.nextBytes(tokenBytes);
        String token = Base64.getEncoder().encodeToString(tokenBytes);
        
        // 세션에 토큰 저장
        session.setAttribute("CSRF_TOKEN", token);
        logger.debug("New CSRF token generated and stored in session.");
        return token;
    }
 
    // [CWE-352 조치] 요청 시 토큰 일치 여부 검증
    public boolean validateToken(HttpServletRequest request) {
        HttpSession session = request.getSession(false);
        if (session == null) return false;
 
        String sessionToken = (String) session.getAttribute("CSRF_TOKEN");
        String requestToken = request.getParameter("_csrf"); // 또는 헤더에서 추출
 
        if (sessionToken == null || !sessionToken.equals(requestToken)) {
            // [CWE-754, CWE-390] 검증 실패 시 로그 기록 및 차단
            logger.debug("Security Violation: CSRF token mismatch or missing.");
            return false;
        }
 
        logger.debug("CSRF token validated successfully.");
        return true;
    }
}

코멘트: CSRF 방어의 핵심은 "서버가 받은 요청이 사용자의 실제 의도에서 비롯된 것인가?"를 확인하는 것입니다. 세션 쿠키는 브라우저에 의해 자동으로 전송될 수 있다는 사실을 잊지 마십시오. 스프링 시큐리티(Spring Security)와 같은 프레임워크를 사용한다면 CSRF 기능을 활성화하고, 커스텀 환경이라면 반드시 매개변수화된 토큰 검증을 도입하십시오. logger.debug()를 통해 부적절한 요청 시도를 모니터링하되, 사용자의 권한이 공격자의 도구로 전락하지 않도록 방어막을 구축하는 것이 시큐어 코딩의 의무입니다.

 
    • 글자 크기
내부망 침투의 교두보: CWE-918 SSRF 방지 전략 (by suritam9) 기업 인증 체계를 무너뜨리는 CWE-90 LDAP 삽입 방지 전략 (by suritam9)

댓글 달기

첨부 (0)
위로