전자금융기반시설 보안 취약점 평가기준 - WEB-SER-049

불필요한 HTTP Method 악용 (WM) | 위험도: 2 (낮음) | 통제구분: 5.5.1 HTTP 메서드 제한

케이뱅크

인터넷뱅킹 API 서버

취약점: 불필요한 HTTP Method 허용

HTTP Method 테스터

서버 응답

HTTP Method를 선택하고 요청을 전송하세요

공격 시나리오

취약한 설정

위험
// ❌ 모든 HTTP Method 허용

// Spring Controller
@RestController
@RequestMapping("/api/users")
public class UserController {
    
    // Method 제한 없음!
    @RequestMapping("/{id}")
    public User getUser(@PathVariable Long id) {
        return userService.findById(id);
    }
    
    // DELETE 허용
    @DeleteMapping("/{id}")
    public void deleteUser(@PathVariable Long id) {
        // 권한 체크 없음!
        userService.delete(id);
    }
    
    // PUT 허용
    @PutMapping("/{id}")
    public User updateUser(@PathVariable Long id,
                          @RequestBody User user) {
        // 소유자 확인 없음!
        return userService.update(id, user);
    }
}

// Apache 설정 - Method 제한 없음
<Directory /var/www/html>
    <!-- 모든 Method 허용 -->
    AllowOverride All
    Require all granted
</Directory>

// web.xml - TRACE 활성화
<!-- TRACE method 비활성화 안 됨 -->

공격 실행 결과

대기중

공격 시나리오를 선택하세요

안전한 설정

권장
// ✅ HTTP Method 명시적 제한

// 1. Spring - 필요한 Method만 허용
@RestController
@RequestMapping("/api/users")
public class UserController {
    
    // GET만 허용
    @GetMapping("/{id}")
    public User getUser(@PathVariable Long id) {
        return userService.findById(id);
    }
    
    // DELETE - 권한 검증 필수
    @DeleteMapping("/{id}")
    @PreAuthorize("hasRole('ADMIN')")
    public void deleteUser(@PathVariable Long id,
                          Authentication auth) {
        
        // 본인 또는 관리자만 삭제 가능
        User currentUser = (User) auth.getPrincipal();
        if (!currentUser.isAdmin() && 
            !currentUser.getId().equals(id)) {
            throw new AccessDeniedException();
        }
        
        userService.delete(id);
    }
    
    // PUT - 소유자 확인
    @PutMapping("/{id}")
    public User updateUser(@PathVariable Long id,
                          @RequestBody User user,
                          Authentication auth) {
        
        User currentUser = (User) auth.getPrincipal();
        
        // 본인 데이터만 수정 가능
        if (!currentUser.getId().equals(id)) {
            throw new AccessDeniedException();
        }
        
        return userService.update(id, user);
    }
}

// 2. Spring Security - Method 제한
@Configuration
public class SecurityConfig {
    
    @Bean
    public SecurityFilterChain filterChain(
        HttpSecurity http) throws Exception {
        
        http
            .authorizeHttpRequests(auth -> auth
                // 읽기는 인증된 사용자
                .requestMatchers(HttpMethod.GET, "/api/**")
                    .authenticated()
                
                // 쓰기는 관리자만
                .requestMatchers(HttpMethod.POST, "/api/**")
                    .hasRole("ADMIN")
                .requestMatchers(HttpMethod.PUT, "/api/**")
                    .hasRole("ADMIN")
                .requestMatchers(HttpMethod.DELETE, "/api/**")
                    .hasRole("ADMIN")
                
                // TRACE, OPTIONS 차단
                .requestMatchers(HttpMethod.TRACE, "/**")
                    .denyAll()
                .requestMatchers(HttpMethod.OPTIONS, "/**")
                    .denyAll()
            );
        
        return http.build();
    }
}

// 3. Apache - Method 제한
<Directory /var/www/html>
    <!-- GET, POST만 허용 -->
    <LimitExcept GET POST>
        Require all denied
    </LimitExcept>
    
    <!-- TRACE 비활성화 -->
    TraceEnable off
</Directory>

// 4. Nginx - Method 제한
server {
    location /api {
        # GET, POST만 허용
        limit_except GET POST {
            deny all;
        }
        
        # TRACE 차단
        if ($request_method = TRACE) {
            return 405;
        }
        
        proxy_pass http://backend;
    }
}

// 5. Filter로 Method 검증
@Component
public class HttpMethodFilter extends OncePerRequestFilter {
    
    private static final Set ALLOWED_METHODS = 
        Set.of("GET", "POST");
    
    @Override
    protected void doFilterInternal(
        HttpServletRequest request,
        HttpServletResponse response,
        FilterChain chain) throws IOException {
        
        String method = request.getMethod();
        
        // 허용된 Method인지 확인
        if (!ALLOWED_METHODS.contains(method)) {
            response.sendError(
                HttpServletResponse.SC_METHOD_NOT_ALLOWED,
                "Method " + method + " not allowed"
            );
            return;
        }
        
        // TRACE 특별 차단
        if ("TRACE".equals(method)) {
            response.sendError(
                HttpServletResponse.SC_FORBIDDEN,
                "TRACE method is disabled"
            );
            return;
        }
        
        chain.doFilter(request, response);
    }
}

// 6. WebDAV 비활성화
<IfModule mod_dav.c>
    # WebDAV 완전 비활성화
    DavLockDB /dev/null
    Dav Off
</IfModule>

HTTP Method 보안 체크리스트

필요한 Method만: GET, POST만 허용
TRACE 차단: XST 공격 방어
OPTIONS 제한: 정보 노출 방지
DELETE/PUT 권한: 관리자만 허용
WebDAV 비활성화: 불필요한 기능 제거
405 응답: 허용되지 않은 Method

HTTP Method 허용 매트릭스

Method 일반 사용자 관리자
GET ✓ 허용 ✓ 허용
POST ✓ 허용 ✓ 허용
PUT ✗ 차단 △ 제한적
DELETE ✗ 차단 △ 제한적
TRACE ✗ 차단 ✗ 차단
OPTIONS ✗ 차단 ✗ 차단