보안을 적용하는 방법을 배움에 앞서 무엇으로부터 애플리케이션을 보호하는지 알아야합니다. 이유는 공격자는 공격을 시작하기 전에 취약한 부분을 공략하기 때문입니다.
이러한 취약성을 공부하기에 좋은 출발점으로 OWASP라고도 하는 오픈 웹 애플리케이션 보안 프로젝트에서는 일반적인 취약성에 대한 정보가 있습니다.
위와 같은 항목은 애플리케이션 수준의 보안에 대한 것이며 스프링 시큐리티 사용과 직접적 관련이 있습니다.
인증은 애플리케이션을 이용하려는 사람을 식별하는 프로세스를 의미합니다. 익명 액세스를 지원하기도 하지만 대부분 식별된 사용자만 특정 작업을 이용할 수 있게 합니다. 식별된 사용자에게 권한을 부여합니다. 권한 부여란 인증된 이용자가 특정 기능과 데이터에 대한 이용 권리가 있는지 확인하는 프로세스입니다.
인증 취약성이 있으면 다른 사람의 데이터에 접근 및 이용할 수 있는 상황이 나올 수 있습니다. 또한 수준에 따른 제한이 없는 경우도 마찬가지입니다.
해당 취약성은 웹 애플리케이션이 인증 프로세스중에 고유한 세션 ID를 할당하지 않아 기존 세션 ID가 재사용될 가능성이 있는 경우에 발생합니다. 즉, 이미 생성된 세션ID를 재이용해 유효한 사용자를 가장할 수 있습니다.
공격자는 유효한 세션ID를 획득한 후 사용자의 브라우저가 이를 이용하게 합니다. 웹 애플리케이션이 구현된 방식에 따라 다양하게 이용 가능하며 악성 링크 유도 및 외래 양식 이용 유도를 할 수 있습니다. 또한 애플리케이션이 세션 값을 쿠키에 저장하는 경우 스크립트를 주입하여 브라우저가 스크립트를 실행하게 할 수 있습니다.
클라이언트 쪽 스크립트를 주입하여 다른 이용자가 이를 실행하도록 하는 공격입니다. 이러한 외래 스크립트를 방지하기 위해 이용 전에 요청을 적절하게 확인하는 과정이 필요합니다. 해당 공격에 방어 체계가 없는 경우 XSS에 노출된 모든 이용자들이 공격자가 의도한대로 정보를 가져오거나 보낼 수 있습니다.
특정 서버에서 작업을 호출하는 URL를 추출하여 애플리케이션 외부에서 재사용할 수 있다는 가정하에 서버가 요청의 출처를 확인하지 않고 실행하면 다른 모든 곳에서 요청이 발생할 수 있습니다. 공격자는 사용자가 원치 않는 동작을 실행하도록 할 수 있어 시스템의 데이터를 변경하는 동작을 실행할 수 있습니다.
위와 같은 공격들은 취약점을 파악하여 데이터를 주입(Injection) 공격을 이용합니다. 원치 않는 요청 및 접근이 불가능한 데이터에 접근 및 변경하는 것이 목적입니다.
노출되지 말아야할 정보를 application.yml
, application.properties
와 같은 파일에 설정하면 소스 코드를 볼 수 있는 모든 사람이 이러한 개인값에 접근이 가능합니다. 또한 값의 변경 기록이 저장되는 것도 확인할 수도 있습니다. 공개 정보가 아닌 것은 절대 로그에 기록하지 말아야 합니다.
에를 들어 controller
-> service
-> repository
애플리케이션이 있고 controller
계층에만 권한 부여를 적용한다고 가정하였을 때 service
에서 인증된 사용자가 아니더라도 권한을 주고 repository
에서 데이터 검색을 제한하여 반환하지 않습니다. 당장은 문제가 생기지 않더라도 기능을 추가할 때 문제가 발생할 수 있습니다. 각각의 컨트롤러에 권한 부여 규칙을 다 적용한다면 괜찮을 수 있지만 각각의 계층에서 인증된, 권한이 있는 사용자에게 데이터를 노출하지 않는 것이 가장 바람직합니다.
어떠한 보안 시스템이 무조건 정답일수는 없습니다. 가장 알맞은 아키텍처를 사용해야 하며 이에 따라서 스프링 시큐리티 구성에도 큰 영향을 미칩니다.
다음과 같이 다양한 아키텍처에 적용된 보안이 있습니다.
일체형 웹 애플리케이션에서는 백엔드와 프론트엔드간 직접적인 분리가 없습니다. 애플리케이션이 HTTP 요청수신하고 응답을 클라이언트에 보내는 일반적인 서블릿 흐름을 통합니다. 예를 들어 스프링 부트로 개발을 진행할 때 액추에이터를 포함하는 경우 루트 접근 권한 없이도 다른 데이터에 접근 및 수정이 가능합니다. 이러한 접근 방식은 메모리에 유지되는 시간이 길수록 통계적으로 접근 가능성이 커집니다.
이러한 CSRF의 취약성을 완화하는 가장 쉬운 방법은 CSRF 방지 토큰을 사용하는 것입니다. 스프링 시큐리티에 기본적으로 포함되어있으며 CORS의 검증도 기본적으로 활성화 되어있습니다. 인증과 권한 부여를 통하여 사용자의 자격증명을 애플리케이션과 다른 시스템에서 관리할 수 있습니다.
OAuth2란 권한 부여 서버와 리소스 서버라는 두 가지 별도의 엔티티를 정의합니다. 권한 부여 서버의 목적은 사용자에게 권한을 부여하고 사용자의 이용 권리 집합을 지정하는 토큰을 제공하는 것입니다. 해당 기능을 구현하는 백엔드 부분을 리소스 서버라고 하며 호출할 수 있는 리소스에 대한 호출이 허용되거나 거부됩니다.
OAuth2의 흐름은 다음과 같습니다.
토큰의 수명은 고정되어 있으며 오래 유지되지 않습니다. 만료된 경우 새 토큰을 발급받아야 하며 필요한 경우 서버에서 토큰의 만료 시간보다 일찍 토큰을 만료시킬 수 있습니다. 이러한 방법을 사용하면 다음과 같은 장점이 있습니다.
이러한 토큰을 관리하는 방법은 앱 메모리에 토큰 유지, 데이터베이스에 토큰 유지, JWT를 통한 암호화 서명 사용 등이 있습니다.