Bir uygulamayı dağıtırken “Sınırsız Güç” JCE ilke dosyalarını yüklemekten nasıl kaçınılır?


169

Kutusundan çıkan Java tarafından desteklenmeyen 256 bit AES şifrelemesi kullanan bir uygulamam var. Ben doğru çalışması için bunu biliyorum güvenlik klasörüne JCE sınırsız gücü kavanoz yükleyin. Bu geliştirici olduğum için iyi, onları yükleyebilirim.

Benim sorum bu uygulama dağıtılacağı için, son kullanıcılar büyük olasılıkla bu ilke dosyaları yüklü olmayacaktır. Son kullanıcının bunları sadece uygulama işlevini yapmak için indirmesi çekici bir çözüm değildir.

Uygulamamın son kullanıcı makinesindeki dosyaların üzerine yazmadan çalışmasını sağlamanın bir yolu var mı? Politika dosyaları yüklenmeden işleyebilecek üçüncü taraf bir yazılım mı? Veya sadece bir JAR içinden bu ilke dosyalarına başvurmak için bir yol?




11
Sun / Oracle'ın niyetinin, istemcinin NSA'nın bağlantıyı gözetebilmesi için daha az güvenli bir şifre kullanacağından şüpheleniyorum. Şaka yapmıyorum ya da paranoyak değilim, ancak kriptografi bir silah gibi muamele görüyor ve şifrelemeyi paylaşmada ihracat yasakları var .
Kızak

Yanıtlar:


175

Bu soruna genel olarak alıntı yapılan birkaç çözüm var. Ne yazık ki bunların hiçbiri tamamen tatmin edici değil:

  • Sınırsız güç ilkesi dosyalarını yükleyin . Bu muhtemelen geliştirme iş istasyonunuz için doğru çözüm olsa da, teknik olmayan kullanıcıların dosyaları her bilgisayara yüklemesi hızlı bir şekilde büyük bir güçlük haline gelir (birlikte gösterim değilse). Orada hiçbir şekilde sizin programla dosyaları dağıtmak; bunların JRE dizinine yüklenmesi gerekir (bu izinler nedeniyle salt okunur olabilir).
  • JCE API'sini atlayın ve Bouncy Castle gibi başka bir şifreleme kütüphanesi kullanın . Bu yaklaşım, uygulamaya bağlı olarak önemli bir yük olabilecek fazladan 1 MB'lık bir kütüphane gerektirir. Ayrıca standart kitaplıklarda bulunan yinelenen işlevsellik de saçma geliyor. Açıkçası, API aynı zamanda normal JCE arayüzünden tamamen farklıdır. (BC bir JCE sağlayıcısı uygular, ancak uygulamaya geçmeden önce temel güç kısıtlamaları uygulandığından bu yardımcı olmaz .) Bu çözüm ayrıca 256 bit TLS (SSL) şifreleme paketleri kullanmanıza izin vermez. standart TLS kütüphaneleri, JCE'yi dahili olarak çağırır ve herhangi bir kısıtlama belirler.

Ama sonra yansıma var. Yansımayı kullanarak yapamayacağınız bir şey var mı?

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()Herhangi bir şifreleme işlemi gerçekleştirmeden önce statik bir başlatıcıdan veya benzeri bir şeyden çağrı yapmanız yeterlidir .

JceSecurity.isRestricted = falseBölümü doğrudan 256 bit şifrelere kullanmak için gerekli olan tüm olduğu; ancak, diğer iki işlem yapılmadan Cipher.getMaxAllowedKeyLength()128 bildirmeye devam eder ve 256 bit TLS şifre paketleri çalışmaz.

Bu kod Oracle Java 7 ve 8'de çalışır ve Java 9 ve OpenJDK'daki işlemi otomatik olarak atlar. Sonuçta çirkin bir hack olmak, diğer satıcıların sanal makinelerinde çalışmaz.

Özel Java JCE sınıfları burada gizlenmiş olduğu için Oracle Java 6'da da çalışmaz. Gizleme sürümden sürüme değişmez, bu nedenle Java 6'yı desteklemek hala teknik olarak mümkündür.


23
Yansıtma çözümü Java Lisans Anlaşmasını ihlal edebilir : "F. JAVA TEKNOLOJİ KISITLAMALARI. ..." java "," javax "olarak tanımlanan ... sınıflarının, arayüzlerin veya alt paketlerin davranışlarını değiştiremezsiniz. , 'güneş', 'kehanet' ya da benzeri bir sözleşme ... ”
M. Dudley

14
@ M.Dudley Olabilir. Sizi ilgilendiriyorsa bu kod parçasını içeren bir ürünü göndermeden önce bir avukata danışın.
ntoskrnl

3
@peabody Bazı durumlarda programınıza 100MB JRE eklemek kesinlikle bir seçenektir. Ancak değilse, programınıza dahil etseniz bile kullanıcıların ilke dosyalarını elle yüklemeleri gerekir (dosya izinleri gibi çeşitli nedenlerden dolayı). Deneyimlerime göre, birçok kullanıcı bunu yapamaz.
ntoskrnl

8
Yansıma çözümü 1.8.0_112'de çalışmayı durdurmuş gibi görünüyor. 1.8.0_111'de çalışıyor, ancak 112'de değil.
John L

3
@JohnL Bunu bir uygulamada kullanıyorum. final8u111'deki alanla sorun yaşadıktan sonra , bu cevabı izleyerek son alanı değiştirebilmesi için değiştirdim . Sonuç, ntoskrnl'in yeni sürümü ile hemen hemen aynı, ancak modifiersFieldolarak ilan etmedim final. Kullanıcılarımdan biri 8u112'de de çalıştığını bildirdi.
Arjan

87

Artık Java 9 için veya Java 6, 7 veya 8'in son sürümlerinde artık gerekli değildir. :)

Başına JDK-8170157 , sınırsız kriptografik politikası artık varsayılan olarak etkindir.

JIRA sorununun belirli sürümleri:

  • Java 9 (10, 11 vb.): Herhangi bir resmi sürüm!
  • Java 8u161 veya üstü ( Şimdi kullanılabilir )
  • Java 7u171 veya üstü (Yalnızca 'My Oracle Support' aracılığıyla edinilebilir)
  • Java 6u181 veya üzeri (Yalnızca 'My Oracle Support' aracılığıyla edinilebilir)

Bazı garip nedenlerden dolayı Java 9'da eski davranış gerekliyse, aşağıdakiler kullanılarak ayarlanabilir:

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

4
Aslında, bu politika varsayılan değerdir, bu nedenle Java 9'da herhangi bir işlem yapmanız gerekmez!
ntoskrnl

2018/01/14 itibariyle (en son Oracle JDK 8u151 / 152'dir) bu, Java 8'de varsayılan olarak etkin değildir, bu cevabın orijinal olarak yazılmasından bir yıl sonra ... Ancak java.com/en/jre'ye göre -jdk-cryptoroadmap.html Bu 2018/01/16 tarihinde GA'ya yöneliktir
Alex

Benim durumumda ve benim için bu sitede A Mark almak için: ssllabs.com/ssltest ... Ben bu şekilde ayarlamak zorunda: Security.setProperty ("crypto.policy", "sınırsız"); o zaman ... benim uygulamalarımda server.ssl.ciphers ayarlayın. bu makalede belirtilen 256 tabanlı algoritmalara sahip özellikler -> poordh.org/sysadmin.html
Artanis Zeratul

OpenJDK 8-Kurulumları için de geçerlidir. Bakınız: stackoverlow-Makale: JCE politikası openjdk 8 ile birlikte mi geliyor?
leole

22

İşte çözüm: 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) {
    }
}

Bu, "defaultPolicy" kısmı olmadan benimkiyle aynı çözümdür. Blog yazısı cevabımdan sonra tarihli.
ntoskrnl

1
Ama bu yapılacak doğru şey mi? Bu kod gerçek zamanlı olarak uygulama güvenliğini zorlayabilir mi? Emin değilim lütfen bunun etkisini anlamama yardımcı olun.
Yemek

1
Bunu çalıştırdıktan sonra bu hatayı alıyorum:java.security.InvalidKeyException: Wrong algorithm: AES or Rijndael required
Andy

3
Java 8 build 111'den itibaren, isRestrictedalan nihai hale geldikçe bu çözüm yetersiz olacaktır ( bugs.openjdk.java.net/browse/JDK-8149417 ). @ ntoskrnl'in cevabı, olası bir "son" değiştiricinin dahil edilmesi ile ilgilenir. @ M.Dudley'nin Java Lisans Anlaşması hakkındaki yorumu hala geçerlidir.
MPelletier


13

JDK 8u102'den itibaren yansımayı temel alan yayınlanan çözümler artık çalışmaz: bu çözümlerin ayarlandığı alan şu anda final( https://bugs.openjdk.java.net/browse/JDK-8149417 ).

Görünüşe göre ya (a) Bouncy Kalesi kullanarak ya da (b) JCE ilke dosyalarını yüklemek.


7
Her zaman daha fazla yansıma kullanabilirsiniz stackoverflow.com/questions/3301635/…
Universal Electricity

Evet, @ M.Dudley'nin çözümü hala isRestrictedsahada çalışacaktır , çünkü olası bir "son" değiştiricinin eklenmesiyle ilgilenmektedir.
MPelletier

1
Yeni sürüm JDK 8u151, "kripto politikasını kontrol etmek için Yeni Güvenlik özelliğine" sahip. Alt satır: "lib \ security \ java.security" deki "#" satırından "# crypto.policy = unlimited" satırını kaldırın: oracle.com/technetwork/java/javase/8u151-relnotes-3850493.html
hemisphire

8

Alternatif bir şifreleme kütüphanesi için Bouncy Castle'a bir göz atın . AES ve birçok ek işleve sahiptir. Liberal bir açık kaynak kütüphanesi. Bunun çalışması için hafif, tescilli Bouncy Castle API'sini kullanmanız gerekecek.


19
Onlar büyük bir kripto sağlayıcısıdır, ancak yine de büyük anahtarlarla çalışmak için sınırsız güçlü JCE dosyasına ihtiyaç duyarlar.
John Meagher

16
Bouncy Castle API'sini doğrudan kullanıyorsanız, sınırsız güç dosyalarına ihtiyacınız yoktur.
laz

4

Yöntemi kullanabilirsiniz

javax.crypto.Cipher.getMaxAllowedKeyLength(String transformation)

kullanılabilir anahtar uzunluğunu test etmek için kullanın ve kullanıcıyı neler olduğu hakkında bilgilendirin. Örneğin, ilke dosyalarının yüklenmemesi nedeniyle uygulamanızın 128 bit anahtarlara düştüğünü belirten bir şey. Güvenlik bilincine sahip kullanıcılar ilke dosyalarını kuracak, diğerleri daha zayıf anahtarları kullanmaya devam edecektir.


3

Uygulamamız için bir istemci sunucu mimarimiz vardı ve sadece sunucu düzeyinde verilerin şifresini çözmeye / şifrelemeye izin verdik. Bu nedenle JCE dosyaları sadece orada gereklidir.

İstemci makinelerde bir güvenlik kavanozunu güncellememiz gerektiğinde başka bir sorun yaşadık, JNLP aracılığıyla ${java.home}/lib/security/, ilk çalıştırmada kütüphanelerin ve JVM'nin üzerine yazıyor .

Bu işe yaradı.


2

İşte ntoskrnl yanıtının güncellenmiş bir sürümü . Ayrıca yorumlarda bahsedilen Arjan gibi son değiştiriciyi kaldırmak için bir işlev içerir .

Bu sürüm JRE 8u111 veya daha yenisi ile çalışır.

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"));
}

Güzel çalışıyor, ancak çizgi ((Map<?, ?>) perms.get(defaultPolicy)).clear();bir derleyici hatası veriyor. Yorum yapmak işlevselliğini etkilemiyor gibi görünüyor. Bu çizgi gerekli mi?
Andreas Unterweger

2

İşte @ ntoskrnl kod içeren değiştirilmiş bir versiyonu isRestrictedCryptographytarafından kontrol gerçekCipher.getMaxAllowedKeyLength , slf4j kaydı ve bunun gibi uygulama bootstrap gelen tekil başlatma desteği:

static {
    UnlimitedKeyStrengthJurisdictionPolicy.ensure();
}

@ Cranphin'in cevabının öngördüğü gibi Java 8u162'de varsayılan olarak sınırsız politika kullanılabilir olduğunda bu kod yansımayla karışmayı doğru bir şekilde durduracaktır.


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;

// /programming/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
    }
}

-1

Programınızın yüklenmesi sırasında, kullanıcıya sormanız yeterlidir ve bir DOS Toplu İş komut dosyası veya bir Bash kabuk komut dosyası indirip JCE'yi uygun sistem konumuna kopyalayın.

Bunu bir sunucu web hizmeti için yapmak zorunda kaldım ve resmi bir yükleyici yerine, uygulamayı çalıştırmadan önce uygulamayı kurmak için komut dosyaları sağladım. Kurulum komut dosyasını çalıştırana kadar uygulamayı çalıştırılamaz hale getirebilirsiniz. Ayrıca, uygulamanın JCE'nin eksik olduğundan şikayet etmesini ve ardından uygulamayı indirip yeniden başlatmasını isteyebilirsiniz?


7
"Uygulamamı son kullanıcı makinesindeki dosyaların üzerine yazmadan çalıştır "
erickson

İlk cevabım yanlış olduğu için cevabımın tam bir düzenlemesini yaptım.
djangofan
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.