Rails4-4 Strong Parameters, Authenticity Token, Filters, Sessions, Flash
Overview
이번 포스트는 attr_accesibles같은 파라미터 엑세서 변경, filters, 세션 보안강화, 커스텀 플래시에 대한 이야기입니다.
Strong parameters
<form action="/users" method="post">
<p>
<input id="name" name="name" type="name" />
</p>
<p>
<input name="commit" type="submit" value="Save" />
<input name="admin" type="hidden" value="1" />
</p>
</form>
만약 핵커가 다음과 같이 input을 추가 한다음, submit 을 때리면 어떻게 될까요? 만약 admin 필드가 boolean타입으로 되어 있었다면 admin권한을 가진 사용자 하나가 추가되면서... ㅠ.ㅠ. 이런것을 방지하기위해 whitelisting이라고 하는데 기존에 Rails3에서는 이 작업의 책임이 Model에서 했었죠? 다음 코드에서 보시것과 같이요.
# File name : models/user.rb
class User < ActiveRecord::Base
attr_accessible :name
end
#File name : controllers/users_controller.rb
def update
if @user.update_attributes(params[:user])
redirect_to @user, notice: 'Updated'
else
render action: 'edit'
end
end
이렇게 하면 attr_accessible로 선언된 필드를 제외한 필드에 대해서 업데이트나 인서트를 하려고 하면 모델에서 이를 ActiveMode::MassAssignmentsSecurity::Error를 발생시키면서 이를 막아줍니다.
그러나 Rails4에서 이 whitelisting parameter기능이 모델에서 컨트롤러로 넘어왔습니다.
이제 모델에서는 아무것도 하지 않고 컨트롤러에서 다음과 같이 적어주면 됩니다.
# File name : controllers/user_controller.rb
def update
# attr_accessiable :name과 동일
user_params = params.require(:user).permit(:name)
if @user.update_attributes(user_params)
redirect_to @user, notice: 'Updated'
else
render action: 'edit'
end
end
이렇게 하면 사용자가 admin이라는 파라미터를 날려도 #permit메소드가 알아서 이를 지워버리고 name이라는 필드만 넘겨주게 됩니다.
#permit메소드는 디폴트로 파라미터의 타입도 같이 체크 해주는데요. 다음이 허용되는 파라미터 타입들입니다.
- String
- Symbol
- NilClass
- Numeric
- TrueClass, FalseClass
- Date, Time, DateTime
- StringIO, IO
- ActionDispatch::Http::UploadFile, Rack::Test::UploadFile
디폴트 이렇게 걸러진 파리미터들은 다 로깅이 되는데요. 로깅되는것 뿐만 아니라 exception까지 발생 시키고 싶으시다면,
# File name : config/application.rb
config.action_controller.action_on_unpermitted_parameters = :raise
이렇게 설정해 주시면 됩니다.
Rails4에서 계속해서 attr_accessible을 사용하고 싶으시다면 protected_attributes젬을 이용하세요
Rails4로 업그레이드하지 않고 Strong Parameters을 사용하려고 하시거나, 좀 더 자세한 기능을 확인하고 싶으신 분은 [여기 클릭]
Authenticity Token
Rails에서는 기본적으로 모든 폼에 Authenticity_token이라는 히든 필드가 추가 됩니다.(form helper을 사용했을경우)
<form id='edit_user_1' . . .>
<input name="authenticity_token" type="hidden" value="y2GIknkh...=" />
....
</form>
그래서 확인되지 않은 인증 토큰이 오면 세션을 지워버리고 세션을 리셋해버리고 경고를 로깅합니다.
WARNING: Can't verify CSRF token authenticity
Rails4에서는 이 동작에 대해서 좀 더 커스터 마이징할 수 있는 기능이 추가 됐습니다.
# File name : controllers/applcation.rb
# 인증되지 않은 토큰이 오면 exception발생 default
protect_from_forgery with: :exception
# 인증되지 않은 토큰이 오면 세션을 비워버림
protect_from_forgery with: :null_session
# 인증되지 않은 토큰이 오면 이전 세션을 지워버리고 새 새션 만들기
protect_from_forgery with: :reset_session
Filters/Actions
기존에 컨트롤러에서 before_filter많이 쓰셨죠. 그런데 생각해보니.. 이건 실제로 아무것도 filtering하고 있지 않다는 것을 깨닫고 새로운 이름을 주었답니다. action이라고요. 그래서 이제 Rails4에서는 Filter라고 쓸 수 도 있지만, Action이라고 하셔도 됩니다.
Cookie Based Session Store
Rails에서는 세션 정보를 로컬에 있는 쿠키에 저장합니다.
이 값은 사용자가 수정하지는 못하지만, 읽을 수 있었습니다. 그리고 루비를 이용해 이 값을 까 볼 수 조차 있죠.
require 'rack'
cookie = 'daf1b24...'
Rack::Session::Cookie::Base64::Marshal.new.decode(cookie)
=> {"session_id"=> "adfadf98ad8fea8dfa908d7", "user_id"=>"123", "_csrf_token_"=>"2adsfliji231212plfaRE" }
Rails4에서는 여기서 암호화하는 기능을 추가 해서 위 코드와 같이 decode를 해도 nil만 리턴 됩니다. Rails4에서는 key를 기준으로 이를 암호화 하게 됩니다. 이 키는 다음과 같이 설정됩니다.
# File name : config/initializers/secret_token.rb
MyApp::Application.config.secret_key_base = '123123123123'
그런데 이 상태로 Github같은데 올리면 공개되어 버리겠죠? 그럴때는 되도록
MyApp::Application.config.secret_key_base = ENV['SECRET_KEY_BASE']
이런 식으로 환경 변수로 숨겨 두시는게 좋겠죠?
Flash
Flash는 컨트롤러에서 값을 주면 view로 넘어가서 사용자에게 메시지를 전달할 때 사용하죠.
# File name : controllers/users_controller.rb
if @item.save
flash[:notice] = "User Saved"
redirect_to @item
end
이제 뷰에서
# File name : views/items/show.html.erb
<p id="notice"><%= flash[:notice] %></p>
실제 html에서는
# HTML
<p id="notice">Item_created </p>
그리고, 뷰에서 간편하게
<%= notice %>
<%= alert %>
이렇게도 사용가능합니다. 그런데 이건 이미 등록된 flash type에 대해서만 이런 키워드를 사용할 수 있었습니다. 이제 Rails4에서는 이런 Flash Type을 새로 정의 해서 사용할 수 있게 되었습니다. 사용법도 간단합니다. 컨트롤러 상단에 add_flash_types 키워드를 이용해서 선언해 주면 기존 notice나 alert처럼 자유롭게 쓸 수 있습니다.^^
# File name : controllers/application_controller.rb
class ApplicationController < ActionController::Base
add_flash_types :new_type, :nice
end
이번 포스트는 Rails4로 바뀌면서 강화된 전반적인 보안 강화에 관한 이야기였네요. 그럼 다음 포스트에서는 Rails4에서 강화된 View에 대해서 알아 보겠습니다.