레일즈로 안전한 웹 애플리케이션 만들기

Building secure web applications with Ruby on Rails

Posted by npmachine on September 24, 2017

Murtaza Gulamali의 Building secure web applications with Ruby on Rails를 번역한 글입니다.


루비 온 레일즈와 같은 성숙한 프레임워크로 웹 프로그램을 만들 때의 장점은 적정한 수준의 보안을 기본으로 제공한다는 점이다. 4.0 이상 버전에는 항상 기회를 노리는 해커를 막기 위한 몇 가지 기본 메커니즘이 내장되어 있다. 레일즈 커뮤니티는 새로운 취약점을 파악하고 수정하기 위해 적극적으로 노력하고 있으며, 프레임워크는 공식이나 비공식 둘다 훌륭하게 문서화 되어 있다. 그러나 보안 기능 중 일부를 사용하지 않는 경우, 코드가 모범 사례를 따르지 않는 경우, 일반적인 웹 보안을 준수하지 않는 경우에는 당신의 레일즈 앱이 공격에 노출될 수 있다.

이를 더 자세히 이해하기 위해, 올해 초 우리는 클라이언트 프로젝트 작업을 하루 쉬고, 전 Bambino 팀원이었던 Najaf Ali가 주최한 워크샵에서 웹 보안에 대해 배웠다. 우리는 일반적인 웹 앱의 취약점을 악용하는 과제를 완료하는데 그 날 하루를 보냈다. 워크샵을 위한 각각의 프로그램은 소스 코드를 본다던지, 관련 데이터베이스를 참조한다던지, 웹 서버 로그를 검사하지 않고 찾아야하는 “비밀” 정보를 포함하도록 특별히 제작되었다.

웹 프로그램을 공격하는 일반적인 방법 중 하나는 코드 삽입(code injection)이다. 코드 삽입을 통해 공격자는 악의적인 코드나 매개 변수를 웹 프로그램에 끼워넣는다. 이는 일반적으로 form 이나 POST 요청과 같이 웹 프로그램에 데이터를 추가 할 수 있는 곳이면 어디에서나 발생한다. 이 악성 코드는 가끔 웹 서버에서 실행하거나, 백엔드 데이터베이스에 입력하거나, 출력하기 전에 보안 처리되지 않는다. 이는 공격자가 웹 애플리케이션의 보안 영역 안에서 실행될 수 있는 코드를 삽입 할 수 있는 기회를 만든다.

다행히 레일즈는 코드 삽입(code injection) 방지를 도와준다. 우선, ERB 뷰에서 일반 문자열은 자동으로 예외 처리(escape)된다.

<%= "<script>document.alert('Mwahahaha!')</script>" %>

&lt;script&gt;document.alert('Mwahahaha!')&lt;/script&gt;

으로 된다.

나아가 보안처리(sanitize) 헬퍼는 데이터에서 원하지 않는 HTML 태그를 제거하는데 사용할 수 있다.

sanitize("<script>document.alert('Mwahahaha!')</script>")
=> ""

또한 허용할 태그를 지정할 수도 있다.

sanitize("<strong>Safe</strong>\n<b>Dangerous</b>", tags: ['strong'])
=> "<strong>Safe</strong>\nDangerous"

그리고 영리한 공격자를 잡을만큼 똑똑하다. 예를 들어 gsub 메서드는 문자열에서

"<sc<script>ript>".gsub("<script>", "")
=> "<script>"

이렇게 입력을 완전히 보안처리(sanitize) 하지는 못한다.

그러나

sanitize("<sc<script>ript>")
=> "ript&gt;"

보안처리(sanitize) 헬퍼는 가능하다.

코드 주입의 극단적인 예가 XKCD 만화, 어떤 어머니의 위업(Exploits of a mom)에 나온다. 여기서 공격자(엄마)는, 학교가 의심하지 않고 SQL 데이터베이스에 이 쿼리를 입력하면 모든 학생 기록을 삭제한다는 것을 알고 있으면서도, (Little Bobby Tables)라고 부르는 아들 이름을 “ Robert’); DROP TABLE Students; – “라고 지었다. 여기에 더 자세한 설명이 있다. 다행스럽게도 findfind_by 액티브 레코드 메소드는 작은 따옴표, 큰 따옴표, SQL 쿼리의 NULL 문자 및 줄 바꿈을 자동으로 예외 처리(escape)하고, 어머니의 악용을 비활성화한다. 그러나 개발자는 wherefind_by_sql 과 같은 쿼리 메소드에 전달되는 문자열이 있는지 조심해야하며, 이를 직접 보안 처리해야 한다.

세션 쿠키를 이용하여 웹 애플리케이션을 공격하는 다른 방법이 있다. 세션 쿠키는 브라우저가 보내는 각 요청 사이에 데이터를 유지하는 유용한 방법을 제공하므로 ID와 같이 사용자에게 고유한 정보를 기록하는 일반적인 곳이다. 다행히 레일즈는 기본적으로 쿠키를 암호화하므로 secrets.yml 파일에서 secret_key_base 매개 변수 값이 없으면 공격자가 세션 쿠키를 읽거나 변경할 수 없다.

그러나 사용자의 암호화된 세션 쿠키를 보유한 공격자는 사용자로 위장하여 사이트에 액세스 할 수 있는 잠재적인 위협이다. 이는 세션 가로채기(session hijacking)로 알려져 있으며, 사용자가 HTTP 대신 HTTPS로 사이트에 접속하도록 하여 예방할 수 있다. 이는 애플리케이션 config 파일에서 설정할 수 있다.

config.force_ssl = true

그러면 사용자의 세션 쿠키는 (쿠키 암호화 여부와 상관없이) 요청(request)에서 내용을 식별할 수 없으므로 공격자가 세션 쿠키를 찾아내어(sniff) 복사할 수 없다. 이 외에도 공용 컴퓨터에서 웹 애플리케이션에 접근하는 경우 사용자가 세션 쿠키를 지우도록 만드는 것도 중요하다. 가장 쉬운 방법은 앱에 ‘로그 아웃’버튼을 눈에 띄게 표시하고 로그 아웃시에 reset_session을 추가하는 것이다. 만료 시간 역시 세션 컨트롤러를 사용하여 세션 쿠키에 할당 할 수 있다.

class SessionController < ApplicationController
  def login
    if login_successful?
      reset_session
      session[:expires_after] = 1.hour.from_now.to_i
      redirect_to some_page_url and return
    end
    redirect_to new_login_url
  end

  def logout
    reset_session
    redirect_to root_url
  end

  private

  def login_successful?
    # check login is successful
  end
end

그런 다음, 요청이 있을 때마다 세션 만료 여부를 확인한다.

class ApplicationController < ActionController::Base
  before_action :check_session_validity

  private

  def check_session_validity
    unless session[:expires_after] && session[:expires_after] > Time.now.to_i
      redirect_to new_login_url
    end
  end
end

코드 삽입 및 세션 가로채기와 같은 취약성을 이해하고 레일즈가 웹 애플리케이션을 보호하는 방법을 알고 있으면, 웹 애플리케이션의 보안을 신뢰 할 수 있으며 보안 취약점을 수정하는 방법을 찾아 낼 수 있다. 또한, 레일즈는 우리에게 보안 장치의 존재 목적을 알려주고, 비활성화 하는 경우 안전하고 제어 가능한 방법으로 비활성화할 수 있도록 안내한다.

이 글에서는 두 가지 일반적인 웹 보안 취약점에 대해서만 다루었지만 더 많이 배우기 위해서는 레일즈 보안 공식 가이드가 시작하기 좋다. 또한 OWASP (Open Web Application Security Project)는 정기적으로 업데이트되는 레일즈용 치트 시트를 배포 중이며, 루비 온 레일즈 보안 메일링 리스트는 질문하는 좋은 곳이다.

웹 애플리케이션이 손상되지 않도록 레일즈와 함께 사용할 수 있는 도구가 있다. 특히, Brakeman은 레일즈 앱의 취약점을 분석할 수 있는 정적 분석 도구이며 CI 통합 테스트 스위트의 일부로 실행 할 수 있다. SecureHeaders gem은 여러 보안 관련 헤더를 요청 및 응답에 자동으로 적용 할 수 있다. 또한 Cloud Flare는 SQL 인젝션이나 DoS (Denial of Service) 공격과 같은 온라인 위협으로부터 웹 사이트를 보호 할 수 있는 간편한 방법을 제공한다.

안전하고 유익한 목적으로 웹 애플리케이션의 취약점을 이해하고 찾으려는 경우에는 The Matasano Crypto Challenges를 시도해야 한다. Najaf Ali와 함께한 시도와 유사하지만 레일즈에만 국한되지 않는다. Najaf의 워크샵은 웹 보안이 모든 사람들의 일 이라는 것을 깨닫도록 도와 주었지만 루비 온 레일즈를 사용할 때는 상당히 처리하기 쉽다.


npmachine

a mediocre engineer