केवल "वैध" उपयोगों के लिए सेट करने योग्य कैसे सीमित करें?


100

जितना अधिक मैंने इसकी शक्ति के बारे में सीखा है java.lang.reflect.AccessibleObject.setAccessible, उतना ही चकित हूं कि मैं यह क्या कर सकता हूं। यह मेरे प्रश्न के उत्तर से अनुकूलित है ( स्थैतिक अंतिम File.separatorChar को इकाई परीक्षण के लिए बदलने के लिए प्रतिबिंब का उपयोग करके )।

import java.lang.reflect.*;

public class EverythingIsTrue {
   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);
   }
   public static void main(String args[]) throws Exception {      
      setFinalStatic(Boolean.class.getField("FALSE"), true);

      System.out.format("Everything is %s", false); // "Everything is true"
   }
}

आप वास्तव में अपमानजनक सामान कर सकते हैं:

public class UltimateAnswerToEverything {
   static Integer[] ultimateAnswer() {
      Integer[] ret = new Integer[256];
      java.util.Arrays.fill(ret, 42);
      return ret;
   }   
   public static void main(String args[]) throws Exception {
      EverythingIsTrue.setFinalStatic(
         Class.forName("java.lang.Integer$IntegerCache")
            .getDeclaredField("cache"),
         ultimateAnswer()
      );
      System.out.format("6 * 9 = %d", 6 * 9); // "6 * 9 = 42"
   }
}

संभवत: एपीआई डिजाइनरों को एहसास है कि अपमानजनक कैसे setAccessibleहो सकता है, लेकिन यह माना है कि इसे प्रदान करने के लिए इसके वैध उपयोग हैं। तो मेरे सवाल हैं:

  • वास्तव में वैध उपयोग क्या हैं setAccessible?
    • क्या जावा को इस तरह से डिज़ाइन किया गया है कि पहली जगह में इसकी आवश्यकता नहीं है?
    • इस तरह के डिजाइन के नकारात्मक परिणाम (यदि कोई हो) क्या होगा?
  • क्या आप setAccessibleकेवल वैध उपयोगों तक ही सीमित रह सकते हैं ?
    • के माध्यम से ही है SecurityManager?
      • यह कैसे काम करता है? श्वेतसूची / ब्लैकलिस्ट, ग्रेन्युलैरिटी, आदि?
      • क्या आपके एप्लिकेशन में इसे कॉन्फ़िगर करना आम है?
    • क्या मैं कॉन्फ़िगरेशन की setAccessibleपरवाह किए बिना अपनी कक्षाएं लिख सकता हूं SecurityManager?
      • या मैं उस व्यक्ति की दया पर हूँ जो भी विन्यास का प्रबंधन करता है?

मुझे लगता है कि एक और महत्वपूर्ण सवाल है: क्या मुझे इस बारे में पता होना चाहिए ???

मेरी कक्षाओं में से किसी में भी लागू करने योग्य गोपनीयता का कोई जोड़ नहीं है। सिंगलटन पैटर्न (इसके गुणों के बारे में संदेह को अलग रखना) अब लागू करना असंभव है। जैसा कि ऊपर मेरे स्निपेट दिखाते हैं, यहां तक ​​कि जावा मौलिक कार्यों की गारंटी के बारे में कुछ बुनियादी धारणाएं भी गारंटी होने के करीब नहीं हैं।

क्या ये समस्या सच नहीं हैं ???


ठीक है, मैंने अभी पुष्टि की है: धन्यवाद setAccessible, जावा तार अपरिवर्तनीय नहीं हैं ।

import java.lang.reflect.*;

public class MutableStrings {
   static void mutate(String s) throws Exception {
      Field value = String.class.getDeclaredField("value");
      value.setAccessible(true);
      value.set(s, s.toUpperCase().toCharArray());
   }   
   public static void main(String args[]) throws Exception {
      final String s = "Hello world!";
      System.out.println(s); // "Hello world!"
      mutate(s);
      System.out.println(s); // "HELLO WORLD!"
   }
}

क्या मैं अकेला हूँ जो सोचता है कि यह एक बड़ी चिंता है?


30
आपको यह देखना चाहिए कि वे C ++ में क्या कर सकते हैं! (ओह, और शायद सी #।)
टॉम ह्विटिन -

जवाबों:


105

क्या मुझे इस बारे में पता होना चाहिए ???

यह पूरी तरह से इस बात पर निर्भर करता है कि आप किस प्रकार के कार्यक्रम लिख रहे हैं और किस तरह की वास्तुकला के लिए।

यदि आप दुनिया के लोगों के लिए foo.jar नामक एक सॉफ़्टवेयर घटक वितरित कर रहे हैं, तो आप पूरी तरह से उनकी दया पर हैं। वे आपके .jar (रिवर्स इंजीनियरिंग या प्रत्यक्ष बायोटेक हेरफेर के माध्यम से) के अंदर कक्षा की परिभाषाओं को संशोधित कर सकते हैं। वे अपने कोड को अपने स्वयं के जेवीएम, आदि में चला सकते हैं। इस मामले में चिंता करना आपके लिए अच्छा नहीं होगा।

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

यदि आपकी भविष्य की नौकरी सन माइक्रोसिस्टम्स / ओरेकल में कोड लिख रही है और आपको जावा कोर या अन्य विश्वसनीय घटकों के लिए कोड लिखने का काम सौंपा गया है, तो यह कुछ ऐसा है जिसके बारे में आपको जानकारी होनी चाहिए। हालांकि, चिंता करने से आप अपने बालों को खो देंगे। किसी भी मामले में वे संभवत: आपको आंतरिक प्रलेखन के साथ - साथ सुरक्षित कोडिंग दिशानिर्देश पढ़ेंगे ।

यदि आप जावा एप्लेट लिखने जा रहे हैं, तो सुरक्षा ढांचा कुछ ऐसा है जिसके बारे में आपको जानकारी होनी चाहिए। आप पाएंगे कि सेट किए गए कॉल को विफल करने के लिए अहस्ताक्षरित ऐपलेट्स का परिणाम केवल SecurityException में होगा।

setAccessible केवल एक चीज नहीं है जो पारंपरिक अखंडता की जाँच करता है। एक गैर-एपीआई, कोर जावा क्लास है जिसे sun.misc.Unsafe कहा जाता है जो सीधे मेमोरी तक पहुंच सहित सभी को बहुत कुछ कर सकता है। नेटिव कोड (JNI) इस तरह के नियंत्रण के आसपास भी जा सकता है।

सैंडबॉक्स वाले वातावरण में (उदाहरण के लिए Java Applets, JavaFX), प्रत्येक वर्ग के पास अनुमतियों का एक सेट होता है और Unsafe तक पहुंच होती है, SetAccessible और परिभाषित मूल कार्यान्वयन SecurityManager द्वारा नियंत्रित होते हैं।

"जावा एक्सेस संशोधक सुरक्षा तंत्र के लिए अभिप्रेत नहीं हैं।"

यह बहुत कुछ इस बात पर निर्भर करता है कि जावा कोड कहाँ चलाया जा रहा है। सैंडबॉक्स लागू करने के लिए कोर जावा कक्षाएं सुरक्षा तंत्र के रूप में एक्सेस मॉडिफायर का उपयोग करती हैं।

सेट करने योग्य के लिए वास्तव में वैध उपयोग क्या हैं?

जावा कोर कक्षाएं इसे सामान तक पहुंचने के लिए एक आसान तरीके के रूप में उपयोग करती हैं, जिसे सुरक्षा कारणों से निजी रहना पड़ता है। एक उदाहरण के रूप में, जावा सीरियलाइज़ेशन फ्रेमवर्क का उपयोग ऑब्जेक्ट्स को डीरियलाइज़ करते समय निजी ऑब्जेक्ट कंस्ट्रक्टर्स को आमंत्रित करने के लिए करता है। किसी ने System.setErr का उल्लेख किया है, और यह एक अच्छा उदाहरण होगा, लेकिन उत्सुकता से सिस्टम वर्ग के तरीकों को सेट कर दिया गया / अंतिम सेट के मूल्य को सेट करने के लिए सभी मूल कोड का उपयोग करें।

एक और स्पष्ट वैध उपयोग फ्रेमवर्क (दृढ़ता, वेब फ्रेमवर्क, इंजेक्शन) हैं जो वस्तुओं के अंदरूनी हिस्सों में झांकने की आवश्यकता है।

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

क्या जावा को इस तरह से डिज़ाइन किया गया है कि पहली जगह में इसकी आवश्यकता नहीं है?

यह अच्छी तरह से जवाब देने के लिए एक बहुत गहरा सवाल है। मैं कल्पना करता हूं कि हां, लेकिन आपको कुछ अन्य तंत्र को जोड़ने की आवश्यकता होगी जो कि सभी के लिए बेहतर नहीं हो सकते।

क्या आप सेट का उपयोग प्रतिबंधित कर सकते हैं केवल वैध उपयोगों के लिए?

आपके द्वारा लागू किया जा सकने वाला सबसे सीधा OOTB प्रतिबंध एक SecurityManager है और केवल कुछ स्रोतों से आने वाले कोड को सेट करने में असफल है। यह वही है जो जावा पहले से ही करता है - आपके जावा_होम से आने वाले मानक जावा वर्गों को सेटएबेल करने की अनुमति है, जबकि foo.com से अहस्ताक्षरित एपलेट सेट सेट करने योग्य नहीं हैं। जैसा कि पहले कहा गया था, यह अनुमति द्विआधारी है, इस अर्थ में कि या तो उसके पास है या नहीं। दूसरों को ठुकराते समय कुछ क्षेत्रों / विधियों को संशोधित करने में असफल होने की अनुमति देने का कोई स्पष्ट तरीका नहीं है। हालाँकि, SecurityManager का उपयोग करना, हालाँकि, कुछ संकुल को पूरी तरह से या बिना प्रतिबिंब के संदर्भित करने से कक्षाओं को अस्वीकार कर देता है।

क्या मैं अपनी कक्षाओं को लिख सकता हूं कि असफल होने के बावजूद SecurityManager कॉन्फ़िगरेशन की परवाह किए बिना? ... या मैं उस व्यक्ति की दया पर हूँ जो भी विन्यास का प्रबंधन करता है?

आप नहीं कर सकते हैं और आप सबसे निश्चित रूप से कर रहे हैं।


"यदि आप दुनिया के लोगों को foo.jar नामक एक सॉफ़्टवेयर घटक वितरित कर रहे हैं, तो आप वैसे भी पूरी तरह से उनकी दया पर हैं। वे आपके .jar (रिवर्स इंजीनियरिंग या प्रत्यक्ष बायोटेक हेरफेर के माध्यम से) के अंदर वर्ग परिभाषाओं को संशोधित कर सकते हैं।" अपने कोड को अपने स्वयं के जेवीएम में चला सकते हैं, आदि। इस मामले में चिंता करना आपके लिए अच्छा नहीं होगा। " क्या अभी भी यही मामला है? सॉफ़्टवेयर में छेड़छाड़ करने पर कोई सलाह देना कठिन है (उम्मीद है कि महत्वपूर्ण है)? यह सिर्फ जावा डेस्कटॉप अनुप्रयोगों को इस वजह से खिड़की से बाहर फेंकना मुश्किल है।
सेरो

@ मेरा कहना है कि कुछ भी नहीं बदला है। यह सिर्फ इतना है कि वास्तुकला आपके खिलाफ काम कर रही है। मेरी मशीन पर चलने वाला कोई भी सॉफ्टवेयर, जिस पर मेरा पूरा नियंत्रण है, मैं बदल सकता हूं। सबसे मजबूत निवारक एक कानूनी हो सकता है, लेकिन मुझे नहीं लगता कि सभी परिदृश्यों के लिए काम करेगा। मुझे लगता है कि जावा बायनेरिज़ रिवर्स करने में सबसे आसान है, लेकिन अनुभव वाले लोग कुछ भी छेड़छाड़ करेंगे। मोटे तौर पर बड़े बदलाव करने में कठिनाई से मदद मिलती है, लेकिन बूलियन (कॉपीराइट जांच की तरह) के कुछ भी अभी भी बाईपास के लिए तुच्छ है। आप इसके बजाय मुख्य भागों को सर्वर पर रखने का प्रयास कर सकते हैं।
सामी कोईवु

डेवुवो के बारे में कैसे?
सेरो

15
  • वास्तव में वैध उपयोग क्या हैं setAccessible?

यूनिट परीक्षण, जेवीएम के आंतरिक (जैसे कार्यान्वयन System.setError(...)) और इतने पर।

  • क्या जावा को इस तरह से डिज़ाइन किया गया है कि पहली जगह में इसकी आवश्यकता नहीं है?
  • इस तरह के डिजाइन के नकारात्मक परिणाम (यदि कोई हो) क्या होगा?

बहुत सी बातें अमल में लाई जायेंगी। उदाहरण के लिए, विभिन्न जावा दृढ़ता, क्रमांकन और निर्भरता इंजेक्शन प्रतिबिंब पर निर्भर हैं। और बहुत कुछ है जो रनटाइम पर JavaBeans सम्मेलनों पर निर्भर करता है।

  • क्या आप setAccessibleकेवल वैध उपयोगों तक ही सीमित रह सकते हैं ?
  • के माध्यम से ही है SecurityManager?

हाँ।

  • यह कैसे काम करता है? श्वेतसूची / ब्लैकलिस्ट, ग्रेन्युलैरिटी, आदि?

यह अनुमति पर निर्भर करता है, लेकिन मेरा मानना ​​है कि उपयोग की अनुमति setAccessibleद्विआधारी है। यदि आप ग्रैन्युलैरिटी चाहते हैं, तो आपको उन वर्गों के लिए एक अलग सुरक्षा प्रबंधक के साथ एक अलग श्रेणी लोडर का उपयोग करने की आवश्यकता है जिसे आप प्रतिबंधित करना चाहते हैं। मुझे लगता है कि आप एक कस्टम सुरक्षा प्रबंधक को लागू कर सकते हैं जो बेहतर दलील वाले तर्क को लागू करता है।

  • क्या आपके एप्लिकेशन में इसे कॉन्फ़िगर करना आम है?

नहीं।

  • क्या मैं कॉन्फ़िगरेशन की setAccessibleपरवाह किए बिना अपनी कक्षाएं लिख सकता हूं SecurityManager?
    • या मैं उस व्यक्ति की दया पर हूँ जो भी विन्यास का प्रबंधन करता है?

नहीं, तुम नहीं कर सकते, और हाँ तुम हो।

अन्य विकल्प स्रोत-कोड विश्लेषण उपकरणों के माध्यम से इसे "लागू" करना है; जैसे प्रथा pmdया findbugsनियम। या (कहना) द्वारा पहचाने गए कोड की चयनात्मक कोड समीक्षा grep setAccessible ...

फॉलोअप के जवाब में

मेरी कक्षाओं में से किसी में भी लागू करने योग्य गोपनीयता का कोई जोड़ नहीं है। सिंगलटन पैटर्न (इसके गुणों के बारे में संदेह को अलग रखना) अब लागू करना असंभव है।

अगर वह आपको चिंतित करता है, तो मुझे लगता है कि आपको चिंता करने की आवश्यकता है। लेकिन वास्तव में आपको जबरदस्ती करने की कोशिश नहीं करनी चाहिए अपने डिजाइन निर्णयों का सम्मान करने के लिए अन्य प्रोग्रामरों को । यदि लोग आपके एकल (उदाहरण के लिए) के कई उदाहरण बनाने के लिए प्रतिबिंब का उपयोग करने के लिए पर्याप्त बेवकूफ हैं, तो वे परिणामों के साथ रह सकते हैं।

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

<स्ट्रिंग उदाहरण> - क्या मैं अकेला हूं जो सोचता है कि यह एक बड़ी चिंता है?

शायद एक ही नहीं :-)। लेकिन IMO, यह चिंता का विषय नहीं है। यह तथ्य स्वीकार किया जाता है कि अविश्वसनीय कोड को सैंडबॉक्स में निष्पादित किया जाना चाहिए। यदि आपने कोड / एक विश्वसनीय प्रोग्रामर को इस तरह से काम करने का भरोसा दिया है, तो आपकी समस्याएं अप्रत्याशित रूप से उत्परिवर्तनीय स्ट्रिंग्स से भी बदतर हैं। (लॉजिक बम, गुप्त चैनलों के माध्यम से डेटा का बहिष्कार सोचो , वगैरह)

आपके विकास या संचालन टीम में एक "खराब अभिनेता" की समस्या से निपटने (या शमन) के तरीके हैं। लेकिन वे महंगे और प्रतिबंधात्मक हैं ... और अधिकांश उपयोग के मामलों के लिए ओवरकिल।


1
दृढ़ता कार्यान्वयन जैसी चीजों के लिए भी उपयोगी है। विचार-विमर्श वास्तव में डिबगर्स के लिए उपयोगी नहीं है (हालांकि यह मूल रूप से होने का इरादा था)। आप इसके लिए (उपवर्ग) को उपयोगी रूप से नहीं बदल सकते हैं SecurityManager, क्योंकि आपको मिलने वाली सभी अनुमति जांच है - आप वास्तव में कर सकते हैं कि एसीसी को देखें और शायद स्टैक की जांच करें वर्तमान धागा। grep java.lang.reflect.
टॉम हॉल्टिन -

@Stephen C: +1 पहले से ही है, लेकिन मैं आपके इनपुट की सराहना करूँगा जो मैंने अभी जोड़े हैं। अग्रिम में धन्यवाद।
पॉलीजेनैलेबुलेंटेंट्स

ध्यान दें कि grep एक भयानक विचार है। जावा में कोड को गतिशील रूप से निष्पादित करने के बहुत सारे तरीके हैं जो आपको लगभग निश्चित रूप से याद करेंगे। सामान्य रूप से ब्लैकलिस्टिंग कोड विफलता का एक नुस्खा है।
एंटिमोनी

"जावा एक्सेस संशोधक सुरक्षा तंत्र के लिए अभिप्रेत नहीं हैं।" - वास्तव में, हाँ वे हैं। जावा को उसी आभासी मशीन में सह-अस्तित्व के लिए विश्वसनीय और अविश्वसनीय कोड की अनुमति देने के लिए डिज़ाइन किया गया है - यह शुरुआत से ही इसकी मुख्य आवश्यकताओं का हिस्सा था। लेकिन केवल तभी जब सिस्टम लॉक-डाउन SecurityManager के साथ चल रहा हो। सैंडबॉक्स कोड की क्षमता पूरी तरह से एक्सेस स्पेसर्स के प्रवर्तन पर निर्भर करती है।
जूल्स

@ जूल्स - अधिकांश जावा विशेषज्ञ इससे सहमत नहीं होंगे; उदा। stackoverflow.com/questions/9201603/…
स्टीफन C

11

परावर्तन वास्तव में इस दृष्टिकोण के तहत सुरक्षा / सुरक्षा के लिए रूढ़िवादी है।

हम प्रतिबिंब को कैसे सीमित कर सकते हैं?

जावा के पास सुरक्षा प्रबंधक है और ClassLoaderइसके सुरक्षा मॉडल के आधार पर। आपके मामले में, मुझे लगता है कि आपको देखने की जरूरत है java.lang.reflect.ReflectPermission

लेकिन यह प्रतिबिंब की समस्या को पूरी तरह से हल नहीं करता है। जो परावर्तक क्षमताएं उपलब्ध हैं, वे एक अच्छी दानेदार प्राधिकरण योजना के अधीन होनी चाहिए, जो अब ऐसा नहीं है। उदाहरण के लिए प्रतिबिंब (जैसे हाइबरनेट) का उपयोग करने के लिए कुछ निश्चित ढांचे की अनुमति देने के लिए, लेकिन आपके कोड के बाकी हिस्से को नहीं। या डिबगिंग उद्देश्य के लिए एक कार्यक्रम को केवल-पढ़ने के लिए केवल तरीके से प्रतिबिंबित करने की अनुमति देने के लिए।

एक दृष्टिकोण जो भविष्य में मुख्यधारा बन सकता है, वह वर्गों से अलग-अलग चिंतनशील क्षमताओं को अलग करने के लिए तथाकथित दर्पणों का उपयोग है । दर्पण देखें : मेटा-स्तरीय सुविधाओं के लिए डिज़ाइन सिद्धांत । हालांकि अन्य विभिन्न शोध हैं इस मुद्दे से निपटने वाले । लेकिन मैं मानता हूं कि समस्या स्थैतिक भाषाओं की तुलना में गतिशील भाषा के लिए अधिक गंभीर है।

क्या हमें उस महाशक्ति से चिंतित होना चाहिए जो प्रतिबिंब हमें देती है?हां और ना।

हां इस मायने में कि जावा प्लेटफॉर्म को Classloaderसिक्योरिटी मैनेजर के साथ सुरक्षित माना जाता है । प्रतिबिंब के साथ गड़बड़ करने की क्षमता को एक उल्लंघन के रूप में देखा जा सकता है।

कोई भावना में पूरी तरह से सुरक्षित नहीं है कि ज्यादातर प्रणाली वैसे भी कर रहे हैं। बहुत सारी कक्षाएं अक्सर उपवर्गित हो सकती हैं और आप संभवतः पहले से ही इस प्रणाली का दुरुपयोग कर सकते हैं। बेशक कक्षाएं बनाई जा सकती हैं final, या सील की जा सकती हैं ताकि उन्हें दूसरे जार में उप-वर्गित नहीं किया जा सके। लेकिन केवल कुछ वर्गों को इसके अनुसार सही तरीके से सुरक्षित किया जाता है (जैसे स्ट्रिंग)।

एक अच्छी व्याख्या के लिए अंतिम कक्षा के बारे में यह उत्तर देखें । सामी कोइवु का ब्लॉग भी देखेंसुरक्षा के आसपास अधिक जावा हैकिंग के लिए ।

जावा के सुरक्षा मॉडल को कुछ संबंध में अपर्याप्त के रूप में देखा जा सकता है। न्यूस्पीक जैसी कुछ भाषाएं और भी अधिक कट्टरपंथी दृष्टिकोण को ले जाती हैं, जहां आपको केवल उसी चीज तक पहुंच प्राप्त होती है जो निर्भरता से उलट (डिफ़ॉल्ट रूप से) आपको स्पष्ट रूप से दी जाती है।

यह भी ध्यान रखना महत्वपूर्ण है कि सुरक्षा वैसे भी सापेक्ष है । भाषा स्तर पर, आप उदाहरण के लिए 100% सीपीयू या सभी मेमोरी का उपभोग करने वाले मॉड्यूल फॉर्म को रोक नहीं सकते हैं OutOfMemoryException। इस तरह की चिंताओं को अन्य तरीकों से संबोधित करने की आवश्यकता है। हम शायद भविष्य में जावा को संसाधन उपयोग कोटा के साथ विस्तारित देखेंगे, लेकिन यह कल के लिए नहीं है :)

मैं इस विषय पर अधिक विस्तार कर सकता था, लेकिन मुझे लगता है कि मैंने अपनी बात बना ली है।

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