摘要:瀏覽器的同源策略并不能夠避免來自于惡意站點的提交。為了保證輸入數據的完整性,服務器端務必要進行數據校驗。輸入驗證即是保證實際輸入與應用預期的輸入的一致性。因此驗證輸入時保證系統安全性與防衛危險的第一道防線。
Github Repo:https://github.com/wxyyxc1992/infosecurity-handbook/blob/master/Reinforce/WebSecurity/basics-of-web-application-security.md
原文:The Basics of Web Application Security
現代的軟件開發者已經有點像瑞士軍刀了,首先,你需要來保證完成用戶的功能或者業務需求,并且要保證又快又好地完成。其次,你希望你的代碼能夠擁有充分的可理解性或者可擴展性:能夠隨著IT需求的快速變遷而有著充分的擴展空間,與此同時還需要穩定與可用。開發者必須列舉出有用的接口,優化數據庫,以及頻繁地建立或者維護一個交付渠道。不過,當我們審視這長長的需求列表的時候,在快速、低成本以及靈活可擴展之下的,即是安全性。或許直到一些東西出了問題,或者你構建的系統被攻擊了之后才能深刻感受到安全才是最重要的。安全這個概念有點像性能,是個泛化的跨越了多個領域的概念。所以一個開發者怎么才能在模糊的安全需求與未知的風險面前選擇合適的開發規劃呢?當然如果能夠明確這些安全需求與定位到威脅的話毫無疑問非常值得推薦,但是這個準備本身就需要耗費大量的時間與金錢。
Trust(信賴)首先,在討論具體的輸入輸出之前,我們需要來強調下自認為安全中最重要也是最根本的原則:Trust。作為一個開發者,也需要不斷地問自己,我們相信來自于用戶瀏覽器的請求嗎?我們相信上游系統正常工作來保證了我們數據的干凈與安全嗎?我們相信服務器與瀏覽器之間的信道就不會被監聽或者偽造嗎?我們相信我們系統本身依賴的服務或者數據存儲嗎?呵呵,都不可信。
當然,就像安全一樣,Trust也不是一個雙選題,非黑即白。我們需要明白系統的風險忍受力與數據的安全邊界。為了能夠正確的、基于某個統一規則的預估,我們需要審視威脅與風險,這個評估方法與標準會在另一篇文章中講解。
Reject Unexpected Form Input(拒絕未知的表單輸入)HTML表單本身就可能帶來些好像很安全的錯覺,表單的構建者肯定覺得他們限制了輸入類型、做了數據校驗,這樣整個表單輸入就是安全的。但確信無疑的是,這只是個錯覺,盡管客戶端地JavaScript腳本可以從安全地角度來說提供完整的校驗。
Untrusted Input無論我們是否在客戶端提供了表單驗證或者是否使用了HTTPs連接,我們能夠信賴來自用戶瀏覽器的連接的比例都是0。用戶可以輕易地在發送之前修改標記,或者使用類似于curl這樣的命令行來提交沒有經過校驗的數據。乃至于一個不明所以的用戶可能在一個懷有惡意的網站莫名其妙地添了些內容。瀏覽器的同源策略并不能夠避免來自于惡意站點的提交。為了保證輸入數據的完整性,服務器端務必要進行數據校驗。
不過估計有人有疑問了,為啥說這個畸形的數據就會導致安全問題呢?這往往取決于你的應用業務邏輯與輸出的編碼,為了避免不可預知的行為、數據泄露與潛在攻擊,需要在輸入的數據與可執行代碼之間架構一個過濾層。譬如,我們的表單里有一個選擇的按鈕來允許用戶選擇合適的通信類型,我們的業務邏輯代碼可能是這樣的:
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)); }
上面代碼危不危險取決于sendError這個方法是怎么定義的,而我們肯定無法確定下游的代碼就一定是安全的。最好的選擇就是我們在控制流中移除這個危險,而使用的方法就是輸入驗證。
Input Validation輸入驗證即是保證實際輸入與應用預期的輸入的一致性。超出預期的輸入數據會導致我們系統拋出未知的結果,譬如邏輯崩壞、觸發錯誤乃至于允許攻擊者控制系統的一部分。其中像數據庫查詢這樣的能夠在服務端作為可執行代碼的輸入與JavaScript這樣在客戶端能夠被執行的代碼更是特別的危險。因此驗證輸入時保證系統安全性與防衛危險的第一道防線。
開發者們在構建應用系統的過程中會進行一些基本的驗證,譬如判斷值是否為空或者是否為正數。而從安全的角度考慮,我們需要將輸入限定到系統允許的最小集合中,譬如數值型值可以被限定在某個特定的范圍內。譬如,系統不會允許用戶將一個負值添加到購物車中。這種限制性的驗證手段就是所謂的positive validation或者whitelisting。一個白名單可以用于限定某個具體的URL或者yyyy/mm/dd這樣的時間日期。它可以限制輸入的長度、單個字符的編碼規范或者上面例子中的只有給定值可以被接受。
另外一種考慮輸入驗證的思維角度就是把它當做服務端與消費者之間簽訂的一種協議,任何違背了這個協議的請求都是無效的并且被拒絕。你的這個協議越嚴格,你的系統在未知情況下遭受的風險就會越小。而當對于某個輸入驗證失敗之后,開發者也要好好考慮應該如何反饋。最嚴格,也是最有爭議的辦法就是全部拒絕,并且沒有任何反饋,不過要注意將這個事情通過日志或者監控記錄下來。不過為啥一點反饋都沒有呢?我們需要提供給用戶哪些信息是無效的嗎?這一點還是要取決于你的約定。在上面的例子中,如果你接收到了除了email或者text之外的內容,那你有可能被攻擊了。不過如果你進行了反饋,可能正中全套。譬如如果開發者直接返回:俺們并不認識你傳入的communicationType,可能這個還無傷大雅,但是如果是這樣的呢:
這種情況下你就會面臨一個用來盜取你的Cookies的XSS攻擊代碼,如果你一定要給用戶反饋,你必須保證不會把不受信任的用戶內容直接返回,而應該使用固定的提示信息。如果你不可避免地要把用戶的輸入反饋回去,你要保證它是被編碼的。
In Practice實踐中,我們經常要通過過濾標簽來避免一些攻擊,過濾掉這些包含著危險值的輸入的方法就是所謂的negative validation 或者blacklisting。不過這種方法的麻煩之處在于潛在的危險輸入是相當多的,很多時候不能勝數。維持一個龐大的危險輸入的列表可能是耗費較大的操作,這需要進行頻繁地更新。如果你真的需要一個黑名單,這就需要覆蓋你所有的測試用例,編寫高質量的測試代碼,遵循OWASP的XSS_Filter_Evasion_Cheat_Sheet原則。
對于危險輸入的過濾,我們常常稱之為sanitization,即是在輸入中移除那些黑名單中的元素而不是直接拒絕。不過這種黑名單機制,很難保證完全正確,往往也會給攻擊者更多地漏洞機會。譬如,在上面的例子中,我們是選擇移除標簽,而一個攻擊者可以通過輸入下面這樣的字符串來逃避檢查:
ipt>
在現代的Web應用程序開發中,已經有很多現成的框架提供了基礎的過濾功能。內建的對于郵件地址、信用卡號碼等等過濾還是灰常好用的,使用這些網絡框架提供的驗證機制可以有效避免一些嚴重的錯誤,譬如:
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 |
盡可能地使用白名單
在不能用白名單的時候用黑名單
盡可能地使用嚴格約定
確保警示潛在的攻擊
避免直接地輸入反饋
盡可能地在不可信數據深入系統邏輯之前進行處理,或者直接使用你的框架的白名單機制
Encode HTML Output:HTML輸出內容編碼除了上述所說的對于輸入的過濾與限制之外,Web應用的開發者還需要關注返回的數據。一個現代的Web應用往往會用HTML標記來構建文檔結構,用CSS來構建文檔樣式,JavaScript來構建應用邏輯。一個HTML文檔通常使用像或者這樣的標記來進行切割。用戶可能在沒料到的地方使用尖括號,特別是在一個可執行的上下文中附著一些特定內容,譬如HTML與JavaScript都會包含URL,只不過它們各有各的處理方法。
Output RisksHTML本身是一個非常非常寬松自由的格式,瀏覽器會盡可能地來渲染內容,即使發現了些格式錯誤。這一點對于開發者非常友好,不過這也是一個很大的漏洞的源泉。攻擊者可能在向你的頁面中注入一些內容來打破可執行的上下文,甚至不需要考慮整個頁面是否有效。處理輸出內容并不一定是安全地考慮,應用從數據庫與上游服務中獲取的渲染數據務必保證不會影響到整個應用,不過從不可信的數據源得到的渲染內容還是會存在很大的風險。就如上文所說的,開發者應該拒絕那些超出約定的輸入,不過有時候我們不可避免的需要接收像尖括號那樣的可能更改我們的代碼的內容,這也就是下面所說的output encoding所需要起作用的地方。
Output Encoding輸出編碼即是將輸出的數據流轉化為最終的輸出的格式,輸出編碼的難點或者復雜的地方在于需要根據輸出數據流向的不同選定不同的編碼方式。如果沒有合適的編碼方式,應用可能會給客戶端提供一個錯誤格式的數據,導致輸出數據不可用乃至于存在一定風險。攻擊者往往會利用錯誤的編碼方式中的漏洞使得整個輸出數據的結構失控。譬如在我們的電商系統中有個用戶叫做Sandra Day O"Connor,系統會在該用戶登錄的時候輸出一個歡迎辭,那么當她的名字渲染到HTML頁面上的時候,效果大概是這樣的:
The Honorable Justice Sandra Day O"Connor
The Honorable Justice Sandra Day O"Connor
開發者期望的正是這樣渲染得出的界面,不過如果我們是基于MVC架構開發出了一個動態網頁,名字會通過JS腳本動態地插入到頁面中,示例代碼如下:
document.getElementById("name").innerText = "Sandra Day O"Connor" //<--unescaped string
而這樣的代碼正是攻擊者們孜孜不倦尋找的漏洞點來執行他們的自定義代碼,如果另一個用戶Chief Justice這樣的輸入他的名字:
Sandra Day O";window.location="http://evil.martinfowler.com/";
那么所有看到他名字頁面的用戶都會被重定向到一個危險的站點,而如果我們應用正確地在這個JS上下文中進行了編碼,整個編碼之后的文本如下所示:
"Sandra Day O";window.location="http://evil.martinfowler.com/";"
那么整個文本雖然看上去有點雜亂,但是已經變成了沒有任何危害的不可執行的代碼。一般來說我們有很多種方式可以來對JS進行編碼,最常見的就是使用轉義字符。
好消息是絕大部分現代Web框架都提供了將內容安全編碼與過濾保留字符的功能。不過大部分開發者會忽略乃至于主動關閉這種過濾編碼功能從而去執行他們自認為的安全的可執行代碼。
Cautions and Caveats關于輸出編碼這部分還有幾個需要了解的地方,重要的事情多強調幾遍,一定要選擇一個自帶編碼功能的框架。另外還需要注意的是,盡管一個框架可以安全地渲染HTML,也不代表他可以安全地渲染PDF或者JavaScript。
另一個我們在應用開發過程中經常遇到的情況,就是很多開發者習慣在獲取用戶的原始輸入后進行編碼然后存入數據庫中。譬如如果你在將數據入庫之前就把純文本格式的數據編碼成HTML格式,然后在需要渲染成其他格式的地方還需要先把HTML反編碼然后再編譯成其他格式。這無端會增加很多復雜性和額外的工作,因此最好直接以原始數據格式存入到數據庫中,然后在渲染時在將它們進行編碼。
In Summary以合適的編碼手段對所有從應用中吐出的數據進行編碼
盡可能地使用框架提供的輸出編碼功能
盡量避免嵌入式渲染上下文
以原始格式存放數據,在渲染時進行編碼
避免使用不安全的框架與規避了編碼的JS調用
Bind Parameters for Database Queries不管你是用SQL在一個關系型數據庫中進行查詢,還是用ORM框架,或者直接使用一個NoSQL數據庫,你都需要考慮到怎么把用戶輸入的數據集成進你的查詢語句中。數據庫可能是一個Web應用程序中最關鍵與緊要的部分,因為它存放了大量的無法重現的狀態數據。譬如一個數據庫中可能存放著大量的關鍵的與敏感的客戶信息,也正是這些數據驅動著整個應用與邏輯的運行。因此你肯定希望開發者在和數據庫打交道的時候要慎之又慎,不過數據庫注入攻擊還是很盛行啊。
Little Bobby Tables很多關于數據庫中參數綁定的討論都會包含著名的2007年的Little Bobby Tables事件,這個事件可以用一個漫畫描述如下:
為了便于分析這個漫畫所要表達的含義,我們假設這個成績追蹤系統有一個用于增加新的學生信息的函數:
void addStudent(String lastName, String firstName) { String query = "INSERT INTO students (last_name, first_name) VALUES ("" + lastName + "", "" + firstName + "")"; getConnection().createStatement().execute(query); }
如果輸入的參數是"Fowler"與"Martin",那么最終構造出的SQL語句為:
INSERT INTO students (last_name, first_name) VALUES ("Fowler", "Martin")
不過如果輸入的是上面那娃的名字,那么整個待執行的SQL語句就變成了:
INSERT INTO students (last_name, first_name) VALUES ("XKCD", "Robert’); DROP TABLE Students;-- ")
實際上,這個SQL語句一共執行了兩個操作:
INSERT INTO students (last_name, first_name) VALUES ("XKCD", "Robert") DROP TABLE Students
最后的--注釋是為了屏蔽余下的內容,保證整個SQL語句能夠穩定執行。類似于這樣的攻擊載荷能夠執行任意的SQL語句,換言之,攻擊者能夠在數據庫內像這個應用系統一樣做任何事情。
采用參數綁定來解決這個問題對于上文描述的這種場景,如果只是依賴于簡單的清洗過濾,肯定無法應付所有的攻擊載荷,這也不是一個正道。基本上能夠采取的方法就是所謂的參數綁定,譬如JDBC中提供的PreparedStatement.setXXX()方法,參數綁定可以將像SQL這樣的可執行代碼與需要進行編碼、過濾的內容區分開來:
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(); }
一般來說,一個功能比較全面地數據訪問層都會提供這種參數綁定的功能,開發者在開發的時候就要注意將所有的不受信任的輸入通過參數綁定生成SQL語句。
Clean and Safe Code有時候我們開發時會遇到一個兩難的問題,即是好的安全性與干凈整潔的代碼之間的沖突。為了保證安全性往往需要我們增加些額外的代碼,不過在上面的例子中我們還是同時達成了較高的安全性與好的代碼設計。使用綁定的參數不僅能使應用系統免于注入攻擊,還能通過在代碼與內容之間構建清晰的邊界來增加整個代碼的可讀性,并且與手動拼接相比還能大大簡化構造可用的SQL的過程。當你用參數綁定來代替原本的格式化字符串或者字符串拼接來構造SQL的時候,你會發現還能用全局的綁定方程來完成這一工作,這又會大大增加整個代碼的整潔度與安全性。
Common Misconceptions有一個常見的錯誤思維就是覺得存儲過程能夠避免SQL注入攻擊,但是這個只有在你是通過參數綁定的方式傳入參數的情況下。如果存儲過程本身也是用的字符串連接的方式,那么同樣存在SQL注入攻擊的風險。類似的,像ActiveRecord、Hibernate或者.Net Entity這樣的框架,也是只有在用參數綁定來構造SQL的情況下才會進行SQL注入清洗。
最后,還有一個常見的錯覺就是NoSQL數據庫不會被SQL注入攻擊影響。這肯定是不對的,所有的查詢語言,無論是不是SQL都需要在可執行代碼與輸入的內容之間劃定明晰的邊界來防止參數混淆可執行的命令。攻擊者會不停尋找能夠在運行時打破這種邊界隔離的方法從而進行潛在的攻擊。即使是Mongodb,采用了二進制的協議與多種語言特定的API都會存在被注入的風險,譬如$where這個操作符。
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 + """) |
避免直接從用戶的輸入中構建出SQL或者等價的NoSQL查詢語句
在查詢語句與存儲過程中都使用參數綁定
盡可能使用框架提供好的原生的綁定方法而不是用你自己的編碼方法
不要覺得存儲過程或者ORM框架可以幫到你,你還是需要手動調用存儲過程
NoSQL 也存在著注入的危險
Protect Data in Transit當我們著眼于系統的輸入輸出的時候,還有另一個重要的店需要考慮進去,就是傳輸過程中數據的保密性與完整性。在使用原始的HTTP連接的時候,因為服務器與用戶之間是直接進行的明文傳輸,導致了用戶面臨著很多的風險與威脅。攻擊者可以用中間人攻擊來輕易的截獲或者篡改傳輸的數據。攻擊者想要做些什么并沒有任何的限制,包括竊取用戶的Session信息、注入有害的代碼等,乃至于修改用戶傳送至服務器的數據。
我們并不能替用戶選擇所使用的網絡,他們很有可能使用一個開放的,任何人都可以竊聽的網絡,譬如一個咖啡館或者機場里面的開放WiFi網絡。普通的用戶很有可能被欺騙地隨便連上一個叫免費熱點的網絡,或者使用一個可以隨便被插入廣告的網路當中。如果攻擊者會竊聽或者篡改網路中的數據,那么用戶與服務器交換的數據就好不可信了,幸好我們還可以使用HTTPS來保證傳輸的安全性。
HTTPS and Transport Layer SecurityHTTPS最早主要用于類似于經融這樣的安全要求較高的敏感網絡,不過現在日漸被各種各樣的網站鎖使用,譬如我們常用的社交網絡或者搜索引擎。HTTPS協議使用的是TLS協議,一個優于SSL協議的標準來保障通信安全。只要配置與使用得當,就能有效抵御竊聽與篡改,從而有效保護我們將要去訪問的網站。用更加技術化的方式說,HTTPS能夠有效保障數據機密性與完整性,并且能夠完成用戶端與客戶端的雙重驗證。
隨著面臨的風險日漸增多,我們應該將所有的網絡數據當做敏感數據并且進行加密傳輸。已經有很多的瀏覽器廠商宣稱要廢棄所有的非HTTPS的請求,乃至于當用戶訪問非HTTPS的網站的時候給出明確的提示。很多基于HTTP/2的實現都只支持基于TLS的通信,所以我們現在更應當在全部地方使用HTTPS。
目前如果要大范圍推廣使用HTTPS還是有一些障礙的,在一個很長的時間范圍內使用HTTPS會被認為造成很多的計算資源的浪費,不過隨著現代硬件與瀏覽器的發展,這點計算資源已經不足為道。早期的SSL協議與TLS協議只支持一個IP地址分配一個整數,不過現在這種限制所謂的SNI的協議擴展來解決。另外,從一個證書認證機構獲取證書也會打消一些用戶使用HTTPS的念頭,不過下面我們介紹的像Let"s Encrypt這樣的免費的服務就可以打破這種障礙。
Get a Server Certificate對于網站的安全認證依賴于TLS的底層的支持,如果客戶端只是根據網站說它自己是誰就是誰,那么攻擊者可以輕易的使用中間人攻擊來模擬站點,從而繞過所有協議提供的安全機制。在使用了TLS協議之后,一個網站可以用它的公鑰證書來證明它自己是誰。在某些系統中客戶端也需要用公鑰證書證明自己是誰,不過大部分情況下受限于為用戶管理證書的復雜性,這個并沒有廣泛使用。除非一個網站證書的真實性已經經過了驗證,不然客戶端在收到一個證書的時候也要通過一定的手段來驗證證書的真實性。而在Web瀏覽器或者其他的應用中,往往是通過一個第三方的稱作CA的機構來管理證書并且提供驗證功能,包括驗證這個證書與證書所屬網站的真實性。
如果我們通過其他渠道已經能夠提前得知某個證書是否可信,那也就沒必要再經過第三方機構進行仲裁。譬如一個移動APP或者其他應用在分發的時候就會內置一些證書從而在使用時來驗證站點是否真實可信。大部分關于HTTPS是否可信的指示會在瀏覽器訪問某個HTTPS的站點的時候顯示出來,如果沒有的話瀏覽器會顯示一個告警信息來警告用戶不要訪問不可信的站點。
在測試的時候我們可以自己創建配置一個證書用于HTTPS認證,不過如果你要提供服務給普通用戶使用,那么還是需要從可信的第三方CA機構來獲取可信的證書。對于很多開發者而言,一個免費的CA證書是個不錯的選擇。當你搜索CA的時候,你可能會遇到幾個不同等級的證書。最常見的就是Domain Validation(DV),用于認證一個域名的所有者。再往上就是所謂的Organization Validation(OV)與Extended Validation(EV),包括了驗證這些證書的請求機構的信息。雖然高級別的證書需要額外的消耗,不過還是很值得的。
Configure Your Server當你申請到了證書之后,你就可以開始配置你的服務器支持HTTPS了。雖然HTTPS啊,包括TLS/SSL的原理好像要個密碼學的PHD學位才能理解,但是要把他們配置著用起來還是很容易的呦。不同的加密算法與站點使用的協議的版本差異會大大影響到它能夠提供的通信的安全級別。所以咋才能一方面保證我們站點的安全性另一方面又保證那些使用老版本的瀏覽器的用戶也能正常使用網站服務呢?這里要推薦下Mozilla提供的Security/Server Side TLS工具,可以協助來自動創建適用的Web服務器的配置。
Use HTTPS for Everything現在我們經常碰到一些網站僅僅只用HTTPS來保護部分資源,有些情況下只會保護一些對于敏感資源的提交操作。另一些情況下,部分網站只會將HTTPS用于自認為敏感的資源上,譬如一個用戶登錄之后才能見到的東西往往是HTTPS加密的。而現在的麻煩事還有很多站點并未使用HTTPS來保護自己,導致整個網站還處于被中間人攻擊的危險之下。筆者很是建議這類網站應該直接關閉掉HTTP端口從而強制性讓用戶轉到HTTPS,雖然這并不是一個理想的解決方案,不過估計是最好的解決方法。
如果是在Web瀏覽器中呈現的資源,那可以添加一個HTTP請求轉發的配置,來將所有的HTTP請求轉發到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可以來避免使用原始的HTTP請求帶來的風險。為了幫助站點把用戶從HTTP遷移到HTTPS,現代的瀏覽器支持一個非常強力的安全特征叫做HSTS(HTTP Strict Transport Security),來告訴瀏覽器我這個站點只會接收來自于HTTPS的請求。這個特性最早來自于2009年的Moxie Marlinspike"s提出的一個用于演示基于HTTP的潛在危險的SSL剝離攻擊。可以用如下的設置來啟用這個特性:
Strict-Transport-Security: max-age=15768000
上述的設置會告訴瀏覽器只和使用HTTPS的站點進行交互,HSTS是一個非常重要的強制使用HTTPS的特性。一旦開啟之后,瀏覽器會自動把不安全的HTTP請求切換到HTTPS,盡管用戶沒有顯式的輸入"https://"。而在瀏覽器端開啟HSTS特性只需要添加如下的一行代碼:
... # HSTS (mod_headers is required) (15768000 seconds = 6 months) Header always set Strict-Transport-Security "max-age=15768000"
不過現在并不是所有的瀏覽器都支持HSTS特性,你可以通過訪問 Can I use. 來看看你面向的用戶常用的瀏覽器能不能使用。
Protect Cookies瀏覽器目前有內建的安全機制來避免包含敏感信息的Cookie暴露出來。在Cookie中設置secure標識位能夠強制讓瀏覽器只會用HTTPS來傳遞Cookie,如果你已經使用了HSTS也要記得這樣設置來保護Cookie。
Other Risks即使你全站都用了HTTPS,也還是有幾個地方可能導致敏感信息的泄露的。譬如如果你直接把敏感數據放在URL里面,然后這個敏感的URL又被緩存在了瀏覽器的歷史記錄里。除此之后,如果包含了敏感信息的站點被鏈接到了其他的網站中,那么在用戶點擊鏈接之后整個敏感數據就會被放在Referer Header中然后傳送過去,然后就呵呵了。另外,有時候因為大家都懂的原因我們會使用一些代理然后允許他們監控HTTPS的流量,也是有危險地,這個時候就要在Header中來關閉緩存從而降低風險。筆者建議你可以參考OWASP Transport Protection Layer Cheat Sheet 來收獲一些有用的建議。
Verify Your Configuration最后一步,你要仔細驗證你的配置是否有效。有很多的在線工具可以幫你做這件事,譬如SSL Lab的SSL Server Test能夠幫你深度分析你的HTTPS的配置,再看看是不是有啥地方配錯了。這個工具會在發現了新的攻擊手段與協議更新之后實時更新,所以多用用它還是個很不錯的事情嗷。
In Summary啥地方都要用HTTPS
采用HSTS來強制使用HTTPS
別忘了從可信的證書機構中請求可信證書
不要亂放你的私鑰
用合理的配置工具來生成可靠地HTTPS配置
在Cookie中設置"secure"標識
不要把敏感的數據放在URL中
隔一段時間就要好好看看你的HTTPS的配置,表過時了
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/11163.html
摘要:本書的這一部分將為隨后的章節打下基礎,會涵蓋模板,模塊化,和依賴注入。本書的小例子中我們會使用未經壓縮的,開發友好的版本,在的上。作用域也可以針對特定的視圖來擴展數據和特定的功能。 上一篇:【譯】《精通使用AngularJS開發Web App》(一) 下一篇:【譯】《精通使用AngularJS開發Web App》(三) 原版書名:Mastering Web Application D...
摘要:前端日報精選專題之類型判斷下百度生態構建發布基于的解決方案將全面支持從綁定,看語言發展和框架設計掘金譯機器學習與一付費問答上線,向你心目中的大牛提問吧產品技術日志中文第期團隊技術信息流建設翻譯基于路由的異步組件加載個必備的裝逼 2017-07-06 前端日報 精選 JavaScript專題之類型判斷(下) · Issue #30 · mqyqingfeng/Blog 百度Web生態構...
閱讀 3396·2021-09-22 15:17
閱讀 2747·2021-09-02 15:15
閱讀 1769·2019-08-30 15:54
閱讀 2006·2019-08-30 14:02
閱讀 2534·2019-08-29 16:58
閱讀 2994·2019-08-29 16:08
閱讀 1335·2019-08-26 12:24
閱讀 1660·2019-08-26 10:41