📕🐘 도로락 - 코끼리를 냉장고에 넣는 방법
자바[Java] | 2019. 3. 22. 10:15

[Apache Shiro] 아파치 시로란 무엇인가? JAVA 보안 프레임워크 아파치 시로 간략 개념

주의)

이 글은 미천한 영어 실력으로 인해 다음의 원문을 의역과 오역을 통해 작성된 글입니다. 거기에 주관적인 의견이 중간중간 섞여 있으므로 Shiro가 이러이러한 느낌이구나 정도만 참고해 주시면 감사하겠습니다.

원문 - https://www.infoq.com/articles/apache-shiro

누가 Shiro 소리를 내었는가? Shiro는 무엇인가 말이야

Apache Shiro는 인증, 권한관리, 암호화, 세션관리를 수행하는 강력한 Java Security(보안) 프레임워크입니다. Shiro는 일본어로 城(성, castle)을 뜻하며 '시로'라고 발음됩니다. 즉 외부 침입으로부터 보호를 위해 만들어진 성이라는 의미를 담고 있는 게 아닌가 싶습니다.

왜 일본어인 shiro를 채택했는지 확실하지는 않지만 Shiro의 개발자 대표의 취미가 일본어 공부임을 생각해볼 때 어느 정도 납득(?)이 되지 않나 싶습니다.

Apache Shiro의 등장 배경

Shiro는 2003년 jSecurity라는 프로젝트로 시작되어 2019년 현재 16년이라는 시간 동안 발전해왔습니다. 2003년 당시에는 Java 진영에 사용할만한 베스트 프랙티스가 없었으니 jSecurity 프로젝트는 Java 진영 개발자들에게는 반가운 소식이었을 것입니다.

당시에 EJB라는 강력한 솔루션이 있었으나 EJB는 컨테이너에 종속적이기 때문에 모든 Java 응용프로그램의 솔루션이 될 수 없었을 것입니다. 또한 당시에는 구글 같은 정보를 제공해 줄만한 사이트가 없었기에 암호화 같은 고급 기술은 전문가가 아닌 이상 사용하기 힘들었을 것입니다. 그러한 이유로 보안은 물론 암호화마저 깔끔한 API로 손쉽게 사용할 수 있도록 해주는 Shiro는 고마운 솔루션이 아닐 수 없습니다.

Shiro의 기능

Shiro는 크게 다음의 기능을 제공합니다. 이는 어떤 어플리케이션에서든 대부분 공통적으로 요구하는 기능들입니다.

  • 인증 - 보통 로그인이라는 신원 증명 기능을 제공합니다.
  • 권한 부여 - 접근을 제어합니다.
  • 암호화 - 중요한 데이터를 보호하거나 숨깁니다.
  • 세션 관리 - 사용자별 세션을 관리합니다.

Shiro의 장점

사용이 쉬움 - 최대한 API를 사용하기 쉽도록 설계(이건 누구 생각이야?)

유연성 - 특정 환경이나 컨테이너(톰캣 같은)에 종속되지 않습니다.

웹 환경 지원 - 명령행에서 실행하거나 Swing을 이용하는 독립형 Java 어플리케이션뿐만 아니라 웹 환경도 지원합니다. (즉 JSP/Servlet 환경도 지원함)

지원 - Shiro는 꾸준히 업데이트되고 있습니다.

확장성 - 공식 홈페이지에는 Pluggable이라고 되어 있는데, Spring 프레임워크는 물론 이 밖에도 여러 가지 환경과 통합될 수 있도록 지원합니다.

Shiro의 핵심 개념: Subject, SecurityManager, Realm

여기서부터는 Shiro 프레임워크에 대한 간략한 내용입니다. 제목에서 언급했듯이 Shiro에는 크게 중요한 세 가지 개념이 있으며 Java의 API답게 Subject, SecurityManager, Realm이라는 인터페이스로 제공됩니다.

Subject

응용프로그램의 보안에서 가장 중요하면서도 흔하게 고려해야 할 점은 "현재 응용프로그램에 접속된 사용자(주체)가 누구인가?"일 것입니다. Shiro에서는 Subject를 현재 Shiro의 세계에 접속한 사용자를 나타내는 API로 사용합니다. Subject는 주제라고 해석할 수도 있지만 어릴 때 영어를 공부했다면 5형식을 외웠을 당시에 S는 Subject를 뜻하며, 주어, 주체를 뜻한다는 사실을 떠올릴 수 있습니다.

이는 Servlet/JSP 환경에서 Session(현재 접속 중인 주체인 브라우저)과 비슷한 개념이라 할 수 있습니다. 비슷한 개념이라 말했지만 Shiro를 웹 환경에서 사용하는 경우 Shiro는 서블릿 컨테이너(예를 들어 톰캣)에서 제공하는 javax.servlet.HttpSession 인스턴스를 기반으로 Subject를 만듭니다. (물론 HttpSession = Subject라는 것이 아니라 Subject가 세션을 가지고 있는 개념입니다.)

코드1. Subject를 얻는 방법은 다음과 같습니다.

import org.apache.shiro.subject.Subject;
import org.apache.shiro.SecurityUtils;

...
Subject currentUser = SecurityUtils.getSubject();

Subject를 획득했다면 이제 이 Subject를 통해 로그인, 로그아웃을 수행함은 물론이고 세션 접근이나 권한 확인 등 Shiro에서의 거의 대부분의 정보를 얻을 수 있습니다. 또한 어플리케이션 코드 내에서는 어디서나 Subject를 얻어 보안과 관련된 작업을 수행할 수 있습니다.

SecurityManager

Subject가 현재 접속한 사용자에 대응되는 녀석이라면 SecurityManager는 어플리케이션에 접속해 있는 모든 사용자를 관리하는 역할을 합니다. Shiro의 핵심 기반이라 할 수 있겠습니다.

질문! 그럼 SecurityManager를 설정하는 방법은? 어쨌든 Spring을 사용하려면 Spring의 핵심인 DI/IOC 컨테이너를 설정해야 하는 것과 마찬가지로 Shiro를 사용하려면 SecurityManager를 설정해야 합니다. 그러나 SecurityManager를 설정하는 방법은 어플리케이션의 환경에 따라 다릅니다. 예를 들어 웹 어플리케이션 환경이라면 Spring에서 DispatcherServlet을 등록하듯이 Shiro ServletFilterweb.xml에 등록해야 합니다.

독립형 Java 어플리케이션이라면 다른 방법으로 구성해야 합니다. 또한 SecurityManager는 특별한 경우가 아니라면 어플리케이션당 하나(singleton)만 생성하는 것이 거의 대부분이며, Java 코드, Spring XML, YAML, .properties 파일 등을 사용하여 구성할 수 있습니다.

보통 여러 환경에서 공통적으로 사용할 수 있는 INI(Initialization) 파일을 사용할 수 있도록 제공합니다. INI 파일은 단순 텍스트 파일이고 속성이름=값 형식이기 때문에 읽기에도 쉽고 특정 환경에 종속적이지 않기 때문에 여러 환경에서 쉽게 사용할 수 있기 때문입니다.

예를 들어 아래와 같이 설정을 구성할 수 있습니다.

코드2. INI로 Shiro 설정 구성하기

[main]
cm = org.apache.shiro.authc.credential.HashedCredentialsMatcher
cm.hashAlgorithm = SHA-512
cm.hashIterations = 1024
# Base64 encoding (less text):
cm.storedCredentialsHexEncoded = false


iniRealm.credentialsMatcher = $cm


[users]
jdoe = TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJpcyByZWFzb2
asmith = IHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbXNoZWQsIG5vdCB

(이거 뭐 .properties 랑 똑같은 거 아냐? 라고 할 수도 있겠지만 아주 조금 다릅니다. 예를 들어 [main] 섹션을 보면 []는 섹션을 나타냅니다. 즉 속성들이 무엇을 의미하는지 섹션으로 구분 지을 수 있습니다는 차이가 있습니다.)

코드2는 SecurityManager 설정 예제입니다. [main] 섹션과 [users] 섹션이 있다는 것을 눈치 채셨을 것입니다. (그렇다고 믿고 있습니다)

일단 [main] 섹션은 SecurityManager 객체나 Shiro 프레임워크에서 사용되는 여러 가지 구성요소 객체(나중에 배우겠지만 Realm 같은)들을 구성하는 섹션입니다. 현재 코드2에는 두 개의 객체만을 구성하고 있습니다.

코드2-1. 자세한 설명을 위해 코드2에서 [main] 섹션의 코드만 긁어왔습니다.

[main]
cm = org.apache.shiro.authc.credential.HashedCredentialsMatcher
cm.hashAlgorithm = SHA-512
cm.hashIterations = 1024
# Base64 encoding (less text):
cm.storedCredentialsHexEncoded = false

자세히 보면 cmHashedCredentialsMatcher 객체를 할당하고 아래 설정들은 cm에 대한 설정들임을 알 수 있습니다. 마치 객체를 생성하고 setXXX() 메서드를 통해 값을 설정하는 것 같습니다. 그렇습니다. Shiro가 이 INI를 읽게 되면 실제 그런 식으로 초기화를 진행합니다.

아직 끝이 아닙니다. [main] 섹션의 가장 아래를 봅니다.

iniRealm.credentialsMatcher = $cm

iniRealm은 INI를 이용하여 SecurityManager가 동작할 때 사용되는 객체입니다. 아무튼 INI를 이용한 SecurityManagercredentialsMatcher에 앞서 설정해 둔 HashedCredentialsMatcher를 할당하고 있습니다. $cm은 앞서 설정한 cm을 가리킵니다. (마치 C 언어에서 포인터에 *을 붙일 때와 안 붙일 때의 차이점 같습니다.)

마지막으로 [users] 섹션은 그냥 테스트용 사용자 계정 정의입니다. jdoe, asmith 사용자를 정의했습니다. 값으로 할당된 것은 암호입니다.

[users]
jdoe = TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJpcyByZWFzb2
asmith = IHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbXNoZWQsIG5vdCB

코드3. shiro.ini 설정 파일 로딩하는 방법

```java import org.apache.shiro.SecurityUtils; import org.apache.shiro.config.IniSecurityManagerFactory; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.util.Factory;

//1. Load the INI configuration (classpath상에 위치한 INI 설정파일 로드) Factory factory = new IniSecurityManagerFactory("classpath:shiro.ini");

//2. Create

도로락

도로락

Writer

IT, 프로그래밍, 컴퓨터 활용 정보 등을 위한 블로그