1 puan yazan GN⁺ 4 시간 전 | 1 yorum | WhatsApp'ta paylaş
  • EEF CNA tarafından yayımlanan CVE’lerin %35,8’i kontrolsüz kaynak tüketimiyle ilgili ve BEAM ekosisteminde tekrarlayan atom tükenmesi önemli bir paya sahip
  • Atom tükenmesi, hizmet reddi türünde bir zafiyettir; atom’lar garbage collection ile temizlenmez, küresel tabloda birikir ve tablo dolunca VM çöker
  • Olası değer kümesinin sonlu olduğu garanti edilmeyen verilerden, örneğin kullanıcı girdisinden, atom üretmek DoS riski doğurur; URI scheme de buna dahildir
  • Risk yalnızca binary_to_atom/1, String.to_atom/1 gibi açık çağrılarda değil, JSON anahtarlarını atom olarak decode etme ve string enterpolasyonuna dayalı dinamik üretimde de vardır
  • Güvenli yaklaşım, çalışma zamanında yeni atom üretmekten kaçınmak; bilinen değerleri açık bir lookup tablosu ya da to_existing_atom türevleriyle sınırlamak ve linter ile denetlemektir

Atom tükenmesinin yarattığı hizmet reddi zafiyeti

  • EEF CNA tarafından yayımlanan CVE’lerin %35,8’i kontrolsüz kaynak tüketimidir ve BEAM ekosisteminde yinelenen atom tükenmesi sorunları büyük pay tutar {p:36}
  • Güncel dağılım, EEF CNA’nın Common Weaknesses sayfasında görülebilir
  • Atom tükenmesi bir hizmet reddi (DoS) zafiyetidir
    • Atom’lar garbage collection ile temizlenmez
    • Küresel atom tablosunda saklanır
    • Tablo dolarsa VM çöker
  • Sonlu olmayan değerlerden, özellikle kullanıcı girdisinden, atom üretmek potansiyel bir DoS yaratır
  • Risk yalnızca bariz çağrılarla sınırlı değildir
    • Erlang’da binary_to_atom/1, list_to_atom/1
    • Elixir’de String.to_atom/1, List.to_atom/1
  • Daha az görünür risk kalıpları da vardır
    • Erlang’da enterpolasyon yoluyla dinamik atom üretimi:
      % Erlang: 보간을 통한 동적 atom 생성
      list_to_atom("field_" ++ UserInput)
      
    • Elixir’de JSON anahtarlarını atom olarak decode etme:
      
      
      
      # Elixir: JSON을 atom 키로 디코딩
      Jason.decode(json, keys: :atoms)
      
    • Elixir’de enterpolasyon yoluyla dinamik atom üretimi:
      
      
      
      # Elixir: 보간을 통한 동적 atom 생성
      :"field_#{user_input}"
      

Güvenli işleme yöntemleri ve kontrol edilmesi gerekenler

  • Atom tükenmesi zafiyetleri yalnızca basit bir dikkatsizlikten kaynaklanmaz; çoğu zaman girdinin denetimli ya da sonlu olduğu varsayılan kodlarda ortaya çıkar
  • URI scheme bunun tipik bir örneğidir
    • İşlenecek scheme sayısının yalnızca birkaç tane olduğu düşünülebilir
    • Ancak değer dış girdiden geliyorsa, olası kümenin artık sonlu olduğu garanti edilemez
  • Girdiden atom üreten kod, ancak olası değer kümesi sonlu, biliniyor ve zorunlu kılınıyorsa güvenlidir
  • En güvenli yaklaşım, çalışma zamanında yeni atom üretmemektir
  • İzin verilen değerler biliniyorsa açık bir lookup tablosu kullanmak daha güvenlidir
    % Erlang
    case Scheme of
        <<"http">> -> http;
        <<"https">> -> https;
        _ -> error
    end
    
  • Lookup tablosu pratik değilse, yeni atom üretmeden yalnızca mevcut atom’ları kullanan varyantlar tercih edilmelidir
    • Bu fonksiyonlar yeni atom oluşturmaz, hata üretir
    % Erlang
    binary_to_existing_atom(Value)
    list_to_existing_atom(Value)
    
    
    
    
    # Elixir
    String.to_existing_atom(value)
    List.to_existing_atom(value)
    
  • Linter’lar, zafiyete dönüşmeden önce riskli kalıpları yakalamaya yardımcı olur
    • Elixir projelerinde Credo’nun Credo.Check.Warning.UnsafeToAtom denetimini etkinleştirmek düşünülebilir
    • Bu denetim, String.to_atom/1, List.to_atom/1, Module.concat/1,2 ve Jason.decode/2 içinde keys: :atoms kullanımının güvensiz çağrılarını işaretler
    • Bu denetim varsayılan olarak devre dışıdır
  • Erlang veya Elixir projelerinin bakımını yapanlar; binary, string, JSON anahtarları, URI bileşenleri, header’lar ve yapılandırma değerlerinden atom üreten kodları aramalıdır
  • Bu zafiyet sınıfı, CVE’ye dönüşmeden önce düzeltilmesi en kolay türlerden biridir
  • Daha ayrıntılı yönergeler, EEF Security Working Group’un atom tükenmesini önleme kılavuzunda yer alıyor

1 yorum

 
GN⁺ 4 시간 전
Lobste.rs yorumları
  • Ruby’de Symbol çöp toplanabilir hale gelmeden önceki duruma benziyor

  • Başlığı anlamadım. Bu kesinlikle bir footgun gibi görünüyor

    • Sanırım başlığın demek istediği, atom tükenmesini “sadece bir footgun” diye adlandırmanın sorunun ciddiyetini hafife almak olduğu
    • Yanlış hatırlamıyorsam, Erlang’ı her gün kullanmıyorum ama atomlar çöp toplanmıyor
      “Ruby’de de Erlang atomlarına benzeyen symbol’ler yok muydu?” diye düşünürseniz, evet ama Ruby symbol’leri çöp topluyor
      Ayrıca Erlang atomlarının tutulduğu arama tablosu varsayılan olarak en fazla 1.048.576 öğeye izin veriyor
      Form gibi kullanıcı girdilerinden dinamik olarak atom üretirseniz bu çok tehlikelidir ve yazılımı hizmet engelleme saldırılarına açık hale getirir
    • Ben bunu, “sıradan” bir footgun’dan daha büyük bir sorun olduğu şeklinde anladım
      Yine de deneyimime göre “footgun” zaten oldukça geniş bir ifade, bu yüzden başlık her hâlükârda tuhaf duruyor
    • Evet, hatta devasa bir footgun gibi görünüyor
  • Tasarımın ya da uygulamanın temelden kötü bir yanı varmış gibi gelmesi şaşırtıcı. İnternette sürekli övülen bir dil olduğu için daha da beklenmedik

    • BEAM atomları özünde intern edilmiş string’lerdir ve global bir bayt↔tamsayı tablosuna sahiptir
      Bu tabloya referans sayımı eklemek maliyetlidir ve onlarca yıldır var olan kodun ölçeklenme özelliklerini değiştirir
      Varsayılan atom üst sınırı 1 milyondur ve VM başlatılırken belirlenir
      Bu bir tuzaktır ama kaçınılması zor değildir. Çok uzun zamandır tavsiye edilen şey “kullanıcı girdisinden atom oluşturmayın” olmuştur
      Örneğin JSON ayrıştırıyorsanız, normalde anahtarları atomlara çevirmemeli ya da yalnızca zaten var olan bir atomsa çevirmelisiniz. Böylece atom anahtarlarıyla pattern matching yapabilirsiniz; kod yüklenirken bu atomlar zaten oluşturulmuştur ve catch-all klozu atom yerine string alabilir
    • Erlang’ın, özel durumlarda uzman programcıların kullandığı niş bir dil olduğunu hesaba katmak gerekir
      Elixir çok daha yaygın; dolayısıyla Erlang geliştiricileri bunu biliyor olabilir ama Elixir geliştiricileri bilmiyor olabilir
  • Bana göre atomları bu şekilde kullanmak baştan garip geliyor. Çünkü Erlang atomlarını kabaca C’deki enum türü gibi düşünüyorum
    Belirli bir biçimde kelime yazınca içeride enum’a dönüşen bir kolaylık özelliği gibi
    Yazı kullanıcı girdisinden bahsediyor ama zaten kullanıcı girdisinden yeni bir enum türü üretmek isteyeceğiniz bir kullanım senaryosu neden olsun, emin değilim. Kullanım alanı aşırı dar görünüyor
    Yan yorumlarda ayrıştırmadan söz ediliyor ama idealde önceden bilinen veri yapıları ayrıştırılıyor olmaz mı? Sanki bir şeyi kaçırıyorum

    • Soruyla biraz alakasız ama K dilinde symbol’ler global olarak intern edilir ve Erlang’daki gibi K süreçleri symbol tablosunu tüketerek öldürülebilir
      O dilde symbol’leri, yalnızca hızlı eşitlik karşılaştırmasının ötesinde ayrı bir tür olarak tutmanın en az iki avantajı var. Symbol’ler atomlardır; yani karakter listesi türü bir dizi değil, atomik birimlerdir, bu yüzden birçok operatör onları farklı ele alır ve symbol’ler vektörize edilerek tek türden listelerde sıkı biçimde saklanabilir
      K ve Q’da veritabanı tablolarının sütunlarını vektörize edilmiş türler olarak temsil etmek çok arzu edilir. Yerellik daha iyidir, bellek daha verimli kullanılır ve birçok operatörde hızlı yollar vardır. Ancak symbol tablosu kısıtları nedeniyle, kardinalitesi yüksek sütunlarda symbol kullanırken dikkatli olmak gerekir
      Bilinen şemaya sahip JSON ayrıştırılıyorsa, symbol’ler sözlük anahtarları için harikadır ve k2/k3’te fiilen zorunludur. Ama kimliği belirsiz bir JSON ise, bunun kullanıcı girdisinden gelmemesi gerekir
      Bazı K lehçeleri symbol uzunluğunu kısa tutarak 64 bitlik bir değere paketlenip taşınabilmesini sağlar. Genellikten ödün verilir ama bunun karşılığında symbol tablosuna ihtiyaç kalmaz
  • “Kontrollü girdi” ile “kontrolsüz girdi” ayrımı, güvenlikte null olup olmaması gibi geliyor
    webpack-plugin-less-css güvenilmeyen CSS dosyaları aldığında hizmet engelleme yaşanıyor türü kayıtları görünce CVE yorgunluğu ciddi biçimde hissediliyor
    Yine de burada daha iyi sınır işaretleri olsa güzel olurdu. Örneğin string birleştirmeden geçince hangi güvenlik özelliklerinin korunduğu gibi bileşim kurallarını da iyi ele alabilsek
    Ayrıca HTTP POST ile gelen bir sürü şeyi SafeString yapıştırıp geçtiyseniz, bu da bir noktaya kadar sizin sorumluluğunuzdur