एप्लिकेशन को लागू करते समय "असीमित शक्ति" जेसीई नीति फ़ाइलों को स्थापित करने से कैसे बचें?


169

मेरे पास एक ऐप है जो 256-बिट एईएस एन्क्रिप्शन का उपयोग करता है जो कि जावा आउट ऑफ द बॉक्स द्वारा समर्थित नहीं है। मैं इसे सही ढंग से कार्य करने के लिए जानता हूं मैं सुरक्षा फ़ोल्डर में जेसीई असीमित शक्ति जार स्थापित करता हूं। यह मेरे लिए डेवलपर होने के लिए ठीक है, मैं उन्हें स्थापित कर सकता हूं।

मेरा प्रश्न यह है कि इस ऐप को वितरित किया जाएगा, अंत उपयोगकर्ताओं को सबसे अधिक संभावना है कि इन पॉलिसी फ़ाइलों को स्थापित नहीं किया जाएगा। एंड यूज़र को डाउनलोड करने के लिए ये सिर्फ ऐप फंक्शन बनाने के लिए एक आकर्षक समाधान नहीं है।

क्या अंत उपयोगकर्ता मशीन पर फ़ाइलों को अधिलेखित किए बिना मेरे ऐप को चलाने का एक तरीका है? एक थर्ड पार्टी सॉफ्टवेयर जो बिना इंस्टॉल किए हुए पॉलिसी फाइलों को संभाल सकता है? या JAR के भीतर से केवल इन नीति फ़ाइलों को संदर्भित करने का एक तरीका?




11
मुझे संदेह है कि सन / ओरेकल का इरादा था कि ग्राहक कम-सुरक्षित सिफर का उपयोग करेगा ताकि एनएसए कनेक्शन पर स्नूप कर सके। मैं मजाक नहीं कर रहा हूं या पागल नहीं हूं, लेकिन क्रिप्टोग्राफी को एक हथियार के रूप में माना जाता है और एन्क्रिप्शन साझा करने पर निर्यात प्रतिबंध हैं ।
स्लेज

जवाबों:


175

इस समस्या के लिए आमतौर पर उद्धृत समाधान के एक जोड़े हैं। दुर्भाग्य से इनमें से कोई भी पूरी तरह से संतोषजनक नहीं हैं:

  • असीमित ताकत नीति फ़ाइलों को स्थापित करें । हालांकि यह संभवतः आपके विकास कार्य केंद्र के लिए सही समाधान है, यह जल्दी से एक बड़ी परेशानी बन जाती है (यदि कोई अवरोध नहीं है) गैर-तकनीकी उपयोगकर्ताओं को हर कंप्यूटर पर फ़ाइलों को स्थापित करने के लिए। आपके प्रोग्राम के साथ फ़ाइलों को वितरित करने का कोई तरीका नहीं है ; उन्हें JRE निर्देशिका में स्थापित किया जाना चाहिए (जो कि केवल अनुमतियों के कारण भी पढ़ा जा सकता है)।
  • जेसीई एपीआई को छोड़ें और एक अन्य क्रिप्टोग्राफी लाइब्रेरी जैसे बाउंसी कैसल का उपयोग करें । इस दृष्टिकोण के लिए अतिरिक्त 1MB पुस्तकालय की आवश्यकता होती है, जो कि आवेदन के आधार पर एक महत्वपूर्ण बोझ हो सकता है। यह मानक पुस्तकालयों में शामिल कार्यक्षमता की नकल करने के लिए मूर्खतापूर्ण लगता है। जाहिर है, एपीआई भी सामान्य जेसीई इंटरफेस से पूरी तरह से अलग है। (बीसी एक जेसीई प्रदाता को लागू करता है, लेकिन इससे मदद नहीं मिलती है क्योंकि कार्यान्वयन को सौंपने से पहले प्रमुख ताकत प्रतिबंध लागू होते हैं ।) यह समाधान आपको 256-बिट टीएलएस (एसएसएल) सिफर सुइट्स का उपयोग करने की अनुमति नहीं देगा, क्योंकि मानक टीएलएस पुस्तकालय किसी भी प्रतिबंध को निर्धारित करने के लिए आंतरिक रूप से जेसीई को बुलाते हैं।

लेकिन फिर प्रतिबिंब है। वहाँ कुछ भी आप प्रतिबिंब का उपयोग नहीं कर सकते है?

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-बिट टीएलएस सिफर सूट काम नहीं करेंगे।

यह कोड ओरेकल जावा 7 और 8 पर काम करता है, और स्वचालित रूप से जावा 9 और ओपनजेडके पर प्रक्रिया को रोक देता है जहां इसकी आवश्यकता नहीं है। आखिरकार एक बदसूरत हैक होने के नाते, यह अन्य विक्रेताओं के वीएम पर काम नहीं करता है।

यह ओरेकल जावा 6 पर भी काम नहीं करता है, क्योंकि निजी जेसीई कक्षाएं वहां बाधित होती हैं। हालाँकि, संस्करण से संस्करण में आपस में परिवर्तन नहीं होता है, इसलिए जावा 6 का समर्थन करना अभी भी तकनीकी रूप से संभव है।


23
प्रतिबिंब समाधान जावा लाइसेंस समझौते का उल्लंघन कर सकता है : "एफ। जेएवीए प्रौद्योगिकी निष्कर्ष। आप नहीं हो सकता ... व्यवहार को बदल दें ... कक्षाएं, इंटरफेस, या उप-पैकेज जो किसी भी तरह से 'जावा', 'जमैक्स' के रूप में पहचाने जाते हैं। , 'सूरज', 'ओरेकल' या इसी तरह का सम्मेलन ... "
एम। डुडले

14
@ M.Dudley हो सकता है। किसी उत्पाद की शिपिंग करने से पहले एक वकील के साथ जाँच करें जिसमें कोड का यह टुकड़ा है अगर यह आपको चिंतित करता है।
ntoskrnl

3
@peabody अपने कार्यक्रम के साथ 100MB JRE को शामिल करना निश्चित रूप से कुछ मामलों में एक विकल्प है। लेकिन यदि नहीं, तो उपयोगकर्ताओं को अभी भी नीति फ़ाइलों को मैन्युअल रूप से स्थापित करना होगा, भले ही आप उन्हें अपने कार्यक्रम के साथ शामिल करें (क्योंकि विभिन्न कारणों जैसे अनुमतियाँ)। मेरे अनुभव में, कई उपयोगकर्ता इसके लिए सक्षम नहीं हैं।
ntoskrnl

8
ऐसा लगता है कि प्रतिबिंब समाधान बस 1.8.0_112 में काम करना बंद कर दिया। यह 1.8.0_111 में काम करता है, लेकिन 112 में नहीं।
जॉन एल

3
@ जॉन मैं एक एप्लिकेशन में इसका उपयोग करता हूं। final8u111 में क्षेत्र के साथ मुसीबत में चलने के बाद , मैंने इसे संशोधित किया ताकि यह इस उत्तर के बाद अंतिम क्षेत्र को बदल सके । परिणाम ntoskrnl के नए संस्करण के समान है, सिवाय इसके कि मैंने घोषित नहीं modifiersFieldकिया final। मेरे उपयोगकर्ताओं में से एक रिपोर्ट करता है कि यह 8u112 में भी काम करता है।
अर्जन

87

यह अब जावा 9 के लिए आवश्यक नहीं है , और न ही जावा 6, 7 या 8 के किसी भी हालिया रिलीज के लिए। :)

प्रति JDK-8170157 , असीमित क्रिप्टोग्राफिक नीति अब डिफ़ॉल्ट रूप से सक्षम है।

JIRA मुद्दे से विशिष्ट संस्करण:

  • जावा 9 (10, 11, आदि ..): कोई आधिकारिक रिलीज!
  • जावा 8u161 या बाद में ( अब उपलब्ध )
  • जावा 7u171 या बाद में (केवल 'माई ओरेकल सपोर्ट' के माध्यम से उपलब्ध)
  • जावा 6u181 या बाद में (केवल 'माई ओरेकल सपोर्ट' के माध्यम से उपलब्ध)

ध्यान दें कि यदि किसी अजीब कारण से जावा 9 में पुराने व्यवहार की आवश्यकता है, तो इसका उपयोग करके सेट किया जा सकता है:

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

4
वास्तव में, यह नीति डिफ़ॉल्ट है, इसलिए जावा 9 में कोई कार्रवाई आवश्यक नहीं है!
ntoskrnl

2018/01/14 के अनुसार (नवीनतम Oracle JDK 8u151 / 152 है) यह अभी भी जावा 8 पर डिफ़ॉल्ट रूप से सक्षम नहीं है, अच्छी तरह से इस उत्तर के लिखे जाने के एक साल बाद ... हालांकि java.com/en/jre के अनुसार -jdk-cryptoroadmap.html यह 2018/01/16 को जीए करने का इरादा है
एलेक्स

मेरे मामले में, और मेरे लिए इस साइट में एक मार्क प्राप्त करने के लिए: ssllabs.com/ssltest ... मुझे इसे इस तरह सेट करना होगा: Security.setProperty ("crypto.policy", "Unlimited"); तब ... मेरे ऐप्लिकेशन में server.ssl.ciphers सेट
Artanis Zeratul

OpenJDK 8-कॉलम के लिए भी प्रासंगिक है। देखें: stackoverlow-Article: क्या JCE नीति को Openjdk 8 के साथ बंडल किया गया है?
leole

22

यहाँ समाधान है: 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) {
    }
}

यह "डिफ़ॉल्टपॉलिसी" भाग को छोड़कर, मेरा जैसा ही समाधान है। मेरे उत्तर के बाद ब्लॉग पोस्ट दिनांकित है।
ntoskrnl

1
लेकिन क्या यह सही बात है? क्या वास्तविक समय में यह कोड आवेदन सुरक्षा को चुनौती दे सकता है? मुझे यकीन नहीं है कि कृपया मुझे यह समझने में मदद करें कि यह प्रभाव है।
डिश

1
इसे चलाने के बाद मुझे यह त्रुटि मिलती है:java.security.InvalidKeyException: Wrong algorithm: AES or Rijndael required
एंडी

3
जावा 8 बिल्ड 111 के रूप में, यह समाधान अपर्याप्त होगा, क्योंकि isRestrictedक्षेत्र अंतिम हो गया है ( बगसोपेनज्डक.जवा.नेट.ब्रोवस / जेडीके- 8149417 )। @ ntoskrnl का जवाब "अंतिम" संशोधक के किसी भी संभावित समावेश का ख्याल रखता है। @ एम। डुडले की जावा लाइसेंस समझौते पर टिप्पणी अभी भी लागू होती है।
MPelletier


13

JDK 8u102 के अनुसार, परावर्तन पर निर्भर पोस्ट किए गए समाधान अब काम नहीं करेंगे: इन समाधानों को सेट करने का क्षेत्र अब final( https://bugs.openjdk.java.net/browse/JDK-8149417 ) है।

ऐसा लगता है कि बाउंसी कैसल का उपयोग कर (ए) या तो वापस आ गया है, या (बी) जेसीई नीति फ़ाइलों को स्थापित कर रहा है।


7
तुम हमेशा अधिक प्रतिबिंब stackoverflow.com/questions/3301635/…
यूनिवर्सल बिजली

हां, @ M.Dudley का समाधान अभी भी isRestrictedक्षेत्र के लिए काम करेगा , क्योंकि यह एक "अंतिम" संशोधक के संभावित जोड़ का ख्याल रखता है।
MPelletier

1
नई रिलीज JDK 8u151 में "क्रिप्टो नीति को नियंत्रित करने के लिए नई सुरक्षा संपत्ति" है। नीचे पंक्ति: "lib \ Security \ java.security" में "#" लाइन से "# crypto.policy = असीमित"
हटाएं

8

एक वैकल्पिक क्रिप्टोग्राफी लाइब्रेरी के लिए, बाउंसी कैसल पर एक नज़र डालें । इसमें एईएस और बहुत अधिक कार्यक्षमता है। यह एक उदार खुला स्रोत पुस्तकालय है। हालांकि इसके लिए आपको हल्के, मालिकाना बाउंसी कैसल एपीआई का उपयोग करना होगा।


19
वे एक महान क्रिप्टो प्रदाता हैं, लेकिन फिर भी बड़ी कुंजी के साथ काम करने के लिए असीमित ताकत जेसीई फ़ाइल की आवश्यकता होती है।
जॉन मेघेर 12

16
यदि आप सीधे बाउंसी कैसल एपीआई का उपयोग करते हैं तो आपको असीमित शक्ति फ़ाइलों की आवश्यकता नहीं है।
laz

4

आप विधि का उपयोग कर सकते हैं

javax.crypto.Cipher.getMaxAllowedKeyLength(String transformation)

उपलब्ध कुंजी की लंबाई का परीक्षण करने के लिए, इसका उपयोग करें और उपयोगकर्ता को इस बारे में सूचित करें कि क्या चल रहा है। उदाहरण के लिए, नीति फ़ाइलों को स्थापित नहीं किए जाने के कारण आपका एप्लिकेशन 128 बिट कुंजियों पर वापस गिर रहा है। सुरक्षा के प्रति जागरूक उपयोगकर्ता नीति फ़ाइलों को स्थापित करेंगे, अन्य कमजोर कुंजियों का उपयोग करना जारी रखेंगे।


3

हमारे आवेदन के लिए, हमारे पास एक क्लाइंट सर्वर आर्किटेक्चर था और हमने केवल सर्वर स्तर में डेटा को डीक्रिप्ट / एन्क्रिप्ट करने की अनुमति दी थी। इसलिए जेसीई फाइलों की जरूरत है।

हमारे पास एक और समस्या थी जहां हमें JNLP के माध्यम से क्लाइंट मशीनों पर एक सुरक्षा जार को अपडेट करने की आवश्यकता थी, यह ${java.home}/lib/security/पहले रन में पुस्तकालयों और JVM को ओवरराइट करता है ।

इससे काम बन गया।


2

यहाँ ntoskrnl उत्तर का एक अद्यतन संस्करण है । इसमें अतिरिक्त रूप से टिप्पणियों में उल्लिखित अर्जन जैसे अंतिम संशोधन को हटाने का एक कार्य शामिल है ।

यह संस्करण JRE 8u111 या नए के साथ काम करता है।

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

यह अच्छी तरह से काम करता है, लेकिन लाइन ((Map<?, ?>) perms.get(defaultPolicy)).clear();एक संकलक त्रुटि पैदा करता है। बाहर टिप्पणी करने से इसकी कार्यक्षमता प्रभावित नहीं होती है। क्या यह लाइन आवश्यक है?
एंड्रियास अन्वेतवेगर

2

यहाँ @ ntoskrnl के कोड का एक संशोधित संस्करण है , isRestrictedCryptographyजो वास्तविकCipher.getMaxAllowedKeyLength , slf4j लॉगिंग द्वारा चेक की विशेषता है और इस तरह के एप्लीकेशन बूटस्ट्रैप से सिंगलटन इनिशियलाइज़ेशन का समर्थन करता है:

static {
    UnlimitedKeyStrengthJurisdictionPolicy.ensure();
}

यह कोड सही ढंग से प्रतिबिंब के साथ छेड़छाड़ करना बंद कर देगा, जब जावा 8u162 में @ क्रैनफिन के उत्तर की भविष्यवाणी के रूप में असीमित नीति डिफ़ॉल्ट रूप से उपलब्ध हो जाती है।


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

अपने प्रोग्राम की स्थापना के दौरान, केवल उपयोगकर्ता को संकेत दें और डॉस बैच स्क्रिप्ट या बैश शेल स्क्रिप्ट डाउनलोड करें और जेसीई को उचित सिस्टम स्थान में कॉपी करें।

मुझे सर्वर webservice के लिए ऐसा करना पड़ता था और एक औपचारिक इंस्टॉलर के बजाय, मैंने उपयोगकर्ता को चलाने से पहले एप्लिकेशन को सेटअप करने के लिए स्क्रिप्ट प्रदान की। जब तक वे सेटअप स्क्रिप्ट नहीं चलाते आप ऐप को अन-रनेबल बना सकते हैं। आप यह भी शिकायत कर सकते हैं कि जेसीई गायब है और फिर ऐप डाउनलोड करने और फिर से शुरू करने के लिए कहें?


7
"मेरे ऐप को अंत उपयोगकर्ता मशीन पर फ़ाइलों को अधिलेखित किए बिना चलाएं "
इरिकसन 5'09

मैंने अपने उत्तर का पूर्ण संपादन किया क्योंकि मेरा प्रारंभिक उत्तर गलत था।
djangofan
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.