HTTP協議安全頭部X-Content-Type-Options引入的問題

轉載:http://www.jackieathome.net/archives/369.html?utm_source=tuicool&utm_medium=referral
前段時間測試MM反饋了一個問題,在富文本編輯器裏上傳的圖片無法正常呈現。因爲Jackie在本機的環境上沒有觀察類似的現象,而恰好那天測試環境的某個重要配項被改錯了,於是Jackie想當然的歸類爲配置項錯誤引入的問題。但修改完測試環境的配置項後,測試反饋富文本編輯器內圖片無法呈現的現象依然存在。

這下就有點麻煩了,問題是在版本上線的前一天晚上發現的,如果問題不能儘快處理,勢必對第二天的版本上線產生影響。雖然逢上線必加班至深夜,但也不能讓問題掛在Jackie手裏。

時間緊急,問題詭異,Jackie馬上放下手頭的工作,全力投入分析工作中。

排查過程
如前所述,配置項修改正確後,問題現象仍然存在,因此首先排除了配置項配置引入問題的可能。
請測試MM幫忙復現問題,仔細觀察之後,發現使用不同瀏覽器訪問問題頁面時可以觀察到不同的現象:
使用Chrome訪問頁面時,富文本編輯器內的圖片可以正常呈現。
使用IE9、IE11訪問頁面時,富文本編輯器內的圖片無法呈現。從瀏覽器的呈現效果看,貌似是圖片加載失敗;但在調試器的網絡面板查看頁面資源的加載情況,可以觀察到瀏覽器發起了圖片的獲取請求,而Web應用確實返回了圖片信息;但就是沒有呈現出來。
直接把富文本編輯器的內圖片的URL複製出來,貼到瀏覽器的地址欄裏訪問,圖片可以正常呈現。
在生產環境和體驗環境上做對比驗證,使用IE9、IE11訪問這兩個環境,查看富文本編輯器內的圖片,沒有觀察到前述的問題,因此可以判定測試MM在測試環境上發現的問題是最近引入的,時間範圍不超過2個星期,因爲那段時間項目組早已切換爲兩週一迭代的節奏。
檢查富文本編輯器相關代碼的提交記錄,發現最近的提交記錄遠在幾個月前,因此基本可以排除富文本編輯器自身代碼的問題。
腫麼搞呢?似乎進入了死衚衕。看來常規的方法都不見效,只能逐一排查代碼提交記錄了。
幸運的是提交記錄不多,10分鐘之內被Jackie掃描了一遍;大部分提交記錄都是清白了,唯一可疑的提交記錄來自於Jackie本人,果然這個問題只能由Jackie來定位和分析。爲了解決AppScan報告中提到的“HTTP響應缺少安全頭部”的警告,Jackie在發現問題的那天早上修改了Tomcat的配置,增加了安全頭部相關的過濾器,而晚上留在辦公室加班,目的就是要確認前述的警告是否已消除。

爲了確認前述問題和HTTP安全頭部的相關性,Jackie手工修改測試環境上Tomcat的配置,去掉了增加安全頭部的過濾器,重啓Tomcat後嘗試重現問題,驚喜的發現,富文本編輯器內的圖片恢復正常呈現,這說明HTTP響應增加安全頭部之後,對基本功能產生了影響。

當前啓用了HTTP協議的安全頭部的如下幾個:

Strict-Transport-Security
X-Frame-Options
X-Content-Type-Options
X-XSS-Protection
範圍比較小,逐個排查之後,發現前述問題現象和X-Content-Type-Options相關,因此決定仍然啓用HTTP安全頭部的輸出,但禁用X-Content-Type-Options,富文本編輯器內的圖片可以正常呈現,同時不會對安全性造成很大的影響。

本來覺得修改Tomcat的配置和業務不相關,不會有什麼問題,也沒有過基本功能,結果偏偏天不遂人願,還真讓測試MM發現個詭異問題。看來僥倖心理不能有,該做的工作不能省,否則就得加班、加倍的補回來。

下面使用最少的樣例代碼來說明問題是如何發生的。

問題是如何發生的
準備復現環境
jsp頁面
<%@ page session=“false” pageEncoding=“UTF-8” contentType=“text/html; charset=UTF-8” %>

<%=request.getServletContext().getServerInfo() %>
FileDownload
</body>
GetPicture的實現 如下這段代碼的實現存在問題,使用流方式返回數據時,沒有顯式指定Content-Type。

package com.struts2.servlets;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;

public class GetPictureServlet extends HttpServlet {

private static final long serialVersionUID = -5935833295545479697L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {          
    String path = req.getServletContext().getRealPath("");

    byte[] buffer = new byte[4096];
    int count = 0;
    InputStream is = null;
    OutputStream os = null;

    try
    {
        is = new FileInputStream(new File(path, "tomcat.png"));
        os = resp.getOutputStream();

        while ((count = is.read(buffer)) > 0) {
            os.write(buffer, 0, count);
        }
    }
    catch (IOException e)
    {
        e.printStackTrace();
    }
    finally
    {
        IOUtils.closeQuietly(is);
        IOUtils.closeQuietly(os);
    }
}

}
web.xml

GetPictureServlet
com.struts2.servlets.GetPictureServlet


GetPictureServlet
/GetPicture

使用瀏覽器觀察
重溫一些安全相關的HTTP響應頭中對X-Content-Type-Options的介紹。

互聯網上的資源有各種類型,通常瀏覽器會根據響應頭的Content-Type字段來分辨它們的類型。例如:”text/html”代表html文檔,”image/png”是PNG圖片,”text/css”是CSS樣式文檔。然而,有些資源的Content-Type是錯的或者未定義。這時,某些瀏覽器會啓用MIME-sniffing來猜測該資源的類型,解析內容並執行。

使用瀏覽器調試面板來觀察HTTP響應的頭部,對上文做驗證。

未啓用HttpHeaderSecurityFilter時,HTTP響應的頭部如下
Content-Length:5103
Date:Mon, 02 May 2016 05:07:22 GMT
Server:Apache-Coyote/1.1
修改$CATALINA_BASE/conf/web.xml,啓用HttpHeaderSecurityFilter

httpHeaderSecurity
org.apache.catalina.filters.HttpHeaderSecurityFilter
true

使用瀏覽器的調試面板觀察Tomcat響應瀏覽器請求時的HTTP頭部

Cache-Control:private
Content-Length:5103
Date:Mon, 02 May 2016 05:42:00 GMT
Expires:Thu, 01 Jan 1970 08:00:00 CST
Server:Apache-Coyote/1.1
Strict-Transport-Security:max-age=30;includeSubDomains
X-Content-Type-Options:nosniff
X-Frame-Options:SAMEORIGIN
X-XSS-Protection:1; mode=block
此時,使用瀏覽器訪問頁面時,圖片不能正常呈現。

修改$CATALINA_BASE/conf/web.xml,禁用X-Content-Type-Options特性

httpHeaderSecurity
org.apache.catalina.filters.HttpHeaderSecurityFilter
true

blockContentTypeSniffingEnabled
false


使用瀏覽器的調試面板觀察Tomcat響應瀏覽器請求時的HTTP頭部

Cache-Control:private
Content-Length:5103
Date:Mon, 02 May 2016 05:50:39 GMT
Expires:Thu, 01 Jan 1970 08:00:00 CST
Server:Apache-Coyote/1.1
Strict-Transport-Security:max-age=30;includeSubDomains
X-Frame-Options:SAMEORIGIN
X-XSS-Protection:1; mode=block
此時,使用瀏覽器訪問頁面時,圖片可以正常呈現。

修改$CATALINA_BASE/conf/web.xml,恢復X-Content-Type-Options特性

httpHeaderSecurity
org.apache.catalina.filters.HttpHeaderSecurityFilter
true

修改GetPictureServlet類的實現,寫入圖片流前先設置HTTP響應頭部Content-Type,取值爲image/png

resp.setHeader(“Content-Type”, “image/png”);
使用瀏覽器的調試面板觀察Tomcat響應瀏覽器請求時的HTTP頭部

Cache-Control:private
Content-Length:5103
Content-Type:image/png
Date:Thu, 05 May 2016 15:38:12 GMT
Expires:Thu, 01 Jan 1970 08:00:00 CST
Server:Apache-Coyote/1.1
Strict-Transport-Security:max-age=30;includeSubDomains
X-Content-Type-Options:nosniff
X-Frame-Options:SAMEORIGIN
X-XSS-Protection:1; mode=block
此時,使用瀏覽器訪問頁面時,圖片可以正常呈現。

結論
按照減少 MIME 類型的安全風險的介紹,IE的行爲受X-Content-Type-Options的影響,如果Web應用沒有返回Content-Type,那麼IE9、IE11將拒絕加載相關資源。

如果服務器發送響應頭 “X-Content-Type-Options: nosniff”,則 script 和 styleSheet 元素會拒絕包含錯誤的 MIME 類型的響應。這是一種安全功能,有助於防止基於 MIME 類型混淆的攻擊。

從前述的測試結果看,的確證實了X-Content-Type-Options對IE9、IE11的影響。

但仍有不明之事,文章減少 MIME 類型的安全風險只提到了script和stylesheet標籤,沒有提到img標籤,不瞭解爲什麼X-Content-Type-Options對圖片的加載也會產生影響。後來使用Windows 10的Edge做驗證,發現Edge也存在相同的問題,只要啓用了X-Content-Type-Options,那麼圖片必定呈現不出來。Jackie猜,這也許是文檔太舊了,或者是Jackie沒有找到最新的文檔。

另外按照Jerry Qu的文章一些安全相關的HTTP響應頭的描述,X-Content-Type-Options應該會影響Chrome的行爲,但從測試結果看,使用img標籤加載圖片時,如果Web應用沒有返回Content-Type,無論是否啓用X-Content-Type-Options,Chrome都可以正常呈現圖片,這一點比較奇怪。

參考資料
一些安全相關的HTTP響應頭
header的安全配置指南
ZT header的安全配置指南
減少 MIME 類型的安全風險

若非註明,均爲原創,歡迎轉載,轉載請註明來源:HTTP協議安全頭部X-Content-Type-Options引入的問題
鏈接地址:http://www.jackieathome.net/archives/369.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章