웹을 통해 데이터를 주고받는 업무를 진행할 경우, 보안상의 문제가 발생하기 쉽다.

Security Service는 웹을 통한 서비스 이용 시 발생할 수 있는 다양한 보안상의 취약점들을 사전에 인지하고 대응함으로써, 서비스의 안정성을 확보한다.

Security Service는 사용자 정보를 DB에서 관리하여 인증을 거쳐야만 접근할 수 있는 Authentication과 사용자 권한 정보를 계층화 시켜서 화면 및 페이지, 또는 메소드에 접근할 수 있는 Authorization이 포함된다.



웹어플리케이션 인증절차


1.리소스 요청

2.요청에 대해 보호되고 있는 자원인지 판단

3.아직 인증이 안되었으므로 HTTP 응답코드(오류) 또는 특정 페이지로 redirect

4.인증 메커니즘에 따라 웹 페이지 로그인 폼 또는 X509 인증서

5.입력 폼의 내용을 HTTP post 또는 인증 세부사항을 포함하는 HTTP 헤더를 서버로 요청

6.신원정보(credential)가 유효한지 판단

7.유효한 경우 다음단계 진행

8.유효하지 않을 경우 신원정보 재요청(되돌아감)

9.보호 자원의 접근 권한이 있을 경우 요청 성공 / 접근 권한이 없을 경우 forbidden 403 HTTP 오류






pom.xml


<!-- security -->
<dependency>
    <groupId>org.springframework.security</groupId>
     <artifactId>spring-security-web</artifactId>
    <version>4.1.2.RELEASE</version>
</dependency>
 
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-config</artifactId>
     <version>4.1.2.RELEASE</version>
 </dependency>
 
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-taglibs</artifactId>
    <version>4.1.2.RELEASE</version>
</dependency>
 
cs



web.xml



<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>
cs



context-security.xml





<?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:security="http://www.springframework.org/schema/security"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.1.xsd">
     
     <!-- url패턴과 스프링 시큐리티를 무시-->
    <security:http pattern="/**/*.js" security="none"/>
    <security:http pattern="/**/*.css" security="none"/>
    <security:http pattern="/images/*" security="none"/>
    
    <!-- 로그인페이지, 기본적인 인증, 로그아웃 기능을 사용, SpEL 사용 -->
    <security:http auto-config="true" use-expressions="true">
         <!-- 세션 관리 -->
        <security:session-management invalid-session-url="/">
            <!-- 동일 ID의 세션 최대수가 한 개, 그 이상일 경우는 기존 세션 무효화 -->
            <security:concurrency-control max-sessions="1" error-if-maximum-exceeded="false" />
        </security:session-management>
        
        <!-- 특정 url 패턴과 그것에 대한 권한 -->
        <security:intercept-url pattern="/admin/**" access="hasRole('ROLE_ADMIN')" />
         <security:intercept-url pattern="/write.do" access="hasAnyRole('ROLE_USER, ROLE_ADMIN')" method="GET"/>
        <security:intercept-url pattern="/**/update.do" access="hasAnyRole('ROLE_USER, ROLE_ADMIN')"/>
        <security:intercept-url pattern="/**/delete.do" access="hasAnyRole('ROLE_USER, ROLE_ADMIN')"/
        <security:intercept-url pattern="/**" access="permitAll"/>
        
        <!--     
                로그인 폼
                login-page                                :    로그인 폼 페이지
                login-processing-url                     :    로그인 폼 페이지에서 post로 보내는 url
                always-use-default-target="true"일 경우    :    write.do -> login.do -> list.do
                always-use-default-target="false"일 경우 :    write.do -> login.do -> write.do
                default-target-url                        :    인증이 성공하면 redirect로 보내는 url        
                authentication-failure-url                :    로그인 폼 페이지에서 실패할때 보내는 url
                username-parameter                        :    로그인 폼 파라미터 (아이디)
                password-parameter                        :    로그인 폼 파라미터 (비밀번호)
         -->
        <security:form-login 
            login-page="/login.do"
            login-processing-url="/login"
            always-use-default-target="true"
            default-target-url="/list.do"
            authentication-failure-url="/login.do?error=true"
            username-parameter="id"
            password-parameter="password"
        />
        
        <!-- 
            자동로그인  
            key                      :    키 이름
            token-validity-seconds   :    유효시간
            remember-me-parameter    :    로그인 폼 파라미터 (remember-me)
        -->
        <security:remember-me key="remember-key" token-validity-seconds="604800" remember-me-parameter="remember-me-param"/>
        
        <!-- 
            로그아웃
            logout-url            :    로그아웃 url
            logout-success-url    :    로그아웃 정상적일때 보내는 url
            invalidate-session    :    로그아웃 했을때 세션을 무효화 할껀지 설정
            delete-cookies        :    삭제하는 쿠키
         -->
        <security:logout logout-url="/logout" logout-success-url="/list.do" invalidate-session="true" 
            delete-cookies="JSESSIONID,SPRING_SECURITY_REMEMBER_ME_COOKIE"/>
        
    </security:http>
    
    <!-- 인증 관련 설정 -->
    <security:authentication-manager>
        <!-- 인증 제공자, userDetails와 userDetailsService 인터페이스 이용-->
        <security:authentication-provider>
            <!--
                jdbc 베이스로 한  userDetailsService
                data-source-ref                    : 참조할 DB빈 
                users-by-username-query            : 로그인 폼에서 입력된 아이디로 아이디, 비번, 활성화 칼럼을 select해 가져오는 쿼리
                                                     기본 파라미터가 username, password, enabled이므로 db의 칼럼이 다르면 as로 맞춰준다
                authorities-by-username-query     : 로그인 폼에서 입력된 아이디로 아이디, 권한 칼럼을 select해 가져오는 쿼리
                                                    기본 파라미터가 username, authority이므로 db의 칼럼이 다르면 as로 맞춰준다
            -->
            <security:jdbc-user-service
                data-source-ref="dataSource"
                users-by-username-query="select id as username, password, enabled from users where id = ?"
                authorities-by-username-query="select id as username, authority from user_roles where id = ?"
            />
        </security:authentication-provider>
    </security:authentication-manager>
</beans>

cs



Controller.java



@RequestMapping(value="login.do", method=RequestMethod.GET)
public ModelAndView loginForm(ModelAndView mav) {
    UsersVO usersVO = new UsersVO();
        
    mav.addObject("usersVO",usersVO);
    mav.setViewName("login");
    return mav;
}
cs



login.jsp




<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>    
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<style type="text/css">
table {
    border: 1px solid black;
    border-collapse: collapse;
}
tr, td {
    border: 1px solid black;
}
</style>
<script type="text/javascript">
function goList() {
    location.href = "${pageContext.request.contextPath}/";
}
</script>
</head
<body>
    <header>스프링 시큐리티 로그인 테스트</header>
    <section>
        <div>
            <form:form commandName="usersVO" action="${ pageContext.request.contextPath}/login"
                <table>
                    <tr>
                        <td>
                            <form:input path="id" placeholder="아이디"/
                        </td
                        <td rowspan="2">
                            <input type="submit" value="로그인">
                        </td>
                    </tr>
                    <tr>
                        <td>
                            <form:password path="password" placeholder="비밀번호"/>
                        </td>
                    </tr>
                    
                </table>
                    <input id="remember_me" name="remember-me-param" type="checkbox"/>아이디 저장
            </form:form>
            <input type="button" value="메인으로" onclick="goList()">
            <br>
            <c:if test="${ error eq 'true' }">
            <!-- 에러메세지와 무슨 에러인지 나타나게해줌 -->
            ${ sessionScope["SPRING_SECURITY_LAST_EXCEPTION"].message }
            <c:remove var="SPRING_SECURITY_LAST_EXCEPTION" scope="session"/>
            </c:if>
        </div>
    </section>
    <footer></footer>
</body>
</html>
cs



access 내장표현식


hasRole([role])

 현재 로그인된 사용자가 지정된 role을 가지고 있으면 true를 반환. 

 제공된 role이 'ROLE_'로 시작하지 않으면 기본적으로 'ROLE_'를 추가.

 hasAnyRole([role1,role2])

 현재 로그인된 사용자가 콤마(,)로 분리하여 주어진 role들 중 하나라도   

 가지고 있으면 true를 반환. 

 제공된 role이 'ROLE_'로 시작하지 않으면 기본적으로 'ROLE_'를 추가. 

 hasAuthority([authority])

 현재 로그인된 사용자가 지정된 권한이 있으면 true를 반환. 

 hasAnyAuthority([authority1,authority2])

 현재 로그인된 사용자가 콤마(,)로 분리하여 주어진 권한들중 하나라도 가지고 있으면 true를 반환. 

 principal

 현재 사용자를 나타내는 principal 객체에 직접 접근가능. 

 authentication SecurityContext로 부터 얻은 Authentication 객체에 직접 접근가능.

 permitAll

 항상 true를 반환. 

 denyAll

 항상 false로 반환. 

 isAnonymous()

 현재 사용자가 익명사용자(로그인 안됨) 사용자이면 true를 반환. 

 isRememberMe()

 현재 로그인된 사용자가 remember-me 사용자이면 true를 반환.

 (로그인 정보 기억 기능에 의한 사용자) 

 isAuthenticated()

 현재 사용자가 로그인된 사용자라면 true를 반환. 

 isFullyAuthenticated()

 로그인 정보 기억(remember-me)이 아니라 아이디/비밀번호를 입력하여 로그인 했다면 true를 반환.

 hasPermission(Object target, Object permission)

 사용자가 주어진 권한으로 제공된 대상에 액세스 할 수 있으면 true를 반환. 

 hasPermission(Object targetId, String targetType, Object permission)

 사용자가 주어진 권한으로 제공된 대상에 액세스 할 수 있으면 true를 반환.



  .jsp


1
2
3
4
5
6
7
8
9
10
<!-- 스프링 시큐리티 태그 -->
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags"%> 
 
<sec:authorize access="isAuthenticated()"></sec:authorize>
<!-- 현재 인증된 주체에 대해 구성된 액세스 표현식이 참으로 평가되는 경우 태그의 본문을 출력하는 태그 -->
 
<sec:authentication property="principal.username" var="loginID"/>${ loginID }
<!-- 현재의 Authentication 객체에 대한 액세스를 허용. 
var로 할당안하면 바로 출력 var로 할당하면 ${var의 이름}로 해야 출력-->
 
cs

 

 

 참조 :    http://www.egovframe.go.kr/wiki/doku.php?id=egovframework:rte2:fdl:server_security:architecture

                 http://www.egovframe.go.kr/wiki/doku.php?id=egovframework:rte3:fdl:server_security:authentication

                 http://pentode.tistory.com/144

 

 

 

 

 

 

'SPRING' 카테고리의 다른 글

스프링 파일 업로드 추가사항  (0) 2018.03.27
스프링 파일 업로드/다운로드  (1) 2018.03.27
스프링에서 한글 인코딩  (0) 2018.03.26

+ Recent posts