轉載: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” %>
</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