ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 스프링 시큐리티(Spring Security)를 이용한 보안 강화
    보안(Security)/Spring Security 2018. 9. 10. 10:18

    보안에 있어 가장 기본적이고 중요한 개념이 인증(Authentication)과 권한부여(Authorization) 두가지다.
    - 인증(Authentication)은 어플리케이션의 사용자가 사용자가 주장하는 본인이 맞는지 확인하는 절차로 3가지 인증기법이 주로 사용된다.
    * 크리덴셜 기반 인증 : 사용자명과 비밀번호를 이용한 방식
    * 이중 인증 : ATM 기기를 이용할 때처럼 물리적인 카드와 사용자가 입력한 개인정보 조합하는 방식
    * 하드웨어 인증 : 자동차 키를 통해 운전할 수 있는지 없는지를 가늠

    권한부여(Authorization)란 인증을 통해 인증된 주체를 하나 이상의 권한을 부여해 보호되는 자원들에 대한 접근 가능여부를 할당하는 것을 말한다.
    - 인증이 되었더라도 권한이 없다면 사용할 수 없는 게시판이 존재함

    Spring Framework 기반의 어플리케이션의 인증과 권한부여를 좀더 쉽게 할 수 있도록 Spring Security를 제공한다.
    - filter 기반으로 동작해 Spring MVC의 구현과 완전히 분리시켜 관리 가능하다.
    - 권한 기반의 허가를 지원하므로 경로별, 권한별 리소스 제한에 대해서도 많은 기능 적용 가능하다(지금은 잘 이해가 가지 않는다)

    이를 위해서 4개의 라이브러리가 필요하다. 
     spring-security-web
     aop-alliance
     spring-sercurity-core
     spring-security-config


    http://mvnrepository.com/


    Maven Repository 접속해 다운받는다.

    ※ 이클립스나 STS에 맞는 버전이 있으므로 호환성 꼭 확인하고 다운받도록 한다.
    spring-security 파일들은 4.0.0
    aop-alliance는 1.0 선택했다.


    다운받은 파일들을 Root Context 하위에 붙여넣는다 (폴더 만들어 관리 추천)

     - web.xml에 세션 리스너, 보안 필터 추가한다.



    <listener>
    		<listener-class>
    			org.springframework.security.web.session.HttpSessionEventPublisher
    		</listener-class>
    	</listener>
    	
    	<filter>
    		<filter-name>springSecurityFilterChain</filter-name>
    		<filter-class>
    			org.springframework.web.filter.DelegatingFilterProxy
    		</filter-class>
    	</filter>
      	<filter-mapping>
      		<filter-name>springSecurityFilterChain</filter-name>
      		<url-pattern>/*</url-pattern>
      	</filter-mapping>
    
    

    HttpSessionEventPublisher : 한 사용자가 다른 브라우저로 동시 로그인 막는 리스너
    DelegatingFilterProxy : 웹으로 들어오는 요청에 대해 스프링 시큐리티가 관여하도록 만들어주는 프록시 필터. 이를 통해 인증 및 권한 체크한다.






    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xmlns:sec="http://www.springframework.org/schema/security"
    	xsi:schemaLocation="
    			http://www.springframework.org/schema/beans
    			http://www.springframework.org/schema/beans/spring-beans.xsd
    			http://www.springframework.org/schema/security
    			http://www.springframework.org/schema/security/spring-security.xsd">
    	
    	<sec:http auto-config="true">
    		<sec:intercept-url pattern="/resources/**" access="permitAll"/>
    		<sec:intercept-url pattern="/" access="permitAll"/>
    		<sec:intercept-url pattern="/memberlogin" access="permitAll"/>
    		<sec:intercept-url pattern="/member/login" access="permitAll"/>
    		<sec:intercept-url pattern="/member/registry" access="permitAll"/>
    		<sec:intercept-url pattern="/member" access="hasRole('ROLE_USER')"/>
    		<sec:intercept-url pattern="/member/**" access="hasRole('ROLE_USER')"/>
    		<sec:csrf disabled="true" />
    		<sec:form-login login-page="/"
    						username-parameter="id"
    						password-parameter="password"
    						login-processing-url="/memberlogin"
    						default-target-url="/member/login"
    						authentication-failure-url="/"
    						always-use-default-target="true" />
    		<sec:logout logout-success-url="/"
    					logout-url="/member/logout2"
    					invalidate-session="true" />
    	<sec:session-management invalid-session-url="/">
    		<sec:concurrency-control max-sessions="1" expired-url="/" />
    	</sec:session-management>
    	</sec:http>
    	
    	<bean id="userService" class="kr.co.hucloud.security.UserService">
    		<property name="memberDAO" ref="memberDAO" />
    	</bean>
    	
    	<sec:authentication-manager>
    		<sec:authentication-provider ref="userService" />
    	</sec:authentication-manager>
    	
    </beans>
    
    

    securityContext.xml 작성해 Context Root 하위에 위치시킨다.
    스프링 시큐리티를 사용하기 위한 설정들을 정의한다.
    * <sec:http auto-config="true" > : http 경로 설정
    * <sec:intercept-url pattern="url" access="ROLE"> 웹 사이트 경로에 대한 접근 권한 제어할 수 있도록 한다.
    url 에 대해 "ROLE"이라는 권한이 있어야 접근할 수 있다.
    * hasIpAddress(ipAddress) : 특정 IP 주소 또는 넷마스크 포함하는 IP 주소와 일치성 비교한다.
    access="hasIpAddress('192.168.201.24')" / access="hasIpAddress('192.168.201.24/224')"
    *hasRole(role) Role 과 GrantedAuthority와의 일치성 비교한다.
    hasAnyRole(role) GrantedAuthority에 일치하는 권한이 있는지 비교한다.

    access에 넣을 수 있는 값들. 모두 "" 안에 입력해야 한다
    - permitAll : 모든 사용자 접근 허가
    - denyAll : 모든 사용자 접근 거부
    - anonymous : 익명 사용자 접근 허가
    - authenticated : 인증된 사용자에게만 허가
    - rememberMe : remember Me 기능으로 인증된 사용자에게만 접근 허가 (이해 안감)
    - fullyAuthenticated : 완전한 크리덴셜로 인증된 사용자에게만 접근 허가

    * <sec:csrf disabled="true"> : csrf 보안을 설정한다. 
    - Spring Security 4부터 추가되었고, true 설정시 모든 페이지에 token 값이 존재해야 한다.

    * <sec:form-login... />
    스프링 시큐리티 사용해 로그인할 설정
    - login-page : login 폼(form)이 존재하는 페이지 url
    - username-parameter : login 폼에서 id 태그의 name 속성값
    - password-parameter : login 폼에서 비밀번호 태그의 name 속성값
    - login-processing-url : 스프링 시큐리티를 이용해 로그인 처리할 url
    - AuthenticationProviter 구현부
    - default-target-url : 로그인 정상적으로 완료되면 이동할 페이지 url
    - authentication-failure-url : 로그인 실패시 이동할 url
    - always-use-default-target
    true 지정하면 로그인 성공시 default-target-url로 무조건 이동
    false로 지정하면 다른 페이지로 이동할 수 있도록 한다(이때 default-target-url 아닌 authentication-success-handler 이용해야 한다. 이해 안감)

    * <sec:logout> 로그아웃 처리할 url 설정
    logout-success-url : 로그아웃 성공시 이동할 페이지
    logout-url : 로그아웃 처리할 url 스프링 시큐리티가 만들어주기 때문에 Context 파일에 입력만 해두고 jsp에서 요청하면 된다.
    invalidate-session : 로그아웃시 세션 삭제여부 "true" 또는 "false"로 입력

    <sec:session-management> : 세션 관련 설정 태그
    invalid-session-url : 세션 타임아웃시 이동할 페이지
    max-sessions : 최대 허용 가능한 세션 수
    expired-url : 중복 로그인 발생시 이동할 주소. 처음 접속한 세션이 invalidate가 되고 다음 요청시 invalid-session-url로 이동한다.
    나중 접속 세션을 차단하고 싶다면 expired-url 대신 error-if-maximum-exceeded를 true로 설정한다.

    * <bean>
    DB, 암호화 방식 등에 대한 정보를 모르기 때문에 Bean 등록해 정보 전달한다.
    - form-login의 login-processing-url로 로그인 요청 들어올 경우 인증 처리한다.
    - AuthenticationProvider 인터페이스의 구현부가 처리(작성해야 함)

    * <sec:authencation-manager>
     authentication-provider : 로그인 처리 클래스를 인증 관리자에 등록한다.

    로그인 요청 url을 securityContext.xml의 login-processing-url로 변경한다.

    로그아웃 요청 url 마찬가지로 logout-url로 변경한다. 이제 로그인, 로그아웃 처리를 Spring Security를 통해 처리할 수 있게 됐다. 

    인터페이스 구현부 작성

    스프링 시큐리티가 사용할 커맨드 객체 생성한다. UserDetails 인터페이스를 구현한다.




    package kr.co.hucloud.security;
    
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.List;
    
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.authority.SimpleGrantedAuthority;
    import org.springframework.security.core.userdetails.UserDetails;
    
    import kr.co.hucloud.security.code.example.member.vo.MemberVO;
    /**
     * 
     * @author Admin
     * 스프링 시큐리티가 관리하는 객체 생성 방법.
     * 
     */
    public class User implements UserDetails{
    
    	private MemberVO memberVO;
    	
    	public User(MemberVO memberVO) {
    		this.memberVO = memberVO;
    	}
    	
    	public MemberVO getMemberVO() {
    		return memberVO;
    	}
    	@Override
    	public Collection getAuthorities() {
    		List authorities = new ArrayList();
    		authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
    		return authorities;
    	}
    
    	@Override
    	public String getPassword() {
    		return memberVO.getPassword();
    	}
    
    	@Override
    	public String getUsername() {
    		return memberVO.getId();
    	}
    
    	@Override
    	public boolean isAccountNonExpired() {
    		return true;
    	}
    
    	@Override
    	public boolean isAccountNonLocked() {
    		return true;
    	}
    
    	@Override
    	public boolean isCredentialsNonExpired() {
    		return true;
    	}
    
    	@Override
    	public boolean isEnabled() {
    		return true;
    	}
    }
    
    

    컨트롤러에서는 세션 등록과 나머지 작업을 수행하면 된다.
    이때 사용자 정보는 SecurityContextHolder.getContext().getAuthentication.getDetails();를 통해 가져온다. Authentication 구현부에서 setDetails(); 메소드의 결과를 가져오는 것이다.

    세션에 대한 정보를 로그인시 할당해주는 기존 로직 설정 방법. 이후 작업을 수행하면 로그인, 로그아웃시 보안을 강화할 수 있다.

Designed by Tistory.