[java] JAX-RS와 시스템 보안 및 해킹 방어

XML 기반의 정적 웹 서비스에서 RESTful 웹 서비스로의 전환은 더욱 빠르고 유연한 개발을 가능케 했습니다. JAX-RS는 Java 웹 애플리케이션에서 RESTful 웹 서비스를 구현하기 위한 API입니다. 그러나 보안은 웹 애플리케이션 개발의 중요한 측면 중 하나입니다. 이 글에서는 JAX-RS 애플리케이션에서 시스템 보안과 해킹 방어에 대해 알아보겠습니다.

1. 사용자 인증과 인가

RESTful 웹 서비스에서 가장 일반적인 보안 요구사항은 사용자 인증과 인가입니다. JAX-RS 애플리케이션에서는 사용자가 요청을 보내기 전에 인증을 거치고, 인증된 사용자에게 적절한 권한이 부여되어야 합니다.

1.1 Basic 인증

JAX-RS에서는 Basic 인증을 지원합니다. 클라이언트가 요청 헤더에 사용자 이름과 비밀번호를 포함하여 보내면, 서버는 이를 검증하여 인증합니다.

@GET
@Produces(MediaType.TEXT_PLAIN)
public Response getMessage(@HeaderParam("Authorization") String authentication) {
    if (authentication != null && authentication.startsWith("Basic")) {
        // 사용자 이름과 비밀번호 추출
        String base64Credentials = authentication.substring("Basic".length()).trim();
        byte[] credentials = Base64.getDecoder().decode(base64Credentials);
        String usernameAndPassword = new String(credentials);
        String[] parts = usernameAndPassword.split(":");

        // 사용자 인증 로직 구현
        if (authenticateUser(parts[0], parts[1])) {
            // 인증된 사용자에게 응답 반환
            return Response.ok("Hello, " + parts[0]).build();
        } else {
            // 인증 실패 시 에러 응답 반환
            return Response.status(Response.Status.UNAUTHORIZED).build();
        }
    } else {
        // 인증 헤더가 없을 경우 에러 응답 반환
        return Response.status(Response.Status.UNAUTHORIZED).build();
    }
}

1.2 토큰 기반 인증

토큰 기반 인증은 클라이언트에게 일련의 토큰을 발급하고, 이를 사용하여 요청을 인증하는 방법입니다. JAX-RS 애플리케이션에서는 주로 JWT(Json Web Token)을 사용하여 토큰 기반 인증을 구현합니다.

@GET
@Produces(MediaType.TEXT_PLAIN)
public Response getMessage(@HeaderParam("Authorization") String token) {
    if (token != null && token.startsWith("Bearer")) {
        // 토큰 검증 및 유효성 확인
        if (validateToken(token.substring("Bearer".length()).trim())) {
            // 인증된 사용자에게 응답 반환
            return Response.ok("Hello, user").build();
        } else {
            // 인증 실패 시 에러 응답 반환
            return Response.status(Response.Status.UNAUTHORIZED).build();
        }
    } else {
        // 인증 헤더가 없을 경우 에러 응답 반환
        return Response.status(Response.Status.UNAUTHORIZED).build();
    }
}

2. 보안 헤더 설정

JAX-RS 애플리케이션에서는 보안 헤더를 설정하여 보안을 강화할 수 있습니다. 예를 들어, Strict-Transport-Security 헤더를 설정하면 HTTPS를 통한 통신만 허용하도록 설정할 수 있습니다.

@GET
@Produces(MediaType.TEXT_PLAIN)
public Response getMessage() {
    // 보안 헤더 설정
    return Response.ok("Hello, secure world!")
            .header("Strict-Transport-Security", "max-age=31536000; includeSubDomains")
            .build();
}

3. SQL Injection 방어

JAX-RS 애플리케이션에서는 보안상 주의해야 할 취약점 중 하나인 SQL Injection에 대한 방어책을 마련해야 합니다. JAX-RS는 SQL Injection을 막을 수 있는 방법을 제공하며, 주로 PreparedStatement를 사용하여 사용자 입력을 쿼리에 바인딩하는 방법을 사용합니다.

@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getUser(@QueryParam("id") int userId) {
    // 쿼리 파라미터를 사용하여 쿼리 실행
    String sql = "SELECT * FROM users WHERE id = ?";
    try (Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "user", "password");
         PreparedStatement statement = connection.prepareStatement(sql)) {
        statement.setInt(1, userId);
        ResultSet resultSet = statement.executeQuery();

        // 결과 반환
        if (resultSet.next()) {
            String username = resultSet.getString("username");
            return Response.ok("Username: " + username).build();
        } else {
            return Response.status(Response.Status.NOT_FOUND).build();
        }
    } catch (SQLException e) {
        return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
    }
}

위의 예제에서는 사용자가 제공한 id 파라미터를 쿼리에 직접 연결하지 않고, PreparedStatement를 사용하여 값을 바인딩한 후 쿼리를 실행합니다. 이렇게 함으로써 SQL Injection 공격을 방지할 수 있습니다.

JAX-RS 애플리케이션에서 시스템 보안과 해킹 방어에 대한 고려는 매우 중요합니다. 이 글에서는 사용자 인증과 인가, 보안 헤더 설정, 그리고 SQL Injection 방어에 대해 알아보았습니다. 이러한 보안 조치를 통해 안전한 JAX-RS 애플리케이션을 개발할 수 있습니다.

참고 자료