1 पॉइंट द्वारा GN⁺ 4 시간 전 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • EEF CNA द्वारा प्रकाशित किए गए CVE में से 35.8% uncontrolled resource consumption हैं, और BEAM ecosystem में बार-बार होने वाली atom exhaustion एक बड़ा हिस्सा रखती है
  • Atom exhaustion एक denial-of-service vulnerability है; atom garbage collection नहीं होते, global table में जमा होते रहते हैं, और table भर जाने पर VM crash हो जाता है
  • User input जैसे ऐसे data से atom बनाना, जिनके possible values का set finite होने की गारंटी न हो, DoS risk पैदा करता है; URI scheme भी इसका अपवाद नहीं है
  • जोखिम सिर्फ binary_to_atom/1, String.to_atom/1 जैसे explicit calls तक सीमित नहीं है, बल्कि JSON key atom decoding और string interpolation आधारित dynamic creation में भी मौजूद है
  • सुरक्षित handling के लिए runtime में नए atom बनाने से बचना चाहिए, known values को explicit lookup table या to_existing_atom परिवार तक सीमित करना चाहिए, और linter से जांच करनी चाहिए

Atom exhaustion से बनने वाली denial-of-service vulnerability

  • EEF CNA द्वारा प्रकाशित CVE में 35.8% uncontrolled resource consumption हैं, और BEAM ecosystem में atom exhaustion की बार-बार आने वाली समस्याएँ बड़ा हिस्सा बनाती हैं {p:36}
  • मौजूदा distribution को EEF CNA के Common Weaknesses पेज पर देखा जा सकता है
  • Atom exhaustion एक denial-of-service (DoS) vulnerability है
    • Atom garbage collection नहीं होते
    • वे global atom table में store होते हैं
    • table भर जाने पर VM crash हो जाता है
  • non-finite values, खासकर user input, से atom बनाना संभावित DoS बन सकता है
  • जोखिम सिर्फ obvious calls तक सीमित नहीं है
    • Erlang में binary_to_atom/1, list_to_atom/1
    • Elixir में String.to_atom/1, List.to_atom/1
  • कम दिखाई देने वाले risky patterns भी मौजूद हैं
    • Erlang में interpolation के जरिए dynamic atom creation:
      % Erlang: interpolation के जरिए dynamic atom creation
      list_to_atom("field_" ++ UserInput)
      
    • Elixir में JSON key को atom के रूप में decode करना:
      
      
      
      # Elixir: JSON को atom key के रूप में decode करना
      Jason.decode(json, keys: :atoms)
      
    • Elixir में interpolation के जरिए dynamic atom creation:
      
      
      
      # Elixir: interpolation के जरिए dynamic atom creation
      :"field_#{user_input}"
      

सुरक्षित handling के तरीके और जांच के लक्ष्य

  • Atom exhaustion vulnerabilities सिर्फ साधारण लापरवाही का परिणाम नहीं हैं; ये अक्सर ऐसे code में पैदा होती हैं जो मान लेता है कि input controlled है या finite है
  • URI scheme इसका एक प्रतिनिधि उदाहरण है
    • ऐसा लग सकता है कि संभालने के लिए scheme सिर्फ कुछ ही हैं
    • लेकिन अगर value बाहरी input से आती है, तो possible set के finite होने की गारंटी नहीं रहती
  • input से atom बनाने वाला code तब तक सुरक्षित नहीं है जब तक possible values का set finite, known, और enforced न हो
  • सबसे सुरक्षित approach है कि runtime पर नए atom बिल्कुल न बनाए जाएँ
  • अगर allowed values known हैं, तो explicit lookup table इस्तेमाल करना ज्यादा सुरक्षित है
    % Erlang
    case Scheme of
        <<"http">> -> http;
        <<"https">> -> https;
        _ -> error
    end
    
  • जब lookup table practical न हो, तब ऐसे variants इस्तेमाल करने चाहिए जो नए atom न बनाएँ और सिर्फ existing atom ही use करें
    • ये functions नया atom बनाने के बजाय error raise करते हैं
    % Erlang
    binary_to_existing_atom(Value)
    list_to_existing_atom(Value)
    
    
    
    
    # Elixir
    String.to_existing_atom(value)
    List.to_existing_atom(value)
    
  • linter vulnerability बनने से पहले risky patterns पकड़ने में मदद कर सकता है
    • Elixir projects में Credo के Credo.Check.Warning.UnsafeToAtom को enable करने पर विचार किया जा सकता है
    • यह check String.to_atom/1, List.to_atom/1, Module.concat/1,2, और keys: :atoms का उपयोग करने वाले Jason.decode/2 के unsafe calls को flag करता है
    • यह check default रूप से disabled है
  • Erlang या Elixir project maintainers को binary, string, JSON key, URI components, headers, और config values से atom बनाने वाले code को खोजकर जांचना चाहिए
  • यह vulnerability category उन प्रकारों में से एक है जिन्हें CVE बनने से पहले अपेक्षाकृत आसानी से ठीक किया जा सकता है
  • अधिक विस्तृत guidance EEF Security Working Group की atom exhaustion prevention guide में दी गई है

1 टिप्पणियां

 
GN⁺ 4 시간 전
Lobste.rs की राय
  • यह कुछ वैसा लगता है जैसे Ruby में Symbol के garbage collection के दायरे में आने से पहले की स्थिति थी

  • शीर्षक समझ नहीं आ रहा। यह तो साफ़ तौर पर footgun जैसा दिखता है

    • लगता है शीर्षक का आशय यह है कि atom exhaustion को “सिर्फ footgun” कहना समस्या की गंभीरता को कम करके आंकना होगा
    • अगर मुझे सही याद है, मैं Erlang रोज़ इस्तेमाल नहीं करता, लेकिन atom का garbage collection नहीं होता
      अगर आप सोचें, “क्या Ruby में भी Erlang atom जैसा symbol नहीं होता?” तो हाँ, लेकिन Ruby symbol का garbage collection करती है
      इसके अलावा, डिफ़ॉल्ट रूप से जिस lookup table में Erlang atom रखे जाते हैं, वह अधिकतम 1,048,576 ही अनुमति देती है
      अगर form जैसे user input से atom को dynamically बनाया जाए, तो यह बहुत ख़तरनाक है और software denial-of-service attack के लिए खुल जाता है
    • मैंने इसे “सिर्फ” एक साधारण footgun से बड़ा मुद्दा समझा
      हालाँकि मेरे अनुभव में “footgun” ख़ुद काफ़ी व्यापक अभिव्यक्ति है, इसलिए किसी भी तरह से देखें तो शीर्षक की भाषा थोड़ी अटपटी लगती है
    • सही है, और यह तो बहुत बड़ा footgun लगता है
  • यह सुनकर हैरानी होती है, जैसे किसी मुख्य डिज़ाइन या implementation में कमी हो। जिस language की इंटरनेट पर लगातार तारीफ़ होती रहती है, उसके लिए यह और भी अप्रत्याशित है

    • BEAM atom मूलतः interned string होते हैं, और उनके लिए एक global byte↔integer table होती है
      उस table में reference counting जोड़ना महँगा पड़ता, और दशकों से मौजूद code की scaling characteristics बदल देता
      atom की अधिकतम संख्या डिफ़ॉल्ट रूप से 10 लाख है, और VM start होने के समय तय हो जाती है
      यह एक trap है, लेकिन इससे बचना मुश्किल नहीं है। बहुत पहले से सलाह यही रही है कि “user input से atom मत बनाओ”
      उदाहरण के लिए, अगर आप JSON parse कर रहे हैं, तो आम तौर पर keys को atom में convert नहीं करते, या फिर केवल तभी convert करते हैं जब atom पहले से मौजूद हो। इससे atom keys पर pattern matching हो सकती है, code loading के कारण वे atom पहले से बने होते हैं, और catch-all clause atom की जगह string ले सकता है
    • यह भी ध्यान रखना चाहिए कि Erlang एक niche language थी, जिसे पेशेवर programmers विशेष मामलों में इस्तेमाल करते थे
      Elixir कहीं ज़्यादा mainstream है, इसलिए Erlang developer के लिए यह बात जानना सामान्य हो सकता है, लेकिन Elixir developer के लिए नहीं
  • व्यक्तिगत रूप से, atom का उस तरह उपयोग करना मुझे अजीब लगता है। मैं Erlang के atom को लगभग C के enum type जैसा समझता हूँ
    यानी किसी खास तरीके से शब्द लिखने पर वह अंदरूनी रूप से enum बन जाने वाली सुविधा जैसा
    लेख में user input का ज़िक्र है, लेकिन मुझे समझ नहीं आता कि शुरुआत से ही user input से नया enum type बनाने की ज़रूरत वाला use case क्यों होगा। इसका उपयोग बहुत सीमित लगता है
    बगल की टिप्पणियाँ parsing की बात कर रही हैं, लेकिन आदर्श रूप से क्या आप पहले से ज्ञात data structure parse नहीं कर रहे होते? लगता है मैं कुछ मिस कर रहा हूँ

    • सवाल से थोड़ा हटकर, K में symbol globally intern होते हैं, और Erlang की तरह K process को symbol table खत्म करके मारा जा सकता है
      उस language में symbol को सिर्फ़ तेज equality comparison से अधिक, एक अलग type के रूप में रखने के कम से कम दो फ़ायदे हैं। symbol atom होते हैं, यानी characters की list-जैसी sequence नहीं, बल्कि atomic unit, इसलिए कई operators उन्हें अलग तरह से handle करते हैं, और symbol vectorized होते हैं, इसलिए उन्हें single-type list में सघन रूप से store किया जा सकता है
      K और Q में database table के columns को vectorized type के रूप में व्यक्त करना बहुत वांछनीय है। locality बेहतर मिलती है, memory का उपयोग अधिक कुशल होता है, और कई operators के लिए fast path मिलते हैं। लेकिन symbol table की सीमाओं के कारण, high-cardinality columns में symbol का उपयोग करते समय सावधानी रखनी पड़ती है
      अगर आप ज्ञात schema वाला JSON parse कर रहे हैं, तो symbol dictionary key के रूप में बहुत अच्छे हैं, और k2/k3 में तो लगभग अनिवार्य हैं। लेकिन अगर JSON की प्रकृति अज्ञात है, तो वह user input से नहीं आना चाहिए
      कुछ K dialects में symbol की लंबाई छोटी सीमित कर दी जाती है ताकि उन्हें 64-bit value में pack करके इधर-उधर ले जाया जा सके। सामान्यता की क़ीमत पर symbol table की ज़रूरत ही ख़त्म हो जाती है
  • सुरक्षा में “controlled input” और “uncontrolled input” का फ़र्क कभी-कभी null जैसी चीज़ की तरह महसूस होता है
    जब webpack-plugin-less-css जैसी एंट्री दिखती है कि अगर उसे untrusted CSS file मिले तो denial-of-service हो जाता है, तो CVE fatigue काफ़ी महसूस होती है
    फिर भी, यहाँ बेहतर boundary marking होनी चाहिए। उदाहरण के लिए, अगर string concatenation से गुज़रने पर कौन-सी safety properties बनी रहती हैं, ऐसे composition rules को भी ठीक से संभाला जा सके तो अच्छा होगा
    और अगर आपने HTTP POST से आई ढेर सारी चीज़ों को SafeString बना दिया, तो वह कुछ हद तक आपकी अपनी ज़िम्मेदारी है