자바 에서 Package Sealing 의 비밀 탐색 여행

간단 한 소개
        JAR (자바 아 카 이브) 의 존재 가 없 었 다 면 자바 가 오늘 처럼 세상 을 크게 만 들 지 는 않 았 을 것 이다.JAR 은 다른 파일 이나 JAR 을 묶 고. jar 를 확장자 로 하 는 파일 이다.Zip 과 같은 형식 으로 압축 하기 때문에 Zip 압축 을 지원 하 는 모든 시스템 환경 에 적 용 됩 니 다.압축 형식 이기 때문에 네트워크 에서 의 전송 이 매우 빠르다.JAR 의 manifest 파일 은 JAR 패키지 에 대해 디지털 서명, 버 전 관리, 패키지 밀봉 (Seal), 프로그램의 실행 입구 설정 등 을 할 수 있 습 니 다. 또한 자바 5 부터 META - INFF 폴 더 에서 색인 파일 인 INDEX. LIST 를 생 성하 여 JAR 파일 의 클래스 로 딩 시간 을 크게 단축 시 킬 수 있 습 니 다.
       이 글 은 주로 JAR 의 Package Sealing 기능 을 살 펴 본다.이 기능 은 자바 1.2 에 도입 되 었 다.Jar 파일 을 만 들 때 전체 Jar 나 그 중 몇 개의 Package 를 밀봉 할 지 여 부 를 지정 할 수 있 습 니 다. Jar 파일 전 체 를 밀봉 하 는 것 이 라면 그 안의 모든 Package 가 밀봉 되 었 음 을 의미 합 니 다.패키지 가 밀봉 되면 자바 가상 머 신 은 밀봉 패키지 의 한 종 류 를 성공 적 으로 불 러 온 후 같은 패키지 이름 을 가 진 모든 종 류 는 같은 Jar 파일 에서 나 와 야 합 니 다. 그렇지 않 으 면 Sealing Violation 안전 이상 을 촉발 합 니 다.긴 말 없 이 다음 과 같은 몇 가지 측면 에서 Package Sealing 의 비밀 여행 을 시작 합 시다.
  • Manifest 의 Package Sealing 설정
  • Java 소스 코드 분석 Sealing Violation 
  • Package Sealing 의 이점
  • 씰 링 위반 사례
  •  
    Manifest 의 Package Sealing 설정
    JAR 파일 이 어떻게 manifest 파일 을 통 해 Jar 파일 의 Package 를 밀봉 하 는 지 먼저 봅 시다.주로 두 가지 밀봉 방식 이 있다.
    Manifest-Version: 1.0
    
    Name: com/tr/algorithm/test/box/
    Sealed: true
    
    Name: com/tr/algorithm/search/
    Sealed: true
    
    Name: com/tr/multiThreads/
    Sealed: true
    
    Name: com/tr/algorithm/BinaryTree/
    Sealed: true

    위의 manifest 파일 중
    몇몇 패키지 에 대해 밀봉 작업 을 했 지만 아래 의 manifest 파일 내용 은 Jar 파일 에 있 습 니 다.
    모든 패 키 지 를 밀봉 합 니 다.
    Manifest-Version: 1.0
    Sealed: true

    Java 소스 코드 분석 Sealing Violation 
    패키지 에 대해 어떻게 밀봉 하 는 지 알 게 된 후 자바 소스 코드 에서 어떻게 Sealing Violation 을 촉발 하 는 지 살 펴 보 자.제 가 사용 하 는 JDK 버 전 은 1.6 입 니 다.
    java version "1.6.0_24"
    Java(TM) SE Runtime Environment (build 1.6.0_24-b50)
    Java HotSpot(TM) Client VM (build 19.1-b02, mixed mode)

    다음은 URLClassLoader 에서 Package Sealing 을 안전하게 검사 하 는 코드 입 니 다. 설명 을 추가 하여 이해 하기 쉽 습 니 다.
    	    String pkgname = name.substring(0, i);
    	    Package pkg = getPackage(pkgname);
    	    Manifest man = res.getManifest();
    		
    	    if (pkg != null) { 
                 /*
                       *           ,  com.seal.util.DateUtil.java,    Package
    	           *    com.seal.util,   ClassLoader  。
                       */		
    		if (pkg.isSealed()) {
    		    /*
    			*        ,  com.seal.util.DateUtil.java,    Package com.seal.util         ,
    			*        URI      Package  ,           Jar    
    			*       。
    			*/
    		    if (!pkg.isSealed(url)) {
    			throw new SecurityException(
    			    "sealing violation: package " + pkgname + " is sealed");
    		    }
    
    		} else { //    Package     ,      。
    			/*
    			*          ,  com.seal.util.DateUtil.java ,    Package com.seal.util       。
    			*     ,       。  ,JVM         Package     。
    			*/
    		    if ((man != null) && isSealed(pkgname, man)) { 
    			throw new SecurityException(
    			    "sealing violation: can't seal package " + pkgname + 
    			    ": already loaded");
    		    }
    		}
    	    } else {
    		/*
    		*             Package   ClassLoader  ,      Package。
    		*  Manifest    ,    Manifest     Package,  ,      Package    。
    		*/
    		if (man != null) {
    		    definePackage(pkgname, man, url);
    		} else {
                        definePackage(pkgname, null, null, null, null, null, null, null);
                    }
    	    }

    전체적으로 말 하면 Sealing 에 대한 안전 이상 을 촉발 하 는 두 가지 상황 이 있다.
  • 현재 불 러 오 려 는 클래스 에 대응 하 는 Package 가 JVM 에 불 러 오고 밀봉 되 었 는 지 확인 합 니 다.불 러 오고 밀봉 되 었 으 나 밀 폐 된 Package 가 현재 불 러 오 는 클래스 와 대응 하 는 Package 가 같은 Jar 파일 에서 온 것 이 아니라면 보안 이상 이 발생 합 니 다
  • 현재 불 러 오 려 는 클래스 에 대응 하 는 Package 가 JVM 에 불 러 오고 밀봉 되 었 는 지 확인 합 니 다.불 러 왔 지만 밀봉 되 지 않 았 다 면 현재 불 러 오 려 는 클래스 에 대응 하 는 Package 가 밀봉 작업 을 시도 하려 면 보안 이상 이 발생 합 니 다.JVM 은 불 러 왔 지만 밀봉 되 지 않 은 Package 를 다시 밀봉 하 는 것 을 허용 하지 않 습 니 다.

  • Package Sealing 의 이점
    Package Sealing 이 가 져 올 수 있 는 장점 은 주로 버 전의 일치 성 입 니 다. 자바 가 실 행 될 때 classpath 에서 정 의 된 순서에 따라 불 러 오고 검사 하 는 것 을 알 고 있 습 니 다. 특히 현재 자바 오픈 소스 패키지 가 가득 합 니 다. 자바 응용 프로그램 이나 미들웨어 의 classpath 에 같은 패키지 의 다른 버 전이 포 함 될 가능성 이 높 습 니 다.이것 은 프로그램 운행 에 일치 하지 않 는 결 과 를 만들어 발견 하기 어렵다.
    Sealing Violation 실례
    다음 두 가지 Sealing Violation 에 대한 예 를 살 펴 보면 쉽게 알 수 있 습 니 다. 
    버 전 업그레이드 예
    첫 번 째 사례 의 큰 배경 은 발 표 된 Jar 가방 을 버 전 업그레이드 하여 사용자 에 게 사용 하 는 것 이다.버 전 1 에는 Dateutil 과 StringUtil 두 가지 가 있 습 니 다.
    package com.seal.util;
    
    public class DateUtil {
    	public void DoDateStuff(){
    		System.out.println("doing date stuffs in version 1.0");
    	}
    }
    package com.seal.util;
    
    public class StringUtil {
    	public void DoStringStuff(){
    		System.out.println("doing string stuffs in version 1.0");
    	}
    }
    

    이 두 가지 종 류 는 우리 가 sealed 로 발표 합 니 다.v1.jar。 이 Jar 파일 은 이미 밀봉 되 었 으 며, Manifest 파일 의 내용 은 다음 과 같다.
    Manifest-Version: 1.0
    Sealed: true

    버 전 2 에 서 는 NumberUtil 과 Dateutil 의 논 리 를 바 꾸 었 습 니 다.버 전 2 에서 발표 한 Jar 파일 은 sealedv2.jar。Manifest 파일 의 내용 은 버 전과 같 습 니 다.자바 클래스 코드 는 다음 과 같 습 니 다.
    package com.seal.util;
    
    public class DateUtil {
    	public void DoDateStuff(){
    		System.out.println("doing date stuffs in version 2.0");
    	}
    }
    
    package com.seal.util;
    
    public class StringUtil {
    	public void DoStringStuff(){
    		System.out.println("doing string stuffs in version 2.0");
    	}
    }
    
    package com.seal.util;
    
    public class NumberUtil {
    	public void DoNumberStuff(){
    		System.out.println("doing number stuffs in version 2.0");
    	}
    }
    

    이때 고객 에 게 사용 가능 한 Jar 버 전 은 sealed 버 전이 있 습 니 다.v1. jar 와 버 전 2 sealedv2.jar。사용자 에 게 다음 과 같은 테스트 클래스 가 있 습 니 다.
    import com.seal.util.DateUtil;
    import com.seal.util.NumberUtil;
    import com.seal.util.StringUtil;
    
    
    public class SealTestCase1 {
      
      public static void main(String[] args){
    	 DateUtil du = new DateUtil();
    	 du.DoDateStuff();
    	 StringUtil su = new StringUtil();
    	 su.DoStringStuff();
    	 
    	 NumberUtil nu = new NumberUtil();
    	 nu.DoNumberStuff();
      }
    }

    우 리 는 자바 명령 을 실행 하여 위의 테스트 클래스 를 컴 파일 하고 실행 합 니 다. 상기 두 Jar 파일 sealed 를 가정 합 니 다.v1. jar 와 sealedv2. jar, 그리고 SealTestCase 1 종 류 는 디 렉 터 리 D: \ sealing Test \ \ case 에 저 장 됩 니 다.1 중.
    다음 명령 을 실행 하여 SealTestCase 1 종 류 를 컴 파일 합 니 다.
    javac -classpath .;D:\sealingTest\case_1\sealed_v1.jar;D:\sealingTest\case_1\sealed_v2.jar SealTestCase1.java
    다음 명령 을 실행 하여 SealTestCase 1 종 류 를 실행 합 니 다.
    java -classpath .;D:\sealingTest\case_1\sealed_v1.jar;D:\sealingTest\case_1\sealed_v2.jar SealTestCase1
    doing date stuffs in version 1.0
    doing string stuffs in version 1.0
    Exception in thread "main" java.lang.SecurityException: sealing violation: package com.seal.util is sealed
            at java.net.URLClassLoader.defineClass(URLClassLoader.java:234)
            at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
            at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
            at java.security.AccessController.doPrivileged(Native Method)
            at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
            at java.lang.ClassLoader.loadClass(ClassLoader.java:305)
            at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
            at java.lang.ClassLoader.loadClass(ClassLoader.java:246)
            at SealTestCase1.main(SealTestCase1.java:14)

    이 Sealing Violation 은 바로 JDK 에서 정의 한 첫 번 째 상황 이다.이 Sealing Violation 이 발생 하 는 근본 적 인 원인 을 이해 하려 면 다음 코드 설명 을 보십시오.
    public class SealTestCase1 {
    
      public static void main(String[] args){
    	 /*
    	  * JVM    com.seal.util.DateUtil ,  Classpath  sealed_v1.jar    ,
    	  *   ,com.seal.util.DateUtil    sealed_v1.jar。    sealed_v1.jar       。
    	  * JVM   Package com.seal.util        。 
    	  */
    	 DateUtil du = new DateUtil();
    	 du.DoDateStuff();
    
             /*
              *   ,sealed_v1.jar classpath  sealed_v2.jar  ,
              *   com.seal.util.StringUtil    sealed_v1.jar     。
              *   Package com.seal.util          ,   com.seal.util.StringUtil 
              *  com.seal.util.DateUtil       Jar  。  ,        。            。
              */
    	 StringUtil su = new StringUtil();
    	 su.DoStringStuff();
    
    	 /*
    	  * JVM     com.seal.util.NumberUtil ,        sealed_v1.jar 
    	  *   ,    sealed_v2.jar,     。
    	  *  JVM       Package com.seal.util         ,    sealed_v1.jar,
    	  *        sealed_v2.jar。  JVM        。
    	  */
    	 NumberUtil nu = new NumberUtil();
    	 nu.DoNumberStuff();
      }
    }
    

    위의 원인 을 알 게 되면 우 리 는 할 수 있다.
    장 sealedv1. jar 와 sealedv2. jar 가 classpath 에서 위 치 를 바 꾼 다음 다시 실행 합 니 다.
    java -classpath .;D:\sealingTest\case_1\sealed_v2.jar;D:\sealingTest\case_1\sealed_v1.jar SealTestCase1
    doing date stuffs in version 2.0
    doing string stuffs in version 2.0
    doing number stuffs in version 2.0

    우 리 는 결과 가 정상적으로 나타 나 는 것 을 보 았 다.우 리 는 Package Sealing 이 버 전의 일치 성 을 보증 하 는 것 을 볼 수 있다.
    제3자 발표 vs 공식 발표
    두 번 째 예 는 어떤 공식 적 으로 밀 폐 된 Jar 파일 을 발 표 했 습 니 다. sealed_official_release.jar。그 종 류 는 아래 와 같다.
    package com.seal.util;
    
    public class DateUtil {
    	public void DoDateStuff(){
    		System.out.println("doing date stuffs officially");
    	}
    }
    
    package com.seal.util;
    
    public class NumberUtil {
    	public void DoNumberStuff(){
    		System.out.println("doing number stuffs officially");
    	}
    }
    
    package com.seal.util;
    
    public class StringUtil {
    	public void DoStringStuff(){
    		System.out.println("doing string stuffs officially");
    	}
    }
    

    그리고 이 공식 적 으로 발 표 된 Jar 파일 은 한 제3자 조직 에 의 해 변경 되 고 발표 되 었 다.Jar 파일 이름 unsealed_3rdparty_release.jar。원래 공식 적 으로 발 표 된 Jar 와 는 또 다른 점 이 있 습 니 다.
    이 Jar 파일 은 밀봉 되 지 않 은 Jar 파일 입 니 다.내용 은 다음 과 같다.
    package com.seal.util;
    
    public class DateUtil {
    	public void DoDateStuff(){
    		System.out.println("doing modified date stuffs by third party");
    	}
    }
    package com.seal.util;
    
    public class StringUtil {
    	public void DoStringStuff(){
    		System.out.println("doing modified string stuffs by third party");
    	}
    }
    

    이 때 사용자 의 손 에는 두 개의 다른 Jar 파일 이 있 을 수 있 으 며, 다음 프로그램 을 실행 해 야 합 니 다.
    import com.seal.util.DateUtil;
    import com.seal.util.NumberUtil;
    import com.seal.util.StringUtil;
    
    
    
    
    public class SealTestCase2 {
    	  public static void main(String[] args){
    			 DateUtil du = new DateUtil();
    			 du.DoDateStuff();
    			 StringUtil su = new StringUtil();
    			 su.DoStringStuff();
    			 
    			 NumberUtil nu = new NumberUtil();
    			 nu.DoNumberStuff();
    		  }
    }

    우 리 는 상술 한 두 개의 Jar 파일 sealed 를 가정 합 니 다.official_release.jar, unsealed_3rdparty_release. jar 와 클래스 SealTestCase 2. java 는 모두 디 렉 터 리 D: \ sealing Test \ \ case 에 있 습 니 다.2 중
    다음 명령 을 실행 합 니 다. 컴 파일 류 SealTestCase 2. java.
    javac -classpath .;D:\sealingTest\case_2\unsealed_3rdparty_release.jar;D:\sealingTest\case_2\sealed_official_release. jar SealTestCase 2. java 는 다음 명령 을 실행 하여 SealTestCase 2. java 를 실행 합 니 다.
    java -classpath .;D:\sealingTest\case_2\unsealed_3rdparty_release.jar;D:\sealingTest\case_2\sealed_official_release.jar SealTestCase2
    doing modified date stuffs by third party
    doing modified string stuffs by third party
    Exception in thread "main" java.lang.SecurityException: sealing violation: can't
     seal package com.seal.util: already loaded
            at java.net.URLClassLoader.defineClass(URLClassLoader.java:242)
            at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
            at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
            at java.security.AccessController.doPrivileged(Native Method)
            at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
            at java.lang.ClassLoader.loadClass(ClassLoader.java:305)
            at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
            at java.lang.ClassLoader.loadClass(ClassLoader.java:246)
            at SealTestCase2.main(SealTestCase2.java:15)

    이 Sealing Violation 은 바로 JDK 에서 정의 한 두 번 째 상황 이다.이 Sealing Violation 이 발생 하 는 근본 적 인 원인 을 이해 하려 면 다음 코드 설명 을 보십시오.
    public class SealTestCase2 {
    	  public static void main(String[] args){
    			 /*
    			  * JVM    com.seal.util.DateUtil ,  Classpath  unsealed_3rdparty_release.jar    ,
    			  *   ,com.seal.util.DateUtil    unsealed_3rdparty_release.jar。
    			  *     unsealed_3rdparty_release.jar       。
    			  * JVM   Package com.seal.util           。 
    			  */
    			 DateUtil du = new DateUtil();
    			 du.DoDateStuff();
    		         /*
    		          *   ,unsealed_3rdparty_release.jar classpath  sealed_official_release.jar  ,
    		          *   com.seal.util.StringUtil    unsealed_3rdparty_release.jar     。
    		          *   Package com.seal.util            ,
    		          *   ,        。            。
    		          */
    		     
    			 StringUtil su = new StringUtil();
    			 su.DoStringStuff();
    			 /*
    			  * JVM     com.seal.util.NumberUtil ,        unsealed_3rdparty_release.jar 
    			  *   ,    sealed_official_release.jar,     。   sealed_official_release.jar
    			  *      。  ,JVM   Package com.seal.util     。
    			  *  JVM  Package com.seal.util      。
    			  *   ,JVM        。
    			  */
    			 NumberUtil nu = new NumberUtil();
    			 nu.DoNumberStuff();	
    		  }
      
    }

    Jar 파일 sealedofficial_release.jar, unsealed_3rdparty_release. jar 의 순 서 는 classpath 에서 위 치 를 바 꾸 고 다음 명령 을 실행 합 니 다.
    java -classpath .;D:\sealingTest\case_2\sealed_official_release.jar;D:\sealingTest\case_2\unsealed_3rdparty_release.jar SealTestCase2
    doing date stuffs officially
    doing string stuffs officially
    doing number stuffs officially

    우 리 는 고객 류 인 SealTestCase 2 가 실행 하 는 모든 종 류 는 공식 적 으로 발 표 된 Jar 파일 에서 나 온 것 을 보 았 다.그래서 버 전의 일치 성 을 확보 했다.

    좋은 웹페이지 즐겨찾기