Programing

응용 프로그램을 배포 할 때“무제한 강도”JCE 정책 파일 설치를 피하는 방법은 무엇입니까?

crosscheck 2020. 5. 27. 21:42
반응형

응용 프로그램을 배포 할 때“무제한 강도”JCE 정책 파일 설치를 피하는 방법은 무엇입니까?


Java에서 즉시 지원하지 않는 256 비트 AES 암호화를 사용하는 앱이 있습니다. 이 기능이 올바르게 작동하려면 보안 폴더에 JCE 무제한 강도 항아리를 설치합니다. 이것은 개발자 인 것이 좋습니다. 설치할 수 있습니다.

내 질문은이 앱이 배포되기 때문에 최종 사용자는 이러한 정책 파일을 설치하지 않았을 가능성이 높습니다. 최종 사용자가이 기능을 다운로드하여 앱 기능을 만드는 것은 매력적인 해결책이 아닙니다.

최종 사용자 컴퓨터에서 파일을 덮어 쓰지 않고 앱을 실행하는 방법이 있습니까? 정책 파일을 설치하지 않고 처리 할 수있는 타사 소프트웨어? 또는 JAR 내에서 이러한 정책 파일을 참조하는 방법은 무엇입니까?


이 문제에 대해 일반적으로 인용되는 몇 가지 해결책이 있습니다. 불행히도 이들 중 어느 것도 완전히 만족스럽지 않습니다.

  • 무제한 강도 정책 파일을 설치하십시오 . 이것은 아마도 개발 워크 스테이션에 적합한 솔루션이지만 기술이 아닌 사용자가 모든 컴퓨터에 파일을 설치하게하는 것은 큰 번거 로움 (로드 블록이 아닌 경우)이됩니다. 프로그램과 함께 파일을 배포 할 방법없습니다 . JRE 디렉토리에 설치해야합니다 (권한으로 인해 읽기 전용 일 수도 있음).
  • JCE API를 건너 뛰고 Bouncy Castle 과 같은 다른 암호화 라이브러리를 사용하십시오 . 이 방법에는 추가 1MB 라이브러리가 필요하며 이는 응용 프로그램에 따라 상당한 부담이 될 수 있습니다. 또한 표준 라이브러리에 포함 된 기능을 복제하는 것은 바보 같은 느낌입니다. 분명히 API는 일반적인 JCE 인터페이스와 완전히 다릅니다. BC는 JCE 공급자를 구현하지만 구현에 전달 하기 전에 주요 강도 제한이 적용되므로 도움이되지 않습니다 . 표준 TLS 라이브러리는 JCE를 내부적으로 호출하여 제한 사항을 판별합니다.

그러나 반성이 있습니다. 반사를 사용하여 할 수없는 것이 있습니까?

private static void removeCryptographyRestrictions() {
    if (!isRestrictedCryptography()) {
        logger.fine("Cryptography restrictions removal not needed");
        return;
    }
    try {
        /*
         * Do the following, but with reflection to bypass access checks:
         *
         * JceSecurity.isRestricted = false;
         * JceSecurity.defaultPolicy.perms.clear();
         * JceSecurity.defaultPolicy.add(CryptoAllPermission.INSTANCE);
         */
        final Class<?> jceSecurity = Class.forName("javax.crypto.JceSecurity");
        final Class<?> cryptoPermissions = Class.forName("javax.crypto.CryptoPermissions");
        final Class<?> cryptoAllPermission = Class.forName("javax.crypto.CryptoAllPermission");

        final Field isRestrictedField = jceSecurity.getDeclaredField("isRestricted");
        isRestrictedField.setAccessible(true);
        final Field modifiersField = Field.class.getDeclaredField("modifiers");
        modifiersField.setAccessible(true);
        modifiersField.setInt(isRestrictedField, isRestrictedField.getModifiers() & ~Modifier.FINAL);
        isRestrictedField.set(null, false);

        final Field defaultPolicyField = jceSecurity.getDeclaredField("defaultPolicy");
        defaultPolicyField.setAccessible(true);
        final PermissionCollection defaultPolicy = (PermissionCollection) defaultPolicyField.get(null);

        final Field perms = cryptoPermissions.getDeclaredField("perms");
        perms.setAccessible(true);
        ((Map<?, ?>) perms.get(defaultPolicy)).clear();

        final Field instance = cryptoAllPermission.getDeclaredField("INSTANCE");
        instance.setAccessible(true);
        defaultPolicy.add((Permission) instance.get(null));

        logger.fine("Successfully removed cryptography restrictions");
    } catch (final Exception e) {
        logger.log(Level.WARNING, "Failed to remove cryptography restrictions", e);
    }
}

private static boolean isRestrictedCryptography() {
    // This matches Oracle Java 7 and 8, but not Java 9 or OpenJDK.
    final String name = System.getProperty("java.runtime.name");
    final String ver = System.getProperty("java.version");
    return name != null && name.equals("Java(TM) SE Runtime Environment")
            && ver != null && (ver.startsWith("1.7") || ver.startsWith("1.8"));
}

removeCryptographyRestrictions()암호화 작업을 수행하기 전에 정적 이니셜 라이저 등에서 호출하면 됩니다.

JceSecurity.isRestricted = false부분은 직접 256 비트 암호를 사용하는 데 필요한 모든 것입니다; 그러나 다른 두 가지 작업이 없으면 Cipher.getMaxAllowedKeyLength()계속 128을보고하며 256 비트 TLS 암호 제품군은 작동하지 않습니다.

이 코드는 Oracle Java 7 및 8에서 작동하며 필요하지 않은 Java 9 및 OpenJDK의 프로세스를 자동으로 건너 뜁니다. 결국 추악한 해킹이기 때문에 다른 공급 업체의 VM에서는 작동하지 않을 수 있습니다.

개인 JCE 클래스가 난독 처리되어 있기 때문에 Oracle Java 6에서도 작동하지 않습니다. 난독 화는 버전마다 바뀌지 않으므로 기술적으로 Java 6을 지원하는 것이 가능합니다.


이제는 더 이상 Java 9 또는 Java 6, 7, 8의 최신 릴리스에는 필요하지 않습니다 . :)

JDK-8170157 , 무제한 암호 정책은 기본적으로 활성화되어 있습니다.

JIRA 문제의 특정 버전 :

  • Java 9 (10, 11 등) : 공식 릴리스!
  • Java 8u161 이상 ( 현재 사용 가능 )
  • Java 7u171 이상 ( 'My Oracle Support'를 통해서만 사용 가능)
  • Java 6u181 이상 ( 'My Oracle Support'를 통해서만 사용 가능)

이상한 이유로 Java 9에서 이전 동작이 필요한 경우 다음을 사용하여 설정할 수 있습니다.

Security.setProperty("crypto.policy", "limited");

해결책은 다음과 같습니다. http://middlesphere-1.blogspot.ru/2014/06/this-code-allows-to-break-limit-if.html

//this code allows to break limit if client jdk/jre has no unlimited policy files for JCE.
//it should be run once. So this static section is always execute during the class loading process.
//this code is useful when working with Bouncycastle library.
static {
    try {
        Field field = Class.forName("javax.crypto.JceSecurity").getDeclaredField("isRestricted");
        field.setAccessible(true);
        field.set(null, java.lang.Boolean.FALSE);
    } catch (Exception ex) {
    }
}

탄력 성은 여전히 ​​알 수있는 한 항아리를 설치해야합니다.

나는 약간의 테스트를했고 이것을 확인하는 것처럼 보였다.

http://www.bouncycastle.org/wiki/display/JA1/Frequently+Asked+Questions


JDK 8u102부터는 리플렉션에 의존하는 게시 된 솔루션이 더 이상 작동하지 않습니다.이 솔루션 세트가 현재 설정된 필드 final( https://bugs.openjdk.java.net/browse/JDK-8149417 ).

(a) Bouncy Castle을 사용하거나 (b) JCE 정책 파일을 설치 한 것으로 보입니다.


대체 암호화 라이브러리에 대해서는 Bouncy Castle을 살펴보십시오 . AES와 많은 추가 기능이 있습니다. 자유주의적인 오픈 소스 라이브러리입니다. 그래도 작동하려면 가볍고 독점적 인 Bouncy Castle API를 사용해야합니다.


당신은 방법을 사용할 수 있습니다

javax.crypto.Cipher.getMaxAllowedKeyLength(String transformation)

to test the available key length, use that and inform the user about what is going on. Something stating that your application is falling back to 128 bit keys due to the policy files not being installed, for example. Security conscious users will install the policy files, others will continue using weaker keys.


For our application, we had a client server architecture and we only allowed decrypting/encrypting data in the server level. Hence the JCE files are only needed there.

We had another problem where we needed to update a security jar on the client machines, through JNLP, it overwrites the libraries in${java.home}/lib/security/ and the JVM on first run.

That made it work.


Here's a updated version of ntoskrnl answer. It additionally contains a function to remove the final modifier like Arjan mentioned in the comments.

This version works with JRE 8u111 or newer.

private static void removeCryptographyRestrictions() {
    if (!isRestrictedCryptography()) {
        return;
    }
    try {
        /*
         * Do the following, but with reflection to bypass access checks:
         * 
         * JceSecurity.isRestricted = false; JceSecurity.defaultPolicy.perms.clear();
         * JceSecurity.defaultPolicy.add(CryptoAllPermission.INSTANCE);
         */
        final Class<?> jceSecurity = Class.forName("javax.crypto.JceSecurity");
        final Class<?> cryptoPermissions = Class.forName("javax.crypto.CryptoPermissions");
        final Class<?> cryptoAllPermission = Class.forName("javax.crypto.CryptoAllPermission");

        Field isRestrictedField = jceSecurity.getDeclaredField("isRestricted");
        isRestrictedField.setAccessible(true);
        setFinalStatic(isRestrictedField, true);
        isRestrictedField.set(null, false);

        final Field defaultPolicyField = jceSecurity.getDeclaredField("defaultPolicy");
        defaultPolicyField.setAccessible(true);
        final PermissionCollection defaultPolicy = (PermissionCollection) defaultPolicyField.get(null);

        final Field perms = cryptoPermissions.getDeclaredField("perms");
        perms.setAccessible(true);
        ((Map<?, ?>) perms.get(defaultPolicy)).clear();

        final Field instance = cryptoAllPermission.getDeclaredField("INSTANCE");
        instance.setAccessible(true);
        defaultPolicy.add((Permission) instance.get(null));
    }
    catch (final Exception e) {
        e.printStackTrace();
    }
}

static void setFinalStatic(Field field, Object newValue) throws Exception {
      field.setAccessible(true);

      Field modifiersField = Field.class.getDeclaredField("modifiers");
      modifiersField.setAccessible(true);
      modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);

      field.set(null, newValue);
   }

private static boolean isRestrictedCryptography() {
    // This simply matches the Oracle JRE, but not OpenJDK.
    return "Java(TM) SE Runtime Environment".equals(System.getProperty("java.runtime.name"));
}

Here is a modified version of @ntoskrnl's code featuring isRestrictedCryptography check by actual Cipher.getMaxAllowedKeyLength, slf4j logging and support of singleton initialization from application bootstrap like this:

static {
    UnlimitedKeyStrengthJurisdictionPolicy.ensure();
}

This code would correctly stop mangling with reflection when unlimited policy becomes available by default in Java 8u162 as @cranphin's answer predicts.


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Cipher;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.security.NoSuchAlgorithmException;
import java.security.Permission;
import java.security.PermissionCollection;
import java.util.Map;

// https://stackoverflow.com/questions/1179672/how-to-avoid-installing-unlimited-strength-jce-policy-files-when-deploying-an
public class UnlimitedKeyStrengthJurisdictionPolicy {

    private static final Logger log = LoggerFactory.getLogger(UnlimitedKeyStrengthJurisdictionPolicy.class);

    private static boolean isRestrictedCryptography() throws NoSuchAlgorithmException {
        return Cipher.getMaxAllowedKeyLength("AES/ECB/NoPadding") <= 128;
    }

    private static void removeCryptographyRestrictions() {
        try {
            if (!isRestrictedCryptography()) {
                log.debug("Cryptography restrictions removal not needed");
                return;
            }
            /*
             * Do the following, but with reflection to bypass access checks:
             *
             * JceSecurity.isRestricted = false;
             * JceSecurity.defaultPolicy.perms.clear();
             * JceSecurity.defaultPolicy.add(CryptoAllPermission.INSTANCE);
             */
            Class<?> jceSecurity = Class.forName("javax.crypto.JceSecurity");
            Class<?> cryptoPermissions = Class.forName("javax.crypto.CryptoPermissions");
            Class<?> cryptoAllPermission = Class.forName("javax.crypto.CryptoAllPermission");

            Field isRestrictedField = jceSecurity.getDeclaredField("isRestricted");
            isRestrictedField.setAccessible(true);
            Field modifiersField = Field.class.getDeclaredField("modifiers");
            modifiersField.setAccessible(true);
            modifiersField.setInt(isRestrictedField, isRestrictedField.getModifiers() & ~Modifier.FINAL);
            isRestrictedField.set(null, false);

            Field defaultPolicyField = jceSecurity.getDeclaredField("defaultPolicy");
            defaultPolicyField.setAccessible(true);
            PermissionCollection defaultPolicy = (PermissionCollection) defaultPolicyField.get(null);

            Field perms = cryptoPermissions.getDeclaredField("perms");
            perms.setAccessible(true);
            ((Map<?, ?>) perms.get(defaultPolicy)).clear();

            Field instance = cryptoAllPermission.getDeclaredField("INSTANCE");
            instance.setAccessible(true);
            defaultPolicy.add((Permission) instance.get(null));

            log.info("Successfully removed cryptography restrictions");
        } catch (Exception e) {
            log.warn("Failed to remove cryptography restrictions", e);
        }
    }

    static {
        removeCryptographyRestrictions();
    }

    public static void ensure() {
        // just force loading of this class
    }
}

During installation of your program, just prompt the user and have a DOS Batch script or a Bash shell script download and copy the JCE into the proper system location.

I used to have to do this for a server webservice and instead of a formal installer, I just provided scripts to setup the app before the user could run it. You can make the app un-runnable until they run the setup script. You could also make the app complain that the JCE is missing and then ask to download and restart the app?

참고URL : https://stackoverflow.com/questions/1179672/how-to-avoid-installing-unlimited-strength-jce-policy-files-when-deploying-an

반응형