2015-10-12 6 views
10

क्या कोई मानक लाइब्रेरी विधियां हैं जो विशेष पथवर्ती अनुक्रमों जैसे ../ और ऊपर की ओर निर्देशिका निर्देशिका ट्रैवर्सल के सभी अन्य रूपांतरित रूपों को फ़िल्टर कर सकती हैं, फ़ाइल पथ API इनपुट की सुरक्षा के लिए दिए गए "रूट" पथ के ऊपर से ट्रैवर्सिंग से?जावा (या स्कैला) में ऊपर पथ ट्रैवर्सल को फ़िल्टर करना

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

यह व्यापक path traversal attack के समान है।

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

+0

कैसे आप वेब करने के लिए उन रास्तों को उजागर कर रहे हैं? आम तौर पर, स्प्रिंग जैसे ढांचे उन हमलों के खिलाफ कमजोर पड़ने का एक अच्छा काम करते हैं, इसलिए आपको शायद ही कभी सुरक्षा की कोई अन्य परत जोड़नी पड़ेगी। – Makoto

+0

मैं नहीं हूं। यह बैकएंड से संबंधित एपीआई के लिए है, जिसमें कुछ फ़ाइल हटाना तर्क शामिल है, और इसे ओएस फाइल सिस्टम अनुमतियों की सहायता के बिना किसी दिए गए रूट फ़ोल्डर के बाहर फ़ाइलों को हटाने से बचने की आवश्यकता है। – matanster

+0

हम किस प्रकार के रास्ते यहां बात कर रहे हैं? 'java.nio.file.Path' में उदाहरण के लिए आधार पर सापेक्ष फ़ाइल पथ को समेकित करने के तरीके हैं। – biziclop

उत्तर

0

ऐसा करने के लिए आपको किसी तृतीय-पक्ष लाइब्रेरी का उपयोग करने की आवश्यकता नहीं है। जावा एपीआई जो जावा प्रदान करता है आपको यह सत्यापित करने की क्षमता देता है कि एक फ़ाइल दूसरे के वंशज हैं।

Path.resolve(String) मूल निर्देशिका संदर्भ, पूर्ण, और सापेक्ष पथ हल करेगा। यदि एक पूर्ण पथ को हल करने की विधि के लिए तर्क के रूप में पारित किया जाता है तो यह पूर्ण पथ देता है। यह गारंटी नहीं देता है कि लौटाया गया मूल्य उस विधि के वंशज है जिस पर विधि लागू की गई थी।

आप यह जांच सकते हैं कि Path.startsWith(Path) विधि का उपयोग कर पथ किसी अन्य पथ का वंशज है।

Path root = java.nio.file.Files.createTempDirectory(null); 
Path relative = root.resolve(pathAsString).normalize(); 
if (!relative.startsWith(root)) { 
    throw new IllegalArgumentException("Path contains invalid characters"); 
} 

जब pathAsString माता पिता निर्देशिका के संदर्भ हैं या एक पूर्ण पथ, relative एक फ़ाइल है कि root में निहित नहीं है संदर्भित कर सकते हैं था। जब ऐसा होता है तो फ़ाइल में किसी भी संशोधन की अनुमति देने से पहले आप एक अपवाद फेंक सकते हैं।

+0

तो यह क्यों काम करता है? ** स्वयं को समझाएं। ** – Makoto

+0

चेतावनी: ऐसा मत करो! यह विधि कुछ भी नहीं बदतर है, क्योंकि यह सुरक्षा की झूठी भावना देती है। आप आसानी से इस चेक के साथ निर्देशिका ट्रैवर्सल हमले कर सकते हैं ... * ट्रैवर्सिंग *! उदाहरण के लिए: 'pathAsString = ".."; '। – Zero3

+0

तुलना से पहले सापेक्ष पथ सामान्यीकृत होना चाहिए। मैंने सुधार को प्रतिबिंबित करने के लिए उत्तर अपडेट किया। – Aaron

12

आप पथ से ".." तत्वों (और उनके पिछले तत्व) को बाहर निकालने के लिए Path.normalize() का उपयोग कर सकते हैं - उदा। यह "ए/बी /../ सी" को "ए/सी" में बदल देगा। ध्यान दें कि पर पथ से शुरू होने पर यह ".." को नहीं हटाएगा, क्योंकि इसके लिए कोई पूर्ववर्ती निर्देशिका घटक भी नहीं है। तो यदि आप एक और रास्ता तैयार करने जा रहे हैं, तो पहले ऐसा करें, फिर परिणाम को सामान्य करें।

आप यह भी जांचने के लिए Path.startsWith(Path) का उपयोग कर सकते हैं कि एक पथ दूसरे के वंशज है या नहीं। और Path.isAbsolute() आपको बताता है, असुरक्षित रूप से, चाहे कोई पथ पूर्ण या सापेक्ष है।

यहाँ कैसे मैं एपीआई में आने अविश्वस्त रास्तों पर कार्रवाई करेंगे:

/** 
* Resolves an untrusted user-specified path against the API's base directory. 
* Paths that try to escape the base directory are rejected. 
* 
* @param baseDirPath the absolute path of the base directory that all 
        user-specified paths should be within 
* @param userPath the untrusted path provided by the API user, expected to be 
        relative to {@code baseDirPath} 
*/ 
public Path resolvePath(final Path baseDirPath, final Path userPath) { 
    if (!baseDirPath.isAbsolute()) { 
    throw new IllegalArgumentException("Base path must be absolute") 
    } 

    if (userPath.isAbsolute()) { 
    throw new IllegalArgumentException("User path must be relative"); 
    } 

    // Join the two paths together, then normalize so that any ".." elements 
    // in the userPath can remove parts of baseDirPath. 
    // (e.g. "/foo/bar/baz" + "../attack" -> "/foo/bar/attack") 
    final Path resolvedPath = baseDirPath.resolve(userPath).normalize(); 

    // Make sure the resulting path is still within the required directory. 
    // (In the example above, "/foo/bar/attack" is not.) 
    if (!resolvedPath.startsWith(baseDirPath)) { 
    throw new IllegalArgumentException("User path escapes the base path"); 
    } 

    return resolvedPath; 
} 
संबंधित मुद्दे