摘要:瀏覽器的同源策略并不能夠避免來(lái)自于惡意站點(diǎn)的提交。為了保證輸入數(shù)據(jù)的完整性,服務(wù)器端務(wù)必要進(jìn)行數(shù)據(jù)校驗(yàn)。輸入驗(yàn)證即是保證實(shí)際輸入與應(yīng)用預(yù)期的輸入的一致性。因此驗(yàn)證輸入時(shí)保證系統(tǒng)安全性與防衛(wèi)危險(xiǎn)的第一道防線。
Github Repo:https://github.com/wxyyxc1992/infosecurity-handbook/blob/master/Reinforce/WebSecurity/basics-of-web-application-security.md
原文:The Basics of Web Application Security
現(xiàn)代的軟件開發(fā)者已經(jīng)有點(diǎn)像瑞士軍刀了,首先,你需要來(lái)保證完成用戶的功能或者業(yè)務(wù)需求,并且要保證又快又好地完成。其次,你希望你的代碼能夠擁有充分的可理解性或者可擴(kuò)展性:能夠隨著IT需求的快速變遷而有著充分的擴(kuò)展空間,與此同時(shí)還需要穩(wěn)定與可用。開發(fā)者必須列舉出有用的接口,優(yōu)化數(shù)據(jù)庫(kù),以及頻繁地建立或者維護(hù)一個(gè)交付渠道。不過(guò),當(dāng)我們審視這長(zhǎng)長(zhǎng)的需求列表的時(shí)候,在快速、低成本以及靈活可擴(kuò)展之下的,即是安全性?;蛟S直到一些東西出了問(wèn)題,或者你構(gòu)建的系統(tǒng)被攻擊了之后才能深刻感受到安全才是最重要的。安全這個(gè)概念有點(diǎn)像性能,是個(gè)泛化的跨越了多個(gè)領(lǐng)域的概念。所以一個(gè)開發(fā)者怎么才能在模糊的安全需求與未知的風(fēng)險(xiǎn)面前選擇合適的開發(fā)規(guī)劃呢?當(dāng)然如果能夠明確這些安全需求與定位到威脅的話毫無(wú)疑問(wèn)非常值得推薦,但是這個(gè)準(zhǔn)備本身就需要耗費(fèi)大量的時(shí)間與金錢。
Trust(信賴)首先,在討論具體的輸入輸出之前,我們需要來(lái)強(qiáng)調(diào)下自認(rèn)為安全中最重要也是最根本的原則:Trust。作為一個(gè)開發(fā)者,也需要不斷地問(wèn)自己,我們相信來(lái)自于用戶瀏覽器的請(qǐng)求嗎?我們相信上游系統(tǒng)正常工作來(lái)保證了我們數(shù)據(jù)的干凈與安全嗎?我們相信服務(wù)器與瀏覽器之間的信道就不會(huì)被監(jiān)聽或者偽造嗎?我們相信我們系統(tǒng)本身依賴的服務(wù)或者數(shù)據(jù)存儲(chǔ)嗎?呵呵,都不可信。
當(dāng)然,就像安全一樣,Trust也不是一個(gè)雙選題,非黑即白。我們需要明白系統(tǒng)的風(fēng)險(xiǎn)忍受力與數(shù)據(jù)的安全邊界。為了能夠正確的、基于某個(gè)統(tǒng)一規(guī)則的預(yù)估,我們需要審視威脅與風(fēng)險(xiǎn),這個(gè)評(píng)估方法與標(biāo)準(zhǔn)會(huì)在另一篇文章中講解。
Reject Unexpected Form Input(拒絕未知的表單輸入)HTML表單本身就可能帶來(lái)些好像很安全的錯(cuò)覺(jué),表單的構(gòu)建者肯定覺(jué)得他們限制了輸入類型、做了數(shù)據(jù)校驗(yàn),這樣整個(gè)表單輸入就是安全的。但確信無(wú)疑的是,這只是個(gè)錯(cuò)覺(jué),盡管客戶端地JavaScript腳本可以從安全地角度來(lái)說(shuō)提供完整的校驗(yàn)。
Untrusted Input無(wú)論我們是否在客戶端提供了表單驗(yàn)證或者是否使用了HTTPs連接,我們能夠信賴來(lái)自用戶瀏覽器的連接的比例都是0。用戶可以輕易地在發(fā)送之前修改標(biāo)記,或者使用類似于curl這樣的命令行來(lái)提交沒(méi)有經(jīng)過(guò)校驗(yàn)的數(shù)據(jù)。乃至于一個(gè)不明所以的用戶可能在一個(gè)懷有惡意的網(wǎng)站莫名其妙地添了些內(nèi)容。瀏覽器的同源策略并不能夠避免來(lái)自于惡意站點(diǎn)的提交。為了保證輸入數(shù)據(jù)的完整性,服務(wù)器端務(wù)必要進(jìn)行數(shù)據(jù)校驗(yàn)。
不過(guò)估計(jì)有人有疑問(wèn)了,為啥說(shuō)這個(gè)畸形的數(shù)據(jù)就會(huì)導(dǎo)致安全問(wèn)題呢?這往往取決于你的應(yīng)用業(yè)務(wù)邏輯與輸出的編碼,為了避免不可預(yù)知的行為、數(shù)據(jù)泄露與潛在攻擊,需要在輸入的數(shù)據(jù)與可執(zhí)行代碼之間架構(gòu)一個(gè)過(guò)濾層。譬如,我們的表單里有一個(gè)選擇的按鈕來(lái)允許用戶選擇合適的通信類型,我們的業(yè)務(wù)邏輯代碼可能是這樣的:
final String communicationType = req.getParameter("communicationType"); if ("email".equals(communicationType)) { sendByEmail(); } else if ("text".equals(communicationType)) { sendByText(); } else { sendError(resp, format("Can"t send by type %s", communicationType)); }
上面代碼危不危險(xiǎn)取決于sendError這個(gè)方法是怎么定義的,而我們肯定無(wú)法確定下游的代碼就一定是安全的。最好的選擇就是我們?cè)诳刂屏髦幸瞥@個(gè)危險(xiǎn),而使用的方法就是輸入驗(yàn)證。
Input Validation輸入驗(yàn)證即是保證實(shí)際輸入與應(yīng)用預(yù)期的輸入的一致性。超出預(yù)期的輸入數(shù)據(jù)會(huì)導(dǎo)致我們系統(tǒng)拋出未知的結(jié)果,譬如邏輯崩壞、觸發(fā)錯(cuò)誤乃至于允許攻擊者控制系統(tǒng)的一部分。其中像數(shù)據(jù)庫(kù)查詢這樣的能夠在服務(wù)端作為可執(zhí)行代碼的輸入與JavaScript這樣在客戶端能夠被執(zhí)行的代碼更是特別的危險(xiǎn)。因此驗(yàn)證輸入時(shí)保證系統(tǒng)安全性與防衛(wèi)危險(xiǎn)的第一道防線。
開發(fā)者們?cè)跇?gòu)建應(yīng)用系統(tǒng)的過(guò)程中會(huì)進(jìn)行一些基本的驗(yàn)證,譬如判斷值是否為空或者是否為正數(shù)。而從安全的角度考慮,我們需要將輸入限定到系統(tǒng)允許的最小集合中,譬如數(shù)值型值可以被限定在某個(gè)特定的范圍內(nèi)。譬如,系統(tǒng)不會(huì)允許用戶將一個(gè)負(fù)值添加到購(gòu)物車中。這種限制性的驗(yàn)證手段就是所謂的positive validation或者whitelisting。一個(gè)白名單可以用于限定某個(gè)具體的URL或者yyyy/mm/dd這樣的時(shí)間日期。它可以限制輸入的長(zhǎng)度、單個(gè)字符的編碼規(guī)范或者上面例子中的只有給定值可以被接受。
另外一種考慮輸入驗(yàn)證的思維角度就是把它當(dāng)做服務(wù)端與消費(fèi)者之間簽訂的一種協(xié)議,任何違背了這個(gè)協(xié)議的請(qǐng)求都是無(wú)效的并且被拒絕。你的這個(gè)協(xié)議越嚴(yán)格,你的系統(tǒng)在未知情況下遭受的風(fēng)險(xiǎn)就會(huì)越小。而當(dāng)對(duì)于某個(gè)輸入驗(yàn)證失敗之后,開發(fā)者也要好好考慮應(yīng)該如何反饋。最嚴(yán)格,也是最有爭(zhēng)議的辦法就是全部拒絕,并且沒(méi)有任何反饋,不過(guò)要注意將這個(gè)事情通過(guò)日志或者監(jiān)控記錄下來(lái)。不過(guò)為啥一點(diǎn)反饋都沒(méi)有呢?我們需要提供給用戶哪些信息是無(wú)效的嗎?這一點(diǎn)還是要取決于你的約定。在上面的例子中,如果你接收到了除了email或者text之外的內(nèi)容,那你有可能被攻擊了。不過(guò)如果你進(jìn)行了反饋,可能正中全套。譬如如果開發(fā)者直接返回:俺們并不認(rèn)識(shí)你傳入的communicationType,可能這個(gè)還無(wú)傷大雅,但是如果是這樣的呢:
這種情況下你就會(huì)面臨一個(gè)用來(lái)盜取你的Cookies的XSS攻擊代碼,如果你一定要給用戶反饋,你必須保證不會(huì)把不受信任的用戶內(nèi)容直接返回,而應(yīng)該使用固定的提示信息。如果你不可避免地要把用戶的輸入反饋回去,你要保證它是被編碼的。
In Practice實(shí)踐中,我們經(jīng)常要通過(guò)過(guò)濾標(biāo)簽來(lái)避免一些攻擊,過(guò)濾掉這些包含著危險(xiǎn)值的輸入的方法就是所謂的negative validation 或者blacklisting。不過(guò)這種方法的麻煩之處在于潛在的危險(xiǎn)輸入是相當(dāng)多的,很多時(shí)候不能勝數(shù)。維持一個(gè)龐大的危險(xiǎn)輸入的列表可能是耗費(fèi)較大的操作,這需要進(jìn)行頻繁地更新。如果你真的需要一個(gè)黑名單,這就需要覆蓋你所有的測(cè)試用例,編寫高質(zhì)量的測(cè)試代碼,遵循OWASP的XSS_Filter_Evasion_Cheat_Sheet原則。
對(duì)于危險(xiǎn)輸入的過(guò)濾,我們常常稱之為sanitization,即是在輸入中移除那些黑名單中的元素而不是直接拒絕。不過(guò)這種黑名單機(jī)制,很難保證完全正確,往往也會(huì)給攻擊者更多地漏洞機(jī)會(huì)。譬如,在上面的例子中,我們是選擇移除標(biāo)簽,而一個(gè)攻擊者可以通過(guò)輸入下面這樣的字符串來(lái)逃避檢查:
ipt>
在現(xiàn)代的Web應(yīng)用程序開發(fā)中,已經(jīng)有很多現(xiàn)成的框架提供了基礎(chǔ)的過(guò)濾功能。內(nèi)建的對(duì)于郵件地址、信用卡號(hào)碼等等過(guò)濾還是灰常好用的,使用這些網(wǎng)絡(luò)框架提供的驗(yàn)證機(jī)制可以有效避免一些嚴(yán)重的錯(cuò)誤,譬如:
Framework | Approaches |
---|---|
Java | Hibernate (Bean Validation) |
ESAPI | |
Spring | Built-in type safe params in Controller |
Built-in Validator interface (Bean Validation) | |
Ruby on Rails | Built-in Active Record Validators |
ASP.NET | Built-in Validation (see BaseValidator) |
Play | Built-in Validator |
Generic JavaScript | xss-filters |
NodeJS | validator-js |
General | Regex-based validation on application inputs |
盡可能地使用白名單
在不能用白名單的時(shí)候用黑名單
盡可能地使用嚴(yán)格約定
確保警示潛在的攻擊
避免直接地輸入反饋
盡可能地在不可信數(shù)據(jù)深入系統(tǒng)邏輯之前進(jìn)行處理,或者直接使用你的框架的白名單機(jī)制
Encode HTML Output:HTML輸出內(nèi)容編碼除了上述所說(shuō)的對(duì)于輸入的過(guò)濾與限制之外,Web應(yīng)用的開發(fā)者還需要關(guān)注返回的數(shù)據(jù)。一個(gè)現(xiàn)代的Web應(yīng)用往往會(huì)用HTML標(biāo)記來(lái)構(gòu)建文檔結(jié)構(gòu),用CSS來(lái)構(gòu)建文檔樣式,JavaScript來(lái)構(gòu)建應(yīng)用邏輯。一個(gè)HTML文檔通常使用像或者這樣的標(biāo)記來(lái)進(jìn)行切割。用戶可能在沒(méi)料到的地方使用尖括號(hào),特別是在一個(gè)可執(zhí)行的上下文中附著一些特定內(nèi)容,譬如HTML與JavaScript都會(huì)包含URL,只不過(guò)它們各有各的處理方法。
Output RisksHTML本身是一個(gè)非常非常寬松自由的格式,瀏覽器會(huì)盡可能地來(lái)渲染內(nèi)容,即使發(fā)現(xiàn)了些格式錯(cuò)誤。這一點(diǎn)對(duì)于開發(fā)者非常友好,不過(guò)這也是一個(gè)很大的漏洞的源泉。攻擊者可能在向你的頁(yè)面中注入一些內(nèi)容來(lái)打破可執(zhí)行的上下文,甚至不需要考慮整個(gè)頁(yè)面是否有效。處理輸出內(nèi)容并不一定是安全地考慮,應(yīng)用從數(shù)據(jù)庫(kù)與上游服務(wù)中獲取的渲染數(shù)據(jù)務(wù)必保證不會(huì)影響到整個(gè)應(yīng)用,不過(guò)從不可信的數(shù)據(jù)源得到的渲染內(nèi)容還是會(huì)存在很大的風(fēng)險(xiǎn)。就如上文所說(shuō)的,開發(fā)者應(yīng)該拒絕那些超出約定的輸入,不過(guò)有時(shí)候我們不可避免的需要接收像尖括號(hào)那樣的可能更改我們的代碼的內(nèi)容,這也就是下面所說(shuō)的output encoding所需要起作用的地方。
Output Encoding輸出編碼即是將輸出的數(shù)據(jù)流轉(zhuǎn)化為最終的輸出的格式,輸出編碼的難點(diǎn)或者復(fù)雜的地方在于需要根據(jù)輸出數(shù)據(jù)流向的不同選定不同的編碼方式。如果沒(méi)有合適的編碼方式,應(yīng)用可能會(huì)給客戶端提供一個(gè)錯(cuò)誤格式的數(shù)據(jù),導(dǎo)致輸出數(shù)據(jù)不可用乃至于存在一定風(fēng)險(xiǎn)。攻擊者往往會(huì)利用錯(cuò)誤的編碼方式中的漏洞使得整個(gè)輸出數(shù)據(jù)的結(jié)構(gòu)失控。譬如在我們的電商系統(tǒng)中有個(gè)用戶叫做Sandra Day O"Connor,系統(tǒng)會(huì)在該用戶登錄的時(shí)候輸出一個(gè)歡迎辭,那么當(dāng)她的名字渲染到HTML頁(yè)面上的時(shí)候,效果大概是這樣的:
The Honorable Justice Sandra Day O"Connor
The Honorable Justice Sandra Day O"Connor
開發(fā)者期望的正是這樣渲染得出的界面,不過(guò)如果我們是基于MVC架構(gòu)開發(fā)出了一個(gè)動(dòng)態(tài)網(wǎng)頁(yè),名字會(huì)通過(guò)JS腳本動(dòng)態(tài)地插入到頁(yè)面中,示例代碼如下:
document.getElementById("name").innerText = "Sandra Day O"Connor" //<--unescaped string
而這樣的代碼正是攻擊者們孜孜不倦尋找的漏洞點(diǎn)來(lái)執(zhí)行他們的自定義代碼,如果另一個(gè)用戶Chief Justice這樣的輸入他的名字:
Sandra Day O";window.location="http://evil.martinfowler.com/";
那么所有看到他名字頁(yè)面的用戶都會(huì)被重定向到一個(gè)危險(xiǎn)的站點(diǎn),而如果我們應(yīng)用正確地在這個(gè)JS上下文中進(jìn)行了編碼,整個(gè)編碼之后的文本如下所示:
"Sandra Day O";window.location="http://evil.martinfowler.com/";"
那么整個(gè)文本雖然看上去有點(diǎn)雜亂,但是已經(jīng)變成了沒(méi)有任何危害的不可執(zhí)行的代碼。一般來(lái)說(shuō)我們有很多種方式可以來(lái)對(duì)JS進(jìn)行編碼,最常見的就是使用轉(zhuǎn)義字符。
好消息是絕大部分現(xiàn)代Web框架都提供了將內(nèi)容安全編碼與過(guò)濾保留字符的功能。不過(guò)大部分開發(fā)者會(huì)忽略乃至于主動(dòng)關(guān)閉這種過(guò)濾編碼功能從而去執(zhí)行他們自認(rèn)為的安全的可執(zhí)行代碼。
Cautions and Caveats關(guān)于輸出編碼這部分還有幾個(gè)需要了解的地方,重要的事情多強(qiáng)調(diào)幾遍,一定要選擇一個(gè)自帶編碼功能的框架。另外還需要注意的是,盡管一個(gè)框架可以安全地渲染HTML,也不代表他可以安全地渲染PDF或者JavaScript。
另一個(gè)我們?cè)趹?yīng)用開發(fā)過(guò)程中經(jīng)常遇到的情況,就是很多開發(fā)者習(xí)慣在獲取用戶的原始輸入后進(jìn)行編碼然后存入數(shù)據(jù)庫(kù)中。譬如如果你在將數(shù)據(jù)入庫(kù)之前就把純文本格式的數(shù)據(jù)編碼成HTML格式,然后在需要渲染成其他格式的地方還需要先把HTML反編碼然后再編譯成其他格式。這無(wú)端會(huì)增加很多復(fù)雜性和額外的工作,因此最好直接以原始數(shù)據(jù)格式存入到數(shù)據(jù)庫(kù)中,然后在渲染時(shí)在將它們進(jìn)行編碼。
In Summary以合適的編碼手段對(duì)所有從應(yīng)用中吐出的數(shù)據(jù)進(jìn)行編碼
盡可能地使用框架提供的輸出編碼功能
盡量避免嵌入式渲染上下文
以原始格式存放數(shù)據(jù),在渲染時(shí)進(jìn)行編碼
避免使用不安全的框架與規(guī)避了編碼的JS調(diào)用
Bind Parameters for Database Queries不管你是用SQL在一個(gè)關(guān)系型數(shù)據(jù)庫(kù)中進(jìn)行查詢,還是用ORM框架,或者直接使用一個(gè)NoSQL數(shù)據(jù)庫(kù),你都需要考慮到怎么把用戶輸入的數(shù)據(jù)集成進(jìn)你的查詢語(yǔ)句中。數(shù)據(jù)庫(kù)可能是一個(gè)Web應(yīng)用程序中最關(guān)鍵與緊要的部分,因?yàn)樗娣帕舜罅康臒o(wú)法重現(xiàn)的狀態(tài)數(shù)據(jù)。譬如一個(gè)數(shù)據(jù)庫(kù)中可能存放著大量的關(guān)鍵的與敏感的客戶信息,也正是這些數(shù)據(jù)驅(qū)動(dòng)著整個(gè)應(yīng)用與邏輯的運(yùn)行。因此你肯定希望開發(fā)者在和數(shù)據(jù)庫(kù)打交道的時(shí)候要慎之又慎,不過(guò)數(shù)據(jù)庫(kù)注入攻擊還是很盛行啊。
Little Bobby Tables很多關(guān)于數(shù)據(jù)庫(kù)中參數(shù)綁定的討論都會(huì)包含著名的2007年的Little Bobby Tables事件,這個(gè)事件可以用一個(gè)漫畫描述如下:
為了便于分析這個(gè)漫畫所要表達(dá)的含義,我們假設(shè)這個(gè)成績(jī)追蹤系統(tǒng)有一個(gè)用于增加新的學(xué)生信息的函數(shù):
void addStudent(String lastName, String firstName) { String query = "INSERT INTO students (last_name, first_name) VALUES ("" + lastName + "", "" + firstName + "")"; getConnection().createStatement().execute(query); }
如果輸入的參數(shù)是"Fowler"與"Martin",那么最終構(gòu)造出的SQL語(yǔ)句為:
INSERT INTO students (last_name, first_name) VALUES ("Fowler", "Martin")
不過(guò)如果輸入的是上面那娃的名字,那么整個(gè)待執(zhí)行的SQL語(yǔ)句就變成了:
INSERT INTO students (last_name, first_name) VALUES ("XKCD", "Robert’); DROP TABLE Students;-- ")
實(shí)際上,這個(gè)SQL語(yǔ)句一共執(zhí)行了兩個(gè)操作:
INSERT INTO students (last_name, first_name) VALUES ("XKCD", "Robert") DROP TABLE Students
最后的--注釋是為了屏蔽余下的內(nèi)容,保證整個(gè)SQL語(yǔ)句能夠穩(wěn)定執(zhí)行。類似于這樣的攻擊載荷能夠執(zhí)行任意的SQL語(yǔ)句,換言之,攻擊者能夠在數(shù)據(jù)庫(kù)內(nèi)像這個(gè)應(yīng)用系統(tǒng)一樣做任何事情。
采用參數(shù)綁定來(lái)解決這個(gè)問(wèn)題對(duì)于上文描述的這種場(chǎng)景,如果只是依賴于簡(jiǎn)單的清洗過(guò)濾,肯定無(wú)法應(yīng)付所有的攻擊載荷,這也不是一個(gè)正道?;旧夏軌虿扇〉姆椒ň褪撬^的參數(shù)綁定,譬如JDBC中提供的PreparedStatement.setXXX()方法,參數(shù)綁定可以將像SQL這樣的可執(zhí)行代碼與需要進(jìn)行編碼、過(guò)濾的內(nèi)容區(qū)分開來(lái):
void addStudent(String lastName, String firstName) { PreparedStatement stmt = getConnection().prepareStatement("INSERT INTO students (last_name, first_name) VALUES (?, ?)"); stmt.setString(1, lastName); stmt.setString(2, firstName); stmt.execute(); }
一般來(lái)說(shuō),一個(gè)功能比較全面地?cái)?shù)據(jù)訪問(wèn)層都會(huì)提供這種參數(shù)綁定的功能,開發(fā)者在開發(fā)的時(shí)候就要注意將所有的不受信任的輸入通過(guò)參數(shù)綁定生成SQL語(yǔ)句。
Clean and Safe Code有時(shí)候我們開發(fā)時(shí)會(huì)遇到一個(gè)兩難的問(wèn)題,即是好的安全性與干凈整潔的代碼之間的沖突。為了保證安全性往往需要我們?cè)黾有╊~外的代碼,不過(guò)在上面的例子中我們還是同時(shí)達(dá)成了較高的安全性與好的代碼設(shè)計(jì)。使用綁定的參數(shù)不僅能使應(yīng)用系統(tǒng)免于注入攻擊,還能通過(guò)在代碼與內(nèi)容之間構(gòu)建清晰的邊界來(lái)增加整個(gè)代碼的可讀性,并且與手動(dòng)拼接相比還能大大簡(jiǎn)化構(gòu)造可用的SQL的過(guò)程。當(dāng)你用參數(shù)綁定來(lái)代替原本的格式化字符串或者字符串拼接來(lái)構(gòu)造SQL的時(shí)候,你會(huì)發(fā)現(xiàn)還能用全局的綁定方程來(lái)完成這一工作,這又會(huì)大大增加整個(gè)代碼的整潔度與安全性。
Common Misconceptions有一個(gè)常見的錯(cuò)誤思維就是覺(jué)得存儲(chǔ)過(guò)程能夠避免SQL注入攻擊,但是這個(gè)只有在你是通過(guò)參數(shù)綁定的方式傳入?yún)?shù)的情況下。如果存儲(chǔ)過(guò)程本身也是用的字符串連接的方式,那么同樣存在SQL注入攻擊的風(fēng)險(xiǎn)。類似的,像ActiveRecord、Hibernate或者.Net Entity這樣的框架,也是只有在用參數(shù)綁定來(lái)構(gòu)造SQL的情況下才會(huì)進(jìn)行SQL注入清洗。
最后,還有一個(gè)常見的錯(cuò)覺(jué)就是NoSQL數(shù)據(jù)庫(kù)不會(huì)被SQL注入攻擊影響。這肯定是不對(duì)的,所有的查詢語(yǔ)言,無(wú)論是不是SQL都需要在可執(zhí)行代碼與輸入的內(nèi)容之間劃定明晰的邊界來(lái)防止參數(shù)混淆可執(zhí)行的命令。攻擊者會(huì)不停尋找能夠在運(yùn)行時(shí)打破這種邊界隔離的方法從而進(jìn)行潛在的攻擊。即使是Mongodb,采用了二進(jìn)制的協(xié)議與多種語(yǔ)言特定的API都會(huì)存在被注入的風(fēng)險(xiǎn),譬如$where這個(gè)操作符。
Parameter Binding FunctionsFramework | Encoded | Dangerous |
---|---|---|
Raw JDBC | Connection.prepareStatement() used with setXXX() methods and bound parameters for all input. | Any query or update method called with string concatenation rather than binding. |
PHP / MySQLi | prepare() used with bind_param for all input. | Any query or update method called with string concatenation rather than binding. |
MongoDB | Basic CRUD operations such as find(), insert(), with BSON document field names controlled by application. | Operations, including find, when field names are allowed to be determined by untrusted data or use of Mongo operations such as "$where" that allow arbitrary JavaScript conditions. |
Cassandra | Session.prepare used with BoundStatement and bound parameters for all input. | Any query or update method called with string concatenation rather than binding. |
Hibernate / JPA | Use SQL or JPQL/OQL with bound parameters via setParameter | Any query or update method called with string concatenation rather than binding. |
ActiveRecord | Condition functions (find_by, where) if used with hashes or bound parameters, eg: where (foo: bar)where ("foo = ?", bar) | Condition functions used with string concatenation or interpolation: where("foo = "#{bar}"")where("foo = "" + bar + """) |
避免直接從用戶的輸入中構(gòu)建出SQL或者等價(jià)的NoSQL查詢語(yǔ)句
在查詢語(yǔ)句與存儲(chǔ)過(guò)程中都使用參數(shù)綁定
盡可能使用框架提供好的原生的綁定方法而不是用你自己的編碼方法
不要覺(jué)得存儲(chǔ)過(guò)程或者ORM框架可以幫到你,你還是需要手動(dòng)調(diào)用存儲(chǔ)過(guò)程
NoSQL 也存在著注入的危險(xiǎn)
Protect Data in Transit當(dāng)我們著眼于系統(tǒng)的輸入輸出的時(shí)候,還有另一個(gè)重要的店需要考慮進(jìn)去,就是傳輸過(guò)程中數(shù)據(jù)的保密性與完整性。在使用原始的HTTP連接的時(shí)候,因?yàn)榉?wù)器與用戶之間是直接進(jìn)行的明文傳輸,導(dǎo)致了用戶面臨著很多的風(fēng)險(xiǎn)與威脅。攻擊者可以用中間人攻擊來(lái)輕易的截獲或者篡改傳輸?shù)臄?shù)據(jù)。攻擊者想要做些什么并沒(méi)有任何的限制,包括竊取用戶的Session信息、注入有害的代碼等,乃至于修改用戶傳送至服務(wù)器的數(shù)據(jù)。
我們并不能替用戶選擇所使用的網(wǎng)絡(luò),他們很有可能使用一個(gè)開放的,任何人都可以竊聽的網(wǎng)絡(luò),譬如一個(gè)咖啡館或者機(jī)場(chǎng)里面的開放WiFi網(wǎng)絡(luò)。普通的用戶很有可能被欺騙地隨便連上一個(gè)叫免費(fèi)熱點(diǎn)的網(wǎng)絡(luò),或者使用一個(gè)可以隨便被插入廣告的網(wǎng)路當(dāng)中。如果攻擊者會(huì)竊聽或者篡改網(wǎng)路中的數(shù)據(jù),那么用戶與服務(wù)器交換的數(shù)據(jù)就好不可信了,幸好我們還可以使用HTTPS來(lái)保證傳輸?shù)陌踩浴?/p> HTTPS and Transport Layer Security
HTTPS最早主要用于類似于經(jīng)融這樣的安全要求較高的敏感網(wǎng)絡(luò),不過(guò)現(xiàn)在日漸被各種各樣的網(wǎng)站鎖使用,譬如我們常用的社交網(wǎng)絡(luò)或者搜索引擎。HTTPS協(xié)議使用的是TLS協(xié)議,一個(gè)優(yōu)于SSL協(xié)議的標(biāo)準(zhǔn)來(lái)保障通信安全。只要配置與使用得當(dāng),就能有效抵御竊聽與篡改,從而有效保護(hù)我們將要去訪問(wèn)的網(wǎng)站。用更加技術(shù)化的方式說(shuō),HTTPS能夠有效保障數(shù)據(jù)機(jī)密性與完整性,并且能夠完成用戶端與客戶端的雙重驗(yàn)證。
隨著面臨的風(fēng)險(xiǎn)日漸增多,我們應(yīng)該將所有的網(wǎng)絡(luò)數(shù)據(jù)當(dāng)做敏感數(shù)據(jù)并且進(jìn)行加密傳輸。已經(jīng)有很多的瀏覽器廠商宣稱要廢棄所有的非HTTPS的請(qǐng)求,乃至于當(dāng)用戶訪問(wèn)非HTTPS的網(wǎng)站的時(shí)候給出明確的提示。很多基于HTTP/2的實(shí)現(xiàn)都只支持基于TLS的通信,所以我們現(xiàn)在更應(yīng)當(dāng)在全部地方使用HTTPS。
目前如果要大范圍推廣使用HTTPS還是有一些障礙的,在一個(gè)很長(zhǎng)的時(shí)間范圍內(nèi)使用HTTPS會(huì)被認(rèn)為造成很多的計(jì)算資源的浪費(fèi),不過(guò)隨著現(xiàn)代硬件與瀏覽器的發(fā)展,這點(diǎn)計(jì)算資源已經(jīng)不足為道。早期的SSL協(xié)議與TLS協(xié)議只支持一個(gè)IP地址分配一個(gè)整數(shù),不過(guò)現(xiàn)在這種限制所謂的SNI的協(xié)議擴(kuò)展來(lái)解決。另外,從一個(gè)證書認(rèn)證機(jī)構(gòu)獲取證書也會(huì)打消一些用戶使用HTTPS的念頭,不過(guò)下面我們介紹的像Let"s Encrypt這樣的免費(fèi)的服務(wù)就可以打破這種障礙。
Get a Server Certificate對(duì)于網(wǎng)站的安全認(rèn)證依賴于TLS的底層的支持,如果客戶端只是根據(jù)網(wǎng)站說(shuō)它自己是誰(shuí)就是誰(shuí),那么攻擊者可以輕易的使用中間人攻擊來(lái)模擬站點(diǎn),從而繞過(guò)所有協(xié)議提供的安全機(jī)制。在使用了TLS協(xié)議之后,一個(gè)網(wǎng)站可以用它的公鑰證書來(lái)證明它自己是誰(shuí)。在某些系統(tǒng)中客戶端也需要用公鑰證書證明自己是誰(shuí),不過(guò)大部分情況下受限于為用戶管理證書的復(fù)雜性,這個(gè)并沒(méi)有廣泛使用。除非一個(gè)網(wǎng)站證書的真實(shí)性已經(jīng)經(jīng)過(guò)了驗(yàn)證,不然客戶端在收到一個(gè)證書的時(shí)候也要通過(guò)一定的手段來(lái)驗(yàn)證證書的真實(shí)性。而在Web瀏覽器或者其他的應(yīng)用中,往往是通過(guò)一個(gè)第三方的稱作CA的機(jī)構(gòu)來(lái)管理證書并且提供驗(yàn)證功能,包括驗(yàn)證這個(gè)證書與證書所屬網(wǎng)站的真實(shí)性。
如果我們通過(guò)其他渠道已經(jīng)能夠提前得知某個(gè)證書是否可信,那也就沒(méi)必要再經(jīng)過(guò)第三方機(jī)構(gòu)進(jìn)行仲裁。譬如一個(gè)移動(dòng)APP或者其他應(yīng)用在分發(fā)的時(shí)候就會(huì)內(nèi)置一些證書從而在使用時(shí)來(lái)驗(yàn)證站點(diǎn)是否真實(shí)可信。大部分關(guān)于HTTPS是否可信的指示會(huì)在瀏覽器訪問(wèn)某個(gè)HTTPS的站點(diǎn)的時(shí)候顯示出來(lái),如果沒(méi)有的話瀏覽器會(huì)顯示一個(gè)告警信息來(lái)警告用戶不要訪問(wèn)不可信的站點(diǎn)。
在測(cè)試的時(shí)候我們可以自己創(chuàng)建配置一個(gè)證書用于HTTPS認(rèn)證,不過(guò)如果你要提供服務(wù)給普通用戶使用,那么還是需要從可信的第三方CA機(jī)構(gòu)來(lái)獲取可信的證書。對(duì)于很多開發(fā)者而言,一個(gè)免費(fèi)的CA證書是個(gè)不錯(cuò)的選擇。當(dāng)你搜索CA的時(shí)候,你可能會(huì)遇到幾個(gè)不同等級(jí)的證書。最常見的就是Domain Validation(DV),用于認(rèn)證一個(gè)域名的所有者。再往上就是所謂的Organization Validation(OV)與Extended Validation(EV),包括了驗(yàn)證這些證書的請(qǐng)求機(jī)構(gòu)的信息。雖然高級(jí)別的證書需要額外的消耗,不過(guò)還是很值得的。
Configure Your Server當(dāng)你申請(qǐng)到了證書之后,你就可以開始配置你的服務(wù)器支持HTTPS了。雖然HTTPS啊,包括TLS/SSL的原理好像要個(gè)密碼學(xué)的PHD學(xué)位才能理解,但是要把他們配置著用起來(lái)還是很容易的呦。不同的加密算法與站點(diǎn)使用的協(xié)議的版本差異會(huì)大大影響到它能夠提供的通信的安全級(jí)別。所以咋才能一方面保證我們站點(diǎn)的安全性另一方面又保證那些使用老版本的瀏覽器的用戶也能正常使用網(wǎng)站服務(wù)呢?這里要推薦下Mozilla提供的Security/Server Side TLS工具,可以協(xié)助來(lái)自動(dòng)創(chuàng)建適用的Web服務(wù)器的配置。
Use HTTPS for Everything現(xiàn)在我們經(jīng)常碰到一些網(wǎng)站僅僅只用HTTPS來(lái)保護(hù)部分資源,有些情況下只會(huì)保護(hù)一些對(duì)于敏感資源的提交操作。另一些情況下,部分網(wǎng)站只會(huì)將HTTPS用于自認(rèn)為敏感的資源上,譬如一個(gè)用戶登錄之后才能見到的東西往往是HTTPS加密的。而現(xiàn)在的麻煩事還有很多站點(diǎn)并未使用HTTPS來(lái)保護(hù)自己,導(dǎo)致整個(gè)網(wǎng)站還處于被中間人攻擊的危險(xiǎn)之下。筆者很是建議這類網(wǎng)站應(yīng)該直接關(guān)閉掉HTTP端口從而強(qiáng)制性讓用戶轉(zhuǎn)到HTTPS,雖然這并不是一個(gè)理想的解決方案,不過(guò)估計(jì)是最好的解決方法。
如果是在Web瀏覽器中呈現(xiàn)的資源,那可以添加一個(gè)HTTP請(qǐng)求轉(zhuǎn)發(fā)的配置,來(lái)將所有的HTTP請(qǐng)求轉(zhuǎn)發(fā)到HTTPS端口上,譬如:
# Redirect requests to /content to use HTTPS (mod_rewrite is required) RewriteEngine On RewriteCond %{HTTPS} != on [NC] RewriteCond %{REQUEST_URI} ^/content(/.*)? RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [R,L]Use HSTS
讓用戶從HTTP遷移到HTTPS可以來(lái)避免使用原始的HTTP請(qǐng)求帶來(lái)的風(fēng)險(xiǎn)。為了幫助站點(diǎn)把用戶從HTTP遷移到HTTPS,現(xiàn)代的瀏覽器支持一個(gè)非常強(qiáng)力的安全特征叫做HSTS(HTTP Strict Transport Security),來(lái)告訴瀏覽器我這個(gè)站點(diǎn)只會(huì)接收來(lái)自于HTTPS的請(qǐng)求。這個(gè)特性最早來(lái)自于2009年的Moxie Marlinspike"s提出的一個(gè)用于演示基于HTTP的潛在危險(xiǎn)的SSL剝離攻擊。可以用如下的設(shè)置來(lái)啟用這個(gè)特性:
Strict-Transport-Security: max-age=15768000
上述的設(shè)置會(huì)告訴瀏覽器只和使用HTTPS的站點(diǎn)進(jìn)行交互,HSTS是一個(gè)非常重要的強(qiáng)制使用HTTPS的特性。一旦開啟之后,瀏覽器會(huì)自動(dòng)把不安全的HTTP請(qǐng)求切換到HTTPS,盡管用戶沒(méi)有顯式的輸入"https://"。而在瀏覽器端開啟HSTS特性只需要添加如下的一行代碼:
... # HSTS (mod_headers is required) (15768000 seconds = 6 months) Header always set Strict-Transport-Security "max-age=15768000"
不過(guò)現(xiàn)在并不是所有的瀏覽器都支持HSTS特性,你可以通過(guò)訪問(wèn) Can I use. 來(lái)看看你面向的用戶常用的瀏覽器能不能使用。
Protect Cookies瀏覽器目前有內(nèi)建的安全機(jī)制來(lái)避免包含敏感信息的Cookie暴露出來(lái)。在Cookie中設(shè)置secure標(biāo)識(shí)位能夠強(qiáng)制讓瀏覽器只會(huì)用HTTPS來(lái)傳遞Cookie,如果你已經(jīng)使用了HSTS也要記得這樣設(shè)置來(lái)保護(hù)Cookie。
Other Risks即使你全站都用了HTTPS,也還是有幾個(gè)地方可能導(dǎo)致敏感信息的泄露的。譬如如果你直接把敏感數(shù)據(jù)放在URL里面,然后這個(gè)敏感的URL又被緩存在了瀏覽器的歷史記錄里。除此之后,如果包含了敏感信息的站點(diǎn)被鏈接到了其他的網(wǎng)站中,那么在用戶點(diǎn)擊鏈接之后整個(gè)敏感數(shù)據(jù)就會(huì)被放在Referer Header中然后傳送過(guò)去,然后就呵呵了。另外,有時(shí)候因?yàn)榇蠹叶级脑蛭覀儠?huì)使用一些代理然后允許他們監(jiān)控HTTPS的流量,也是有危險(xiǎn)地,這個(gè)時(shí)候就要在Header中來(lái)關(guān)閉緩存從而降低風(fēng)險(xiǎn)。筆者建議你可以參考OWASP Transport Protection Layer Cheat Sheet 來(lái)收獲一些有用的建議。
Verify Your Configuration最后一步,你要仔細(xì)驗(yàn)證你的配置是否有效。有很多的在線工具可以幫你做這件事,譬如SSL Lab的SSL Server Test能夠幫你深度分析你的HTTPS的配置,再看看是不是有啥地方配錯(cuò)了。這個(gè)工具會(huì)在發(fā)現(xiàn)了新的攻擊手段與協(xié)議更新之后實(shí)時(shí)更新,所以多用用它還是個(gè)很不錯(cuò)的事情嗷。
In Summary啥地方都要用HTTPS
采用HSTS來(lái)強(qiáng)制使用HTTPS
別忘了從可信的證書機(jī)構(gòu)中請(qǐng)求可信證書
不要亂放你的私鑰
用合理的配置工具來(lái)生成可靠地HTTPS配置
在Cookie中設(shè)置"secure"標(biāo)識(shí)
不要把敏感的數(shù)據(jù)放在URL中
隔一段時(shí)間就要好好看看你的HTTPS的配置,表過(guò)時(shí)了
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/11163.html
摘要:本書的這一部分將為隨后的章節(jié)打下基礎(chǔ),會(huì)涵蓋模板,模塊化,和依賴注入。本書的小例子中我們會(huì)使用未經(jīng)壓縮的,開發(fā)友好的版本,在的上。作用域也可以針對(duì)特定的視圖來(lái)擴(kuò)展數(shù)據(jù)和特定的功能。 上一篇:【譯】《精通使用AngularJS開發(fā)Web App》(一) 下一篇:【譯】《精通使用AngularJS開發(fā)Web App》(三) 原版書名:Mastering Web Application D...
摘要:前端日?qǐng)?bào)精選專題之類型判斷下百度生態(tài)構(gòu)建發(fā)布基于的解決方案將全面支持從綁定,看語(yǔ)言發(fā)展和框架設(shè)計(jì)掘金譯機(jī)器學(xué)習(xí)與一付費(fèi)問(wèn)答上線,向你心目中的大牛提問(wèn)吧產(chǎn)品技術(shù)日志中文第期團(tuán)隊(duì)技術(shù)信息流建設(shè)翻譯基于路由的異步組件加載個(gè)必備的裝逼 2017-07-06 前端日?qǐng)?bào) 精選 JavaScript專題之類型判斷(下) · Issue #30 · mqyqingfeng/Blog 百度Web生態(tài)構(gòu)...
摘要:微服務(wù)簡(jiǎn)介微服務(wù)架構(gòu)是一種架構(gòu)概念,旨在通過(guò)將功能分解到各個(gè)離散的服務(wù)中以實(shí)現(xiàn)對(duì)解決方案的解耦。每個(gè)微服務(wù)僅關(guān)注于完成一件任務(wù)并很好地完成該任務(wù)。服務(wù)異常自動(dòng)隔離。微服務(wù)架構(gòu)挑戰(zhàn)服務(wù)規(guī)模大,部署運(yùn)維管理難度大。 微服務(wù)簡(jiǎn)介 微服務(wù)架構(gòu)(Microservice Architecture)是一種架構(gòu)概念,旨在通過(guò)將功能分解到各個(gè)離散的服務(wù)中以實(shí)現(xiàn)對(duì)解決方案的解耦。 微服務(wù)是一種架構(gòu)風(fēng)格,...
摘要:面試網(wǎng)絡(luò)了解及網(wǎng)絡(luò)基礎(chǔ)對(duì)端傳輸詳解與攻防實(shí)戰(zhàn)本文從屬于筆者的信息安全實(shí)戰(zhàn)中滲透測(cè)試實(shí)戰(zhàn)系列文章。建議先閱讀下的網(wǎng)絡(luò)安全基礎(chǔ)。然而,該攻擊方式并不為大家所熟知,很多網(wǎng)站都有的安全漏洞。 面試 -- 網(wǎng)絡(luò) HTTP 現(xiàn)在面試門檻越來(lái)越高,很多開發(fā)者對(duì)于網(wǎng)絡(luò)知識(shí)這塊了解的不是很多,遇到這些面試題會(huì)手足無(wú)措。本篇文章知識(shí)主要集中在 HTTP 這塊。文中知識(shí)來(lái)自 《圖解 HTTP》與維基百科,若...
閱讀 3513·2021-09-22 15:17
閱讀 2873·2021-09-02 15:15
閱讀 1899·2019-08-30 15:54
閱讀 2062·2019-08-30 14:02
閱讀 2600·2019-08-29 16:58
閱讀 3046·2019-08-29 16:08
閱讀 1409·2019-08-26 12:24
閱讀 1710·2019-08-26 10:41