HTTP 無狀態,Session 通過 session_id(32 字符 MD5)在 Cookie 中維持狀態。Rails 默認 CookieStore(客戶端存儲,Base64 編碼 + HMAC 簽名)或 ActiveRecord::SessionStore(服務端存儲)。
| 攻擊 | 描述 | 對策 |
|---|---|---|
| 側傾監聽 | 公共 WiFi 竊取明文 Cookie | 強制 HTTPS:config.force_ssl = true (Rails 3.1+) |
| 公共終端殘留 | 用戶未登出直接離開 | 顯眼的「登出」按鈕,敏感操作要求重新認證 |
| XSS 竊取 Cookie | 惡意腳本讀取 document.cookie | HttpOnly Cookie(Rails 默認開啟),嚴格輸出轉義 |
| Session Fixation | 攻擊者預設 Session ID,誘導受害者登入 | 登入後重置 Session:reset_session 或 session[:user_id] = user.id 觸發新 ID 生成 |
| Session Replay (CookieStore) | 重放舊 Cookie 恢復舊狀態(如購物車金額) | 關鍵狀態存服務端(DB/Redis),Cookie 僅存標識符 |
config.secret_key_base ≥ 30 字符隨機串)。受害者登入目標站點 → 訪問惡意頁面 → 頁面自動提交表單/發起 AJAX 到目標站點 → 瀏覽器攜帶 Cookie 發送請求 → 服務端執行破壞操作(刪除、轉賬、改密)。

protect_from_forgery with: :exception(默認已開啟)。表單自動嵌入 csrf-token,AJAX 需在 Header 傳遞 X-CSRF-Token。rescue_from ActionController::InvalidAuthenticityToken, with: :handle_invalid_token。| 風險 | 示例 | 防禦 |
|---|---|---|
| 路徑遍歷 | 文件名 ../../../etc/passwd | 白名單校驗文件名(僅允許 [a-zA-Z0-9._-]),重命名存儲(UUID + 原擴展名) |
| 腳本執行 | 上傳 shell.php 訪問執行 | 上傳目錄禁用執行權限(Nginx location /uploads { disable_functions ... }),存放於 Web 根目錄外 |
| 類型偽裝 | 惡意 exe 改名為 image.jpg | 雙重驗證:content_type + 文件魔數(file 命令/mimemagic gem) |
| DoS 攻擊 | 併發上傳大文件耗盡磁盤/內存 | 異步處理(ActiveJob),限制單文件大小、併發數、用戶配額 |
def create
uploaded = params[:post][:picture]
return head :bad_request unless uploaded
# 1. 類型白名單
allowed_types = %w[image/jpeg image/png image/gif application/pdf]
return head :unsupported_media_type unless allowed_types.include?(uploaded.content_type)
# 2. 魔數二次驗證
return head :unsupported_media_type unless valid_magic_number?(uploaded)
# 3. 安全存儲
ext = File.extname(uploaded.original_filename).downcase
safe_name = "#{SecureRandom.uuid}#{ext}"
store_path = Rails.root.join('storage', 'uploads', safe_name)
FileUtils.mkdir_p(File.dirname(store_path))
File.open(store_path, 'wb') { |f| f.write(uploaded.read) } # 關鍵:wb 二進制模式
# 4. 記錄元數據
@post.picture = safe_name
@post.save!
end
id, logical_name, physical_path 映射,下載時通過 ID 查找物理路徑。send_file 時絕不拼接用戶輸入:send_file(@document.physical_path, filename: @document.logical_name)。X-Sendfile/X-Accel-Redirect 交給 Nginx/Apache 發送,釋放 Rails 進程。參數 redirect_to params[:url] 可導向釣魚網站。白名單校驗:
ALLOWED_HOSTS = %w[example.com partner.com].freeze
def safe_redirect
url = params[:redirect_url]
if url.present? && ALLOWED_HOSTS.any? { |host| url.start_with?("https://#{host}") }
redirect_to url
else
redirect_to root_path
end
end
Rails ActiveRecord 參數化查詢默認安全:
# 安全
User.where("email = ?", params[:email])
User.where(email: params[:email])
# 危險:字符串拼接
User.where("email = '#{params[:email]}'") # ❌ 永不使用
避免 system/`/%x 拼接用戶輸入。必須使用 Shellwords.escape 或 Open3.popen3 參數化調用。
Rails 提供了強大的內建防護(CSRF Token、參數化查詢、HttpOnly Cookie、強制 SSL),但開發者必須:
bundle audit、brakeman 靜態掃描、訂閱 Rails Security 郵件列表)。安全無絕對,唯有纏鬥到底。