計(jì)完整清單與自查教程)
從XSS凈化到OAuth登錄Wri.pe安全設(shè)計(jì)完整清單與自查教程【免費(fèi)下載鏈接】open-wripehttps://wri.pe source code項(xiàng)目地址: https://gitcode.com/gh_mirrors/op/open-wripeWri.pe 是一款開源的 Web 個(gè)人筆記應(yīng)用https://wri.pe 的源代碼核心能力包括 Markdown 筆記編輯、多端日歷視圖、頁面分享以及 GitHub、Facebook、Evernote、Dropbox 等第三方登錄與同步。對(duì)于筆記里存著敏感內(nèi)容的產(chǎn)品來說安全設(shè)計(jì)不是可選項(xiàng)。本文帶你用8 個(gè)真實(shí)代碼點(diǎn)完整拆解 Wri.pe 的安全機(jī)制并附一份可直接抄走的自查清單。 Wri.pe 安全設(shè)計(jì)總覽清單先給一張全景表后面逐項(xiàng)展開#安全維度Wri.pe 的做法關(guān)鍵文件1XSS 防護(hù)Markdown 渲染后二次凈化 鏈接協(xié)議白名單app/models/page.rb2前端轉(zhuǎn)義模板統(tǒng)一escape_htmlapp/assets/javascripts/shared/utils.js.coffee3CSRF 防護(hù)protect_from_forgery 失敗降級(jí)處理app/controllers/application_controller.rb4會(huì)話管理session 只存用戶 ID登出即重置app/controllers/sessions_controller.rb5OAuth 登錄GitHub/Facebook 走 OAuth2Evernote 走 OAuth1.0alib/ghauth.rb、lib/evernote_auth.rb6密鑰管理敏感配置獨(dú)立 YAML按環(huán)境加載config/github-sample.yml7數(shù)據(jù)權(quán)限讀/寫/分享三級(jí)權(quán)限越權(quán)返回 403app/models/page.rb8并發(fā)安全lock_version樂觀鎖沖突返回 409app/controllers/pages_controller.rb? 深度一XSS 凈化——先渲染再消毒最后查戶口筆記應(yīng)用最大的風(fēng)險(xiǎn)是用戶輸入 Markdown → 渲染成 HTML → 危險(xiǎn)標(biāo)簽被瀏覽器執(zhí)行。Wri.pe 在 app/models/page.rb 的body_html方法里做了三道防線第一道渲染。用 Redcarpet 把 Markdown 轉(zhuǎn)成 HTML開啟lax_html_blocks等選項(xiàng)支持富文本。第二道凈化。HTML 交給sanitize庫清洗Sanitize.clean(html, Sanitize::Config::RELAXED)依據(jù)白名單移除script、onerror等危險(xiǎn)節(jié)點(diǎn)和屬性依賴聲明在 Gemfile 中升級(jí)時(shí)建議同步關(guān)注安全公告。第三道鏈接協(xié)議白名單。用 Nokogiri 遍歷所有a標(biāo)簽只保留http/https協(xié)議的 href其余比如javascript:alert(1)這種直接被降級(jí)為span并刪掉 href——等于給每個(gè)鏈接查戶口。前端也同步轉(zhuǎn)義JS 模板中拼接用戶數(shù)據(jù)前統(tǒng)一走escape_html底層是 lodash 的_.escape見 app/assets/javascripts/shared/utils.js.coffee例如日歷面板里插入標(biāo)題前先轉(zhuǎn)義# app/assets/javascripts/app/calendar_panel.js.coffee li class\page\a href\\##{escape_html(p.key)}/edit\#{escape_html(p.title)}/a/li 自查要點(diǎn)凡是有用戶輸入 → HTML路徑的地方問自己三個(gè)問題服務(wù)端凈化了嗎白名單是什么前端拼接轉(zhuǎn)義了嗎 深度二CSRF 與會(huì)話——給每個(gè)請(qǐng)求發(fā)防偽貼紙Wri.pe 的控制器全部繼承自 app/controllers/application_controller.rb其中兩處設(shè)計(jì)很值得借鑒全局開啟 CSRF 防護(hù)protect_from_forgery一行代碼所有表單和寫操作都必須攜帶合法 token。失敗的優(yōu)雅降級(jí)handle_unverified_request拋出的InvalidAuthenticityToken被統(tǒng)一攔截——HTML 請(qǐng)求重定向回首頁JSON 請(qǐng)求返回412 Precondition Failed。對(duì)單頁應(yīng)用SPA的 AJAX 調(diào)用特別友好前端能明確感知token 失效并引導(dǎo)重新登錄。會(huì)話本身保持極簡(jiǎn)app/controllers/sessions_controller.rb 中 session 里只存authorized_user_id一個(gè)整數(shù)用戶信息實(shí)時(shí)查庫并校驗(yàn)active?狀態(tài)。登出時(shí)調(diào)用reset_session徹底清空sessions_controller.rb避免 session 固定攻擊。同時(shí)前端每次啟動(dòng)都會(huì)向服務(wù)端拉取最新的csrf_token用于后續(xù) API 請(qǐng)求。 自查要點(diǎn)會(huì)話里是否存了不必要的敏感數(shù)據(jù)token 校驗(yàn)失敗時(shí)接口返回是否能讓前端做正確處理 深度三OAuth 登錄——第三方賬號(hào)的安全接入Wri.pe 支持四種第三方登錄源碼分布清晰服務(wù)協(xié)議授權(quán)模塊回調(diào)控制器GitHubOAuth 2.0lib/ghauth.rbapp/controllers/ghauth_controller.rbFacebookOAuth 2.0lib/fbauth.rbapp/controllers/fbauth_controller.rbEvernoteOAuth 1.0alib/evernote_auth.rbapp/controllers/evernote_auth_controller.rbDropboxOAuth見模型 app/models/dropbox_user.rbapp/controllers/dropbox_auth_controller.rb以 GitHub 為例流程只有兩步app/controllers/ghauth_controller.rb發(fā)起授權(quán)302 跳轉(zhuǎn)到 GitHub 的授權(quán)頁只申請(qǐng)最小權(quán)限scope: user:email——這是 OAuth 安全里最小權(quán)限原則的典型示范回調(diào)換 token拿code換取 access_token驗(yàn)證用戶身份后把user.id寫入 session 并跳轉(zhuǎn)首頁。兩個(gè)細(xì)節(jié)很見功力控制器頂部rescue_from OAuth::Unauthorized授權(quán)異常統(tǒng)一重定向回首頁不會(huì)把堆棧暴露給用戶回調(diào)中的 token 交換用rescue e兜底失敗只記日志 友好提示絕不把 token 或異常細(xì)節(jié)渲染到頁面。密鑰管理是 OAuth 安全的另一半client_id/client_secret放在獨(dú)立 YAML 中且按環(huán)境隔離——倉庫里只提供 config/github-sample.yml、config/evernote-sample.yml 等模板真實(shí)密鑰通過 lib/ghauth.rb 里的YAML.load(...)[Rails.env]按當(dāng)前環(huán)境加載。部署時(shí)替換模板即可模板文件本身不含任何秘密。 自查要點(diǎn)OAuth 權(quán)限范圍是否最小化token 是否只出現(xiàn)在日志和內(nèi)存中密鑰是否隨環(huán)境隔離且模板入庫 深度四數(shù)據(jù)權(quán)限與并發(fā)——最后一道門即使前面全部做對(duì)誰能看什么也不能失守。Wri.pe 在 app/models/page.rb 定義了三級(jí)權(quán)限permit_read?本人、公開頁SHARE_URL或被授權(quán)的協(xié)作者可讀permit_write?/permit_share?本人或顯式授予寫/分享權(quán)限的用戶??刂破骼?app/controllers/pages_controller.rb 的show/update/destroy都在第一行就檢查權(quán)限越權(quán)直接403 Forbidden先鑒權(quán)再干活。并發(fā)安全方面頁面表帶lock_version字段樂觀鎖更新時(shí)若客戶端提交的版本號(hào)落后于服務(wù)端app/controllers/pages_controller.rb直接返回409 Conflict而不是盲目覆蓋——多人協(xié)作場(chǎng)景下避免后寫覆蓋先寫的數(shù)據(jù)丟失。另外用戶的備份導(dǎo)出鏈接靠創(chuàng)建時(shí)隨機(jī)生成的 96 位export-key保護(hù)app/models/user.rb相當(dāng)于URL 即憑證無法被枚舉猜測(cè)。? 安全自查教程5 問清單可直接套用到你的項(xiàng)目XSS所有用戶輸入 → HTML的路徑服務(wù)端有白名單凈化嗎前端拼接有統(tǒng)一轉(zhuǎn)義函數(shù)嗎參考body_html的三道防線CSRF全局開了 forgery 防護(hù)嗎t(yī)oken 失效時(shí)接口返回能驅(qū)動(dòng)前端重新登錄嗎會(huì)話session 里存的最小化嗎登出是否reset_session用戶狀態(tài)失效后舊會(huì)話是否立刻作廢OAuthscope 最小化了嗎異常路徑會(huì)不會(huì)泄露 token/堆棧密鑰是否入庫權(quán)限與并發(fā)每個(gè)數(shù)據(jù)接口第一行是鑒權(quán)嗎寫操作有版本號(hào)或等價(jià)機(jī)制嗎 延伸閱讀核心模塊路徑數(shù)據(jù)模型與凈化邏輯app/models/page.rb權(quán)限與會(huì)話基類app/controllers/application_controller.rb頁面接口鑒權(quán)/樂觀鎖app/controllers/pages_controller.rbOAuth 模塊lib/ghauth.rb、lib/fbauth.rb、lib/evernote_auth.rb會(huì)話管理app/controllers/sessions_controller.rb依賴聲明Gemfile登錄功能測(cè)試spec/features/Wri.pe 的安全設(shè)計(jì)沒有炫技全是小步到位凈化用白名單、授權(quán)用最小 scope、鑒權(quán)放在接口第一行、密鑰按環(huán)境隔離。這正是開源項(xiàng)目最值得新手抄作業(yè)的地方——每一條防護(hù)都有對(duì)應(yīng)的具體代碼可以對(duì)照學(xué)習(xí)?!久赓M(fèi)下載鏈接】open-wripehttps://wri.pe source code項(xiàng)目地址: https://gitcode.com/gh_mirrors/op/open-wripe創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考