레이블이 jsp인 게시물을 표시합니다. 모든 게시물 표시
레이블이 jsp인 게시물을 표시합니다. 모든 게시물 표시

2013년 9월 10일 화요일

[Head First]Servlets & JSP 내용정리-13장

Chapter.13

필터와 랩터


필터
  • 전체 웹 애플리케이션 기능을 확장. 예) 보안, 혹은 , 요청에 대한 로그
  • 일반 자바 컴포넌트, 서블릿으로 요청 처리전 , 클라이언트에게 넘겨가기전 응답을 가로채어 처리 할 수 있다.
  • Request 필터로 처리 할만것들
    • 보안 관련 내용을 체크
    • 요청 헤더와 바디 포맷팅을 수정
    • 요청을 감시하거나 기록으로 남김
  • Response 필터로 처리 할만것들
    • 응답스트림을 압축
    • 응답스트림에 내용을 추가하거나 수정함.
    • 완전 다른 새로운 응답을 만듬.
  • 필터 인터페이스는 Filter 하나 임.
  • 모듈식으로 DD에서 설정
  • Servlet와 비슷한 3 가지
    • 컨테이너가 이들 API를 알고 있음.
    • 컨테이너가 생명주기를 관리함.
    • DD에 설정함.
  • 필터는 누가 자신을 불렀는지 자기 다음에 누구인지 모름
  • 필터의 생명주기
    • 제일 먼저 init() : FilterConfig 객체를 저장하는 역할이 주
    • doFiler() 처리할 것이 많음.
    • 마지막으로 destroy() : 필터 삭제전에 할 작업
  • 필터는 컨테이너에 의해서 stack 처럼 처리 된다.
  • DD에서 필터 설정으로 할 수 3가지 내용
    • 필터의 정의
    • 필터링해야 할 리소스와 필터를 맵핑 할수 있음.
    • 순서대로 필터가 호출될 수 있도록 정렬 할 수 있음.


DD에서 필터 설정
필터 정의
<filter>
 <filter-name>BeerRequest</filter-name>
 --------------------------------------
 필수 - 필터 이름
 <filter-class>com.example.web.BeerRequestFilter</filter-class>
 -------------------------------------------------------------
 필수 - 필터 클래스 이름(패키지명 포함)
 <dispatcher>REQUEST | INCLUDE | FORWARD | ERROR </dispatcher>
 -------------------------------------------------------------
 2.4 부터 가능함. (0..4) 포함 가능함.
  • REQUEST : 클라이언트의 요청 (기본값 : 항목이 없는 경우)
  • INCLUDE : include에 적용
  • FORWARD : 클라이언트의 요청을 다른 곳으로 넘길때(forward)
  • ERROR   : error 핸들러를 호출하였을 때
 <init-param>
    <param-name>LogFileName</param-name>
    <param-value>UserLog.txt</param-value>
 </init-param>
 -------------
 선택 - 여러개 존재해도 됨.
</filter>


URL 패턴과 필터 맵핑 선언하기
<filter-mapping>
 <filter-name>BeerRequest</filter-name>
 --------------------------------------
 필수 - filter의 <filter-name>에 존재해야 함.
 <url-pattern>*.do</url-pattern>
 -------------------------------
 필수 - <url-pattern> 혹은 <servlet-name> 중 하나는 존재해야 함.
</filter-mapping>


서블릿 이름에 필터 맵핑 선언하기
<filter-mapping>
 <filter-name>BeerRequest</filter-name>
 <servlet-name>AdviceServlet</servlet-name>
</filter-mapping>



중요 컨테이너가 필터 순서를 정하는 규칙 : 하나의 리소스에 대한 여러 개의 필터가 적용되는 경우
  1. URL 패턴으로 적용되는 필터가 제일 먼저 옴.DD에 정의된 순서대로 체인에 하나씩 들어간 다음 실행됨.
  2. URL 패턴이후에 <servlet-name>으로 정의된 필터를 찾아 정의된 순서대로 체인에 등록함.


버젼 2.4 부터 요청 디스패처로 들어오는 것도 필터에 적용할 수 있음.
forward, include , request , dispatch ,error


압축필터에 대한 의사 코드(응답필터)
class MyCommpressionFilter implement Filter{
 init();
 
 public void doFilter(request, response,chain){
   // 요청에 대한 처리가 들어감.
   chain.doFilter(request,response); //서블릿이 자기 한일을 함.
   // 압축로직이 들어갈 자리
 }
}


새로운 응답 객체를 만들어 하는 이유
  • 클라이언트로 넘어가는 것을 제어 하기 위해서
  • Wrapper 클래스를 사용하는 새로운 Response 객체를 생성한다.


Wrapper Basic
  • 원본 request, response 객체를 내부에 감싸고, 자신에게 들어오는 모든 메소드를 바로 이 객체로 위임하는 식으로 메소드를 구현함.
  • 개발자의 역할은 랩퍼 클래스를 상속하고 필요한 메소드를 재정의 함.
  • 대표적인 랩퍼 클래스들 : AWT의 Event Listener Adapter 클래스들
  • 서블릿에서 제공하는 4개의 랩퍼 클래스
    • ServletRequestWrapper
    • HttpServletRequestWrapper
    • ServletResponseWraper
    • HttpServletResponseWraper
실제 압축 필터 코드
압축 필터 코드 예제)
... 생략 패키지 구문 및 import 구문


public classs CompressionFilter implements Filter{
 private ServletContext ctx;
 private FilterConfig cfg;
 public void init(FilterConfig cfg) throws ServletException{
   this.cfg = cfg;
   ctx = cfg.getServletContext();
   ctx.log(cfg.getFiltername() + “ initialized.”);
 }
 public void doFilter(ServletRequest req,ServletResponse resp,FilterChain fc) throws IOException, ServletException {
   HttpServletRequest request = (HttpServletRequest)req;
   HttpServletResponse response = (HttpServletResponse)resp;


   String valid_encodings = request.getHeader(“Accept-Encoding”);
   if( valid_encodings.indexOf(“gzip”) > -1){
     CompressionResponseWrapper wrappedResp =
        new CompressionResponseWrapper(response);
     -------------------------------------------
     압축 랩퍼 클래스 생성
     wrappedResp.setHeader(“Content-Encoding”,”gzip”);
     -------------------------------------------------
     응답 컨덴츠가 gzip으로 인코딩됨을 선언하는 부분
     fc.doFilter(request,wrappedResp);
     ---------------------------------
     체인에 있는 다음 컴포넌트를 호출합니다.


     GZIPOutputStream gzos = wrappedResp.getGZIPOutputStream();
     gzos.flush();
     -------------
     원본 스트림으로 모든 테이터를 전송합니다.
     ctx.log(cfg.getFilterName() + “: finished the request.”);
   }else{
     ctx.log(cfg.getFilterName() + “: no encoding performed.”);
   }
 }
 public void destroy(){
   // 인스턴스 변수들을 null 처리 한다.
   cfg = null; ctx = null;
 }
}


압축이 HTTP를 만났을 때

  • 브라우저가 보내는 헤더 중 하나인 “Accept-Endcoing:gzip”은 서버에게 이런 컨덴츠를 다룰 수 있다고 할려 주는 것입.
  • 브라우저가 압축 데이터를 처리할 수 있으면 서버는 헤더에 “Content-Encoding:gzip”을 추가해서 컨덴츠가 압축되었음. 알려 주어야 한다.
  • 브라우저를 위 정보를 확인 하고 화면을 출력하면 압축을 풀어야 함을 알게된다.

[Head First]Servlets & JSP 내용정리-12장

Chapter.12

세가지 유형 해커들

  • Impersonator (임퍼스네이터) : 자신을 다른 사람처럼 속이는 녀석
  • Upgrader(업그레이더) : 자신의 등급을 속이는 녀석
  • Eavesdropper(이즈드롭퍼) : 중요한 정보를 몰래 훔쳐보는 녀석  --> 가장 나쁜 형태의 해커


서블릿 보안의 4요소

  • 인증(Authentication)
  • 인가(Authorization)
  • 비밀보장(Confidentiality)
  • 데이터 무결성(Data Integrity)


HTTP 환경에서 인증

  • HTTP 401 (Unauthorized) 응답 보내서 사용자의 암호와 패스워드를 요구 한다.
  • 컨테이너가 보안 테이블을 확인 하여 주어진 ID와 PWD 올바르면 해당 자원을 보내 준다.


인증, 인가에 컨데이너의 하는 일

  • 요청 자원에 대한 검색(lookup) 작업 : 보안 정보에 대해서
  • 인증 작업을 합니다. : 클라이언트에게 인증 정보를 요청
  • 인가 작업을 함 : 사용자가 자원에 대한 권한을 확인 한다.


보안 관련 제약 사항을 선언적으로 관리하는 이유(DD)

  • XML은 사용하기 용이하므로
  • 서블릿을 좀 더 유연하게 작성할 수 있으므로
  • 유지보수가 쉬우므로


서블릿 보안 관련 체크 사항

보안 개념
책임 소재
복잡도
노력 정보
인증
관리자
중간
높음
인가
(대부분) 배포자
높음
높음
비밀 보장
배포자
낮음
낮음
데이터 일관성
배포자
낮음
낮음


tomcat-users.xml 파일
<tomcat-users>
 <role rolename=”Guest”/>
 <role rolename=”Member”/>
 <user name=”Bill” password=”coder” roles=”Member, Guest”/>
 …
</tomcat-users>


인증 활성화 하기 (DD)
<login-config>
 <auth-memthod>BASIC</auth-memthod>
</login-config>


인가 단계
  1. 인가 단계 1 : 역할(role) 정의 하기


<security-role>
<role-name>Admin</role-name>
<role-name>Member</role-name>
<role-name>Guest</role-name>
</security-role>


<login-config>
 <auth-memthod>BASIC</auth-memthod>
</login-config>
------------------------
관련항목 설정


  1. 인가 단계 2 : 자원/메소드 제약 정의 하기


<security-constraint>
 <web-resource-collection>
   <web-resource-name>UpdateRecipes</web-resource-name>
   <description>선택 사항</description>    
   <url-pattern>/Beer/AddRecipe/*</usrl-pattern>
   <url-pattern>/Beer/ReviewRecipe/*</usrl-pattern>
   
   <http-method>GET</http-method>
   <http-method>POST</http-method>
   -------------------------------
   항목으로 정의한 자원에 대한 제약을 걸 HTTP 메소드를 정의 하라
   GET와 POST에 대해서만 제약 유효 하고 그외 메소드에 대한 누구던지
   접근 가능 하다.
   먄악 정의 하지않으면 모든 메소드에 다 제약을 건다는 의미
 </web-resource-collection>


 <auth-constraint>
   <role-name>Admin</role-name>
   <role-name>Member</role-name>
 </auth-constraint>
 ------------------
 정의된 자원에 대해 http-method 수행 할 group
</security-constraint>


웹은 자원 단위의 제약이 아니라 HTTP 요청단위의 제약을 거는 것입니다.


<role-name> 규칙
  • 만약 <auth-contraint>에 <role-name>이 없다면 어떤 사용자도 접근 할 수 없다.
  • <role-name>*</role-name> 모든 사용자가 다 접근 가능하다.
  • <role-name> 대소문자구분


<auth-contraint> 규칙
  • 옵선 항목
  • 항목이 있다는 말은 관련 URL에 대하여 인증 실시하고 컨데이너에게 지시함.
  • 없다면 URL에 대하여 인증 없이도 접근할 수 있다는 것
  • 안에 <description> 가능 함.
  • <auth-contraint/> 와 공태그는 정 반대 입니다.
  • 이 옵션에 의해서 자원에 접근하지 못해도 Request Dispatcher를 통해서 가능하다.


HttpServletRequest에 프로그램적인 보안과 관련된 3개 메소드
  • getUserPrincipal() : EJB에 사용 (관련 무)
  • getRemoteUser() : 인증이 되어는지 안 되었는지 확인하는 메소드. 잘 사용안함.
  • isUserInRole() : 메소드 내에서 인가관리(권한관리)를 함.


isUserInRole() 동작 방식
  • 호출하기 전, 반드시 인증을 거쳐야 함. (인증하지 않으면 false)
  • 컨데이너가 인자로 넘어온 값(“rolename”)과 정의된 사용자 역할과 비교 합니다.
  • 사용자가 해당 역할이라고 한다면, 참(true)를 리턴함.


서블릿 코드
if(request.isUserInRole(“Manager”)){
                       ----------
                      배포서술자에 <security-role-ref>의 <role-name>와 같음.
}


배포 서술자
<web-app...>
<servlet>
  <security-role-ref>
    <role-name>Manager</role-name>
    <role-link>Admin</role-link>
    ----------------------------
    <security-role>의 Admin와 서로 맵핑함.
  </security-role-ref>
  ...
</servlet>
</web-app>
<web-app...>
 <security-role>
   <role-name>Admin</role-name>
   <role-name>Member</role-name>
 </security-role>
</web-app>


** 만약 <security-role-ref>와 <security-role>에 동일한 이름이 있다면 ~-ref 우선임.


4가지 인증 방식
  • BASIC : 암호하지 않은 인코딩한(base64) 형식을 전송 , 약한 인증 방식
  • DIGEST : 안전한 형태 , 암호화 매커니즘을 사용함. J2EE 컨데이너에서 반드시 지원해야 하는 방식 아님.
  • CLIENT-CERT : 공인키 인증(PKC) 사용. 매우 안전한 방식으로 전송 클라이언트 인증서 가져야 함.
    보통 비즈니스 환경에서 사용
  • FORM : 자신만의 로그인 폼을 제공. 4가지 보안 방식중 가장 약함. 암호화되지 않은 채 전송됨.
설정
<web-app..>
 <login-config>
   <auth-method>BASIC | DIGEST | CLIENT-CERT | FORM</auth-method>
 </login-config>
 FORM 일때만
[
 <form-login-config>
   <form-login-page>/loginPage.html</form-login-page>
   <form-error-page>/loginError.html</form-error-page>
 </form-login-config>
]
 …
</web-app>


폼 기반 인증 - 해야 할일
  1. DD에 <login-config> 정의 하기
  2. HTML 로그인 폼 생성
  3. HTML 오류 페이지 생성


HTML 로그인 폼과 컨테이너간 데이터 공유를 위한 3가지 항목 (반드시 아래 이름으로 사용해야 함.)
  • action 명 :  j_security_check
  • user 명 name 속성 : j_username
  • pwd , name 속성 : j_password


인증 방식 정보 표
유형
스펙
데이타 무결성
주석
BASIC
HTTP
Base64 - 약함
HTTP 표준, 모든 브라우저가 지원
DIGEST
HTTP
좀더 강력한 방식 - SSL 만큼은 아님
HTTP ,J2EE 컨테이너에서 옵션 사항임.
FORM
J2EE
가장 약함, 암호화 안됨
사용자 정의 로그인 화면 지원
CLIENT-CERT
J2EE
강력함 - 공인키(PKC)
강력하지만 사용자가 인증서를 가지고 있어야 함.


안전하게 데이터 전송하기 : HTTPS가 답입니다. 실전에서는 대부분 SSL 기반에 HTTPS를 사용함. (전송 계층의 방식)


데이터 기밀성과 데이터 무결성을 분리하여 선언하기
<web-app..>
<security-constraint>
  <web-resource-collection>
    ...
  </web-resource-collection>
  <auth-constraint>
    ...
  </auth-constraint>
  <user-data-constraint>
    <transport-guarantee>CONFIDENTIAL</transport-guarantee>
  </user-data-constraint>   
</security-constraint>
</web-app>


<transport-guarantee>에 들어 갈 수 있는 값.

  • NONE : 디폴트 값. 데이터 보호를 하지 않겠다는 의미
  • INTEGRAL : 전송 중 데이터가 변경되지 않음을 보장한다는 말이죠.
  • CONFIDENTIAL : 전송 중 그 누구도 데이터를 훔쳐보지 않았음을 보장한다는 말이죠 (보장하기 위해서)
    SSL를 사용한다.