Rails에서 Constantize를 사용하지 않는 또 다른 이유
배경 이야기
최근 한 친구는 후속 코드 사용 결과가 없어도 사용자가 입력할 때
constantize
으로 전화하는 것이 위험하냐고 물었다.예를 들어, 이 Rails 코드는 질의 매개 변수를 상수로 변환합니다.
params[:class].classify.constantize
Brakeman은 이 코드에 대한 "원격 코드 실행"경고를 보고합니다.Confidence: High
Category: Remote Code Execution
Check: UnsafeReflection
Message: Unsafe reflection method `constantize` called with parameter value
Code: params[:class].classify.constantize
File: app/controllers/users_controller.rb
Line: 7
그런데 왜요?물론 문자열을 상수로 변환할 뿐입니다. (상수가 존재한다면!)위험하진 않겠지?우리는 어떻게 그것으로 코드를 집행합니까?좋아요.공교롭게도 같은 시간에 나는 루비의 반서열화 작은 도구인 특히 this one을 연구하고 있다. 그 중에서 루비의
Digest
모듈은 모듈 이름에 따라 파일을 불러올 것이다.예를 들어 Digest::A
은 require 'digest/a'
을 시도합니다.2.7.0 :001 > require 'digest'
=> true
2.7.0 :002 > Digest::Whatever
Traceback (most recent call last):
5: from /home/justin/.rvm/rubies/ruby-2.7.0/bin/irb:23:in `<main>'
4: from /home/justin/.rvm/rubies/ruby-2.7.0/bin/irb:23:in `load'
3: from /home/justin/.rvm/rubies/ruby-2.7.0/lib/ruby/gems/2.7.0/gems/irb-1.2.1/exe/irb:11:in `<top (required)>'
2: from (irb):2
1: from /home/justin/.rvm/rubies/ruby-2.7.0/lib/ruby/2.7.0/digest.rb:16:in `const_missing'
LoadError (library not found for class Digest::Whatever -- digest/whatever)
Digest
라이브러리는 const_missing
갈고리를 사용하여 이 기능을 실현한다.이것은 나로 하여금
constantize
과 const_missing
이 연결될 수 있는지, 그리고 어떤 결과가 발생할지 궁금하게 한다.레일 속의 영원한 불변
Rails turns a string into a constant의
constantize
방법입니다.이 상수가 존재하지 않으면 NameError
이 발생한다.그러나
const_missing
방법을 정의하여 Ruby에서 상수 검색 프로세스에 연결할 수 있습니다.주어진 모듈에서 상수를 찾을 수 없고 이 모듈이 const_missing
으로 정의되어 있으면 const_missing
을 호출합니다.2.7.0 :001 > module X
2.7.0 :002 > def self.const_missing(name)
2.7.0 :003 > puts "You tried to load #{name.inspect}"
2.7.0 :004 > end
2.7.0 :005 > end
=> :const_missing
2.7.0 :006 > X::Hello
You tried to load :Hello
=> nil
만약 const_missing
이 상수 명칭을 기반으로 하는 행위를 통해 이루어진다면, 예를 들어 파일을 불러오거나 새로운 대상을 만들면 악의적인 행위가 발생할 수 있다.여린 보석들
다행히도
const_missing
은 자주 사용하지 않는다.만약 그렇다면, 실현은 통상적으로 이용할 수 없다.나는 약 1300개의gem를 검색했는데 약 40개의gem만 찾았고
const_missing
을 실현했다.그중 대부분은 사용할 수 없는 것이다. 왜냐하면 예상치에 따라 상수 이름을 검사하거나
const_get
을 호출하면 상수가 존재하지 않으면 이상을 일으킬 수 있기 때문이다.보석 한 개, coderayloads files based on constant names, 도서관처럼.요약 라이브러리와 마찬가지로 이 파일들은
coderay
디렉터리에만 한정되어 있기 때문에 사용할 수 없을 것 같습니다.다음 두 개의gem에 메모리 유출이 있습니다. 이것은 메모리 소모를 통해 서비스 공격을 거부할 수 있습니다.
활용단어참조
Templegem은 Haml, Slim 및 기타 템플릿 라이브러리에서 사용되는 기본 gem입니다.
Temple에는 다음과 같이
Temple::Mixins::GrammarDSL
이라는 모듈이 있습니다.def const_missing(name)
const_set(name, Root.new(self, name))
end
이 방법은 주어진 const_missing
을 기반으로 새 상수를 만들고 새 대상을 지정합니다.이것은 쓰레기가 영원히 수집되지 않기 때문에 메모리 유출이다.만약 공격자가 그것을 촉발할 수 있다면, 그들은 무한한 수량의 영구 대상을 만들고 가능한 한 메모리를 사용할 수 있다.
불행히도 이 코드를 이용하는 것은 매우 쉽다.
name
은 Temple::Grammar
으로 확장되어 Temple의 핵심 과정입니다.Haml에서 로드되는지 확인합니다. Haml은 Rails에 자주 사용되는 템플릿 라이브러리입니다.2.7.0 :001 > require 'haml'
=> true
2.7.0 :002 > Temple::Grammar
=> Temple::Grammar
위대하다만약 우리가 존재하지 않는 모듈을 인용하려고 시도한다면, 무슨 일이 일어날까요?2.7.0 :003 > Temple::Grammar::DefinitelyDoesNotExist
=> #<Temple::Mixins::GrammarDSL::Root:0x000055a79b011060 @grammar=Temple::Grammar, @children=[], @name=:DefinitelyDoesNotExist>
상수는 위의 그림에서 보듯이 새 객체와 함께 작성됩니다.한층 더...constantize의 사용은 이 코드를 호출합니까?
Haml을 사용하여 어플리케이션에 대한 Rails 콘솔을 로드하는 테스트를 수행할 수 있습니다.
Loading development environment (Rails 6.0.3.2)
2.7.0 :001 > require 'haml'
=> false
2.7.0 :002 > 'Temple::Grammar::DefinitelyDoesNotExist'.constantize
=> #<Temple::Mixins::GrammarDSL::Root:0x000055ba28031a50 @grammar=Temple::Grammar, @children=[], @name=:DefinitelyDoesNotExist>
네!Haml이나 Slim을 사용하는 모든 Ruby on Rails 응용 프로그램은 사용자가 입력할 때
Template::Mixins::GrammarDSL
(예를 들어 constantize
)을 호출하면 이런 방법을 통해 메모리 유출이 발생하기 쉽다.원력을 회복하다
restforcegem에서 매우 유사한 코드 모델을 실현하였다.
ErrorCode module은 다음과 같이
params[:class].classify.constantize
을 사용합니다.module ErrorCode
def self.const_missing(constant_name)
const_set constant_name, Class.new(ResponseError)
end
end
거의 마찬가지다. 단지 이것은 실제적으로 새로운 클래스를 만들었을 뿐, 일반적인 대상이 아니다.Rails 콘솔에서 다음을 다시 확인할 수 있습니다.
Loading development environment (Rails 6.0.3.2)
2.7.0 :001 > require 'restforce'
=> false
2.7.0 :002 > Restforce::ErrorCode::WhateverWeWant
=> Restforce::ErrorCode::WhateverWeWant
이번에 우리는 새 수업을 하고 싶은 만큼 수업을 한다.Restforce 5.0.0에서 수정되었습니다.
메모리 유출 찾기 및 이용
생산 프로그램에서 이렇게 공격받기 쉬운 코드를 찾는 것은 매우 어려울 것이다.어떤 파라미터가
const_missing
d일 수 있는지 추측하기만 하면 됩니다.메모리 유출을 발견했는지 확인하는 것은 좀 까다롭습니다. 위에서 설명한 두 개의 메모리 유출 생성 대상은 매우 적습니다.
Temple의 새로운
constantize
대상은 약 300바이트의 메모리를 사용하고 Restforce의 새로운 클래스는 1000바이트에 가까운 메모리를 차지할 것으로 추정됩니다.이 점을 바탕으로 테스트한 결과 1GB 메모리만으로 100만 ~ 400만 개의 요청이 필요합니다.
웹 응용 프로그램이 정기적으로 다시 시작되고, 프로세스를 죽이고, 새로운 프로세스를 시작하는 것이 보통 대수롭지 않다는 것을 감안하면, 이것은 그다지 효과적이지 않은 것 같다.
그러나 이것은 짜증나고 작은 사이트에 해로울 수도 있다.예를 들어, 기본 Heroku 인스턴스는 512MB에 불과합니다.
메모리 유출은 보호되지 않은
Rule
호출의 최악의 결과가 아니라는 점도 주의해야 한다.원격 코드 실행을 촉발할 가능성이 더 높다.내가 여기서 탐구하고자 하는 진정한 문제는 의존항에 숨겨질 수 있는 의외의 행위이다.결론
Rails 애플리케이션에서는
constantize
을 사용하지 마십시오.만약 그것을 사용해야 한다면, constantize
을 호출하기 전에 허용된 클래스 이름 집합을 검사하십시오.(단, 먼저 constantize
을 쳐도 됩니다.)Ruby 라이브러리의
classify
도 마찬가지입니다.상수 이름을 사용하여 동적 작업 (파일 불러오기, 새 대상 만들기, 코드 계산 등) 을 피해야 합니다.이상적인 경우 예상된 이름 목록을 대조하여 검사하고 다른 내용을 거부합니다.마지막으로 이것은 사용자의 입력을 불신하고 입력을 엄격하게 검증하는 안전한 기초로 귀결된다.
Reference
이 문제에 관하여(Rails에서 Constantize를 사용하지 않는 또 다른 이유), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/presidentbeef/another-reason-to-avoid-constantize-in-rails-4pm4텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)