over 4 years ago

上篇: Secure Your Application : The Basic (2)


5. bypass HTML Escape

Rails 預設對所有 helper 出來的字串,先都過了一層 html escape。所以是相當安全的。

def render_post_title(post)
  link_to(post.title, post_path(post))
end

但是,在開發者設計一些複雜的元件時,通常會不小心打破這個原則。如美術設計師對該元素下了複雜的 HTML,程式設計師為了貪方便可能就會這樣串接,最後再下一個 raw / html_safe ...

def render_post_title(post)
  str = “”
  str += <li>
  str += link_to(post.title, post_path(post))
  str += </li>”
  return raw(str) 
end

原來那層天然防護罩就不見了。

網站上哪一些設計容易有這種問題:

  • 列表 list
  • 麵包屑 breadcrumb
  • user name with glyphicons

解法:

回歸最初,該是 HTML 的就不要用 helper,用 partial

def render_post_title(post)
  render :partial => "posts/title_for_helper", :locals => { :title => post.title }
end

也可能有問題的地方:TinyMCE on UGC

有些網站被迫要讓使用者使用 TinyMCE 這種所見即所得的工具。但是這種工具危險之處,在於裡面塞的 HTML 可以非常的有創意...如:

  • img
  • table
  • tbody
  • div
  • span

都是高危險地帶。

可能的解法:

Rails 提供消毒 Helper。可以設白名單黑名單..

def s(html)
  sanitize( html, :tags => %w(table thead tbody tr td th ol ul li div span font
   img sup sub br hr a pre p h1 h2 h3 h4 h5 h6),
   :attributes => %w(style src href size color) )
end

6.bypass SQL escape

Rails 在 ORM 裡面也預設提供 SQL escpe,所以這種 query 是安全的:

  User.where([name LIKE ?”, params[:q])
  # safe

但是有些時候,開發者為了實作某些功能,就會不小心用了 find_by_sql

  User.find_by_sql("name LIKE &rsquo;%#{params[:q]}%&rsquo;")
  # not safe

或者是開發者根本就不知道 where 的正確用法,在網路上 google 到一個 sample 會動就丟進去了:

  User.where("email = '#{params[:email]}'").first 
  # won't escape

高危險地帶:

  • Search Functions
  • actions with complex options, ex. :date, :order, :field
  • actions with complex joins
  • find_by_sql, count_by_sql

解法

  • 如果只是搜尋的話,可以改用 ransack 這種 gem,可以用相當漂亮的 DSL 設計出複雜的 SQL search,都沒有 SQL Injection 問題..

  • 設計 Application 時,優先使用 ORM 解,非不得已為了效能才手 drop query

延伸資料


下篇: Secure Your Application : The Basic (4)

← Secure Your Application : The Basic (2) Secure Your Application : The Basic (4) →
 
comments powered by Disqus