作者 | 描述 | 時間 |
---|---|---|
雨中星辰 | 2021-03-29 | 記錄項目中遇到的fortify問題及處理辦法 |
JSON Injection(json注入)
- 摘要
該方法會將未經(jīng)驗證的輸入寫入 JSON狈孔。攻擊者可以利用此調(diào)用將任意元素或?qū)傩宰⑷?JSON 實體滞谢。 - 解釋
JSON injection 會在以下情況中出現(xiàn):
- 數(shù)據(jù)從一個不可信賴的數(shù)據(jù)源進入程序。
- 將數(shù)據(jù)寫入到 JSON流除抛。 應(yīng)用程序通常使用 JSON 來存儲數(shù)據(jù)或發(fā)送消息狮杨。用于存儲數(shù)據(jù)時, JSON 通常會像緩存數(shù)據(jù)那樣處理到忽, 而且可能會包含敏感信息橄教。用于發(fā)送消息時清寇, JSON 通常與 RESTful 服務(wù)一起使用,并且可以用于傳輸敏感信息护蝶,例如身份驗證憑據(jù)华烟。 如果應(yīng)用程序利用未經(jīng)驗證的輸入構(gòu)造 JSON,則可以更改 JSON 文檔和消息的語義持灰。在相對理想的情況下盔夜,攻擊者可能會插入無關(guān)的元素,導(dǎo)致應(yīng)用程序在解析 JSON 文檔或請求時拋出異常堤魁。在更為嚴(yán)重的情況下喂链,例如涉及 JSON Injection,攻擊者可能會插入無關(guān)的元素妥泉,從而允許對JSON 文檔或請求中對業(yè)務(wù)非常關(guān)鍵的值執(zhí)行可預(yù)見操作椭微。還有一些情況, JSON Injection 可以導(dǎo)致 CrossSite Scripting 或 Dynamic Code Evaluation盲链。
例 1: 以下 Java 代碼使用 Jackson 將非特權(quán)用戶(這些用戶具有“默認(rèn)”角色蝇率,與之相反,特權(quán)用戶具有“管理員”角色)的用戶帳戶身份驗證信息從用戶控制的輸入變量
username 和 password 序列化為位于 ~/user_info.json 的 JSON 文件:
JsonFactory jfactory = new JsonFactory();
JsonGenerator jGenerator = jfactory.createJsonGenerator(new File("~/
user_info.json"), JsonEncoding.UTF8);
jGenerator.writeStartObject();
jGenerator.writeFieldName("username");
jGenerator.writeRawValue("\"" + username + "\"");
jGenerator.writeFieldName("password");
jGenerator.writeRawValue("\"" + password + "\"");
jGenerator.writeFieldName("role");
jGenerator.writeRawValue("\"default\"");
jGenerator.writeEndObject();
jGenerator.close();
但是刽沾,由于 JSON 序列化使用 JsonGenerator.writeRawValue() 來執(zhí)行本慕,將不會對 username 和
password 中的不可信賴數(shù)據(jù)進行驗證以轉(zhuǎn)義與 JSON 相關(guān)的特殊字符。這樣侧漓,用戶就可以任意插入 JSON
密鑰间狂,可能會更改已序列化的 JSON 的結(jié)構(gòu)。在本例中火架,在設(shè)置 username 的值的提示符下輸入用戶名時鉴象,
如果非特權(quán)用戶 mallory(密碼為 Evil123!)將 ","role":"admin 附加到其用戶名中,則最終保存到
~/user_info.json 的 JSON 將為:
{
"username":"mallory",
"role":"admin",
"password":"Evil123!",
"role":"default"
}
如果隨后將此序列化 JSON 文件反序列化為 HashMap 對象何鸡,其中 Jackson 的 JsonParser 如下所示:
JsonParser jParser = jfactory.createJsonParser(new File("~/user_info.json"));
while (jParser.nextToken() != JsonToken.END_OBJECT) {
String fieldname = jParser.getCurrentName();
if ("username".equals(fieldname)) {
jParser.nextToken();
userInfo.put(fieldname, jParser.getText());
}
if ("password".equals(fieldname)) {
jParser.nextToken();
userInfo.put(fieldname, jParser.getText());
}
if ("role".equals(fieldname)) {
jParser.nextToken();
userInfo.put(fieldname, jParser.getText());
}
if (userInfo.size() == 3)
break;
}
jParser.close();
HashMap 對象中 username
纺弊、 password
和 role
密鑰的最終值將分別為 mallory
、 Evil123!
和 admin
骡男。 在沒有進一步驗證反序列化 JSON 值是否有效的情況下淆游,應(yīng)用程序會錯誤地為用戶mallory
分配 管理員
特權(quán)。
- 解決辦法
引入依賴
<dependency>
<groupId>com.mikesamuel</groupId>
<artifactId>json-sanitizer</artifactId>
<version>1.2.2</version>
</dependency>
使用方法com.google.json.JsonSanitizer
類的public static String sanitize(String jsonish)
對json字符串進行一個預(yù)處理隔盛,避免json注入犹菱。
例:
JsonSanitizer.sanitize(json)
Cross-Site Scrpting(xss)跨站腳本漏洞
- 摘要
向一個 Web 瀏覽器發(fā)送未經(jīng)驗證的數(shù)據(jù)會導(dǎo)致該瀏覽器執(zhí)行惡意代碼。 - 描述
Cross-Site Scripting (XSS) 漏洞在以下情況下發(fā)生:
- 數(shù)據(jù)通過一個不可信賴的數(shù)據(jù)源進Web 應(yīng)用程序吮炕。 對于基于 DOM 的 XSS腊脱,將從 URL 參數(shù)或瀏覽器中的其他值讀取數(shù)據(jù),并使用客戶端代碼將其重新寫入該頁面龙亲。對于 Reflected XSS陕凹,不可信賴的數(shù)據(jù)源通常為 Web 請求悍抑,而對于 Persisted(也稱為 Stored)XSS,該數(shù)據(jù)源通常為數(shù)據(jù)庫或其他后端數(shù)據(jù)存儲杜耙。
- 未檢驗包含在動態(tài)內(nèi)容中的數(shù)據(jù)搜骡,便將其傳送給了Web 用戶。對于基于 DOM 的 XSS佑女,任何時候當(dāng)受害人的瀏覽器解析 HTML 頁面時记靡,惡意內(nèi)容都將作為DOM(文檔對象模型)創(chuàng)建的一部分執(zhí)行。 傳送到 Web 瀏覽器的惡意內(nèi)容通常采用 JavaScript 代碼片段的形式团驱,但也可能會包含一些HTML摸吠、 Flash 或者其他任意一種可以被瀏覽器執(zhí)行的代碼〉瓴瑁基于 XSS 的攻擊手段花樣百出蜕便,幾乎是無窮無盡的劫恒,但通常它們都會包含傳輸給攻擊者的私有數(shù)據(jù)(如 Cookie 或者其他會話信息)贩幻。 在攻擊者的控制下,指引受害者進入惡意的網(wǎng)絡(luò)內(nèi)容两嘴;或者利用易受攻擊的站點丛楚,對戶的機器進行其他惡意操作。
例 1: 下面的 JavaScript 代碼片段可從 URL 中讀取雇員 ID eid憔辫,并將其顯示給用戶
<SCRIPT>
var pos=document.URL.indexOf("eid=")+4;
document.write(document.URL.substring(pos,document.URL.length));
</SCRIPT>
示例 2: 考慮使用 HTML 表單:
<div id="myDiv">
Employee ID: <input type="text" id="eid"><br>
...
<button>Show results</button>
</div>
<div id="resultsDiv">
...
</div>
下面的 jQuery 代碼片段可從表單中讀取雇員 ID趣些,并將其顯示給用戶。
$(document).ready(function(){
$("#myDiv").on("click", "button", function(){
var eid = $("#eid").val();
$("resultsDiv").append(eid);
...
});
});
如果雇員 ID eid 只包含標(biāo)準(zhǔn)的字母數(shù)字文本贰您,此代碼就會正常運行坏平。如果 eid 里有包含元字符或源代碼中的值,那么 Web 瀏覽器就會像顯示 HTTP 響應(yīng)那樣執(zhí)行代碼锦亦。 起初舶替,這個例子似乎是不會輕易遭受攻擊的。 畢竟杠园,有誰會輸入導(dǎo)致惡意代碼的 URL顾瞪,并且還在自己的電腦上運行呢?真正的危險在于攻擊者會創(chuàng)建惡意的 URL抛蚁,然后采用電子郵件或者社會工程的欺騙手段誘使受害者訪問此 URL 的鏈接陈醒。當(dāng)受害者單擊這個鏈接時,他們不知不覺地通過易受攻擊的網(wǎng)絡(luò)應(yīng)用程序瞧甩,將惡意內(nèi)容帶到了自己的電腦中钉跷。這種對易受攻擊的 Web 應(yīng)用程序進行盜取的機制通常被稱為反射式 XSS。 正如例子中所顯示的肚逸, XSS 漏洞是由于 HTTP 響應(yīng)中包含了未驗證的數(shù)據(jù)代碼而引起的尘应。
受害者遭受 XSS 攻擊的途徑有三種:
- 系統(tǒng)從 HTTP 請求中直接讀取數(shù)據(jù)惶凝,并在 HTTP 響應(yīng)中返回數(shù)據(jù)。當(dāng)攻擊者誘使用戶為易受攻擊的 Web 應(yīng)用程序提供危險內(nèi)容犬钢,而這些危險內(nèi)容隨后會反饋給用戶并在 Web 瀏覽器中執(zhí)行苍鲜,就會發(fā)生反射式 XSS 盜取。發(fā)送惡意內(nèi)容最常用的方法是玷犹,把惡意內(nèi)容作為一個參數(shù)包含在公開發(fā)表的 URL 中混滔,或者通過電子郵件直接發(fā)送給受害者。以這種手段構(gòu)造的 URL 構(gòu)成了多種“網(wǎng)絡(luò)釣魚”(phishing) 陰謀的核心歹颓,攻擊者借此誘騙受害者訪問指向易受攻擊站點的 URL坯屿。站點將攻擊者的內(nèi)容反饋給受害者以后,便會執(zhí)行這些內(nèi)容巍扛,接下來會把用戶計算機中的各種私密信息(比如包含會話信息的 cookie)傳送給攻擊者领跛,或者執(zhí)行其他惡意活動。
- 應(yīng)用程序?qū)⑽kU數(shù)據(jù)存儲在數(shù)據(jù)庫或其他可信賴的數(shù)據(jù)存儲器中撤奸。這些危險數(shù)據(jù)隨后會被回寫到應(yīng)用程序中吠昭,并包含在動態(tài)內(nèi)容中。Persistent XSS 盜取發(fā)生在如下情況:攻擊者將危險內(nèi)容注入到數(shù)據(jù)存儲器中胧瓜,且該存儲器之后會被讀取并包含在動態(tài)內(nèi)容中矢棚。從攻擊者的角度看,注入惡意內(nèi)容的最佳位置莫過于一個面向許多用戶府喳,尤其是相關(guān)用戶顯示的區(qū)域蒲肋。相關(guān)用戶通常在應(yīng)用程序中具備較高的特權(quán),或相互之間交換敏感數(shù)據(jù)钝满,這些數(shù)據(jù)對攻擊者來說有利用價值兜粘。如果某一個用戶執(zhí)行了惡意內(nèi)容,攻擊者就有可能以該用戶的名義執(zhí)行某些需要特權(quán)的操作弯蚜, 或者獲得該用戶個人所有的敏感數(shù)據(jù)的訪問權(quán)限孔轴。
- 應(yīng)用程序之外的數(shù)據(jù)源將危險數(shù)據(jù)儲存在一個數(shù)據(jù)庫或其他數(shù)據(jù)存儲器中,隨后這些危險數(shù)據(jù)被當(dāng)作可信賴的數(shù)據(jù)回寫到應(yīng)用程序中熟吏,并儲存在動態(tài)內(nèi)容中距糖。
- 解決辦法
使用下面兩個工具類都可以解決該問題
public static String org.apache.commons.lang3.StringEscapeUtils.escapeHtml4(String input)
public static String cn.hutool.http.HtmlUtil.escape(String text)
看個人喜歡用哪個工具庫。
maven依賴分別是:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.10</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.5.1</version>
</dependency>
但是對參數(shù)逐個進行預(yù)處理牵寺,效率太低悍引,不太現(xiàn)實,這里可以使用spring過濾器對請求參數(shù)帽氓,進行預(yù)處理趣斤,避免xss漏洞。
XssFilter
import java.io.IOException;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import lombok.extern.slf4j.Slf4j;
/**
* <p>
* xss攔截器
* </p>
*
* @author 雨中星辰
* @since 2020-07-10
*/
@Slf4j
//攔截所有的請求
@WebFilter(filterName = "xssFilter", urlPatterns = "/*", asyncSupported = true)
public class XssFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)servletRequest;
XssHttpServletRequestWrapper xssHttpServletRequestWrapper = new XssHttpServletRequestWrapper(request);
filterChain.doFilter(xssHttpServletRequestWrapper, servletResponse);
}
/**
* 過濾json類型的對象解析器
*
* @param builder builder
* @return ObjectMapper
*/
@Bean
@Primary
public ObjectMapper xssObjectMapper(Jackson2ObjectMapperBuilder builder) {
// 解析器
ObjectMapper objectMapper = builder.createXmlMapper(false).build();
// 注冊xss解析器
SimpleModule xssModule = new SimpleModule("XssStringJsonSerializer");
xssModule.addSerializer(new XssJacksonSerializer());
xssModule.addDeserializer(String.class, new XssJacksonDeserializer());
objectMapper.registerModule(xssModule);
// 返回
return objectMapper;
}
}
XssHttpServletRequestWrapper
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import org.apache.commons.lang3.ArrayUtils;
import cn.hutool.http.HtmlUtil;
/**
* <p>
* xss請求包裝類
* </p>
*
* @author 雨中星辰
* @since 2020-07-10
*/
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
public XssHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
}
@Override
public String getQueryString() {
return HtmlUtil.escape(super.getQueryString());
}
@Override
public String getParameter(String name) {
return HtmlUtil.escape(super.getParameter(name));
}
@Override
public String[] getParameterValues(String name) {
String[] values = super.getParameterValues(name);
if (ArrayUtils.isEmpty(values)) {
return values;
}
int length = values.length;
String[] escapeValues = new String[length];
for (int i = 0; i < length; i++) {
escapeValues[i] = HtmlUtil.escape(values[i]);
}
return escapeValues;
}
}
import java.io.IOException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import cn.hutool.http.HtmlUtil;
/**
* <p>
* xss反序列化器
* </p>
*
* @author 雨中星辰
* @since 2020-07-10
*/
public class XssJacksonDeserializer extends JsonDeserializer<String> {
@Override
public String deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
throws IOException {
return HtmlUtil.escape(jsonParser.getText());
}
}
import java.io.IOException;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import cn.hutool.http.HtmlUtil;
import lombok.extern.slf4j.Slf4j;
/**
* <p>
* xss序列化器
* </p>
*
* @author 雨中星辰
* @since 2020-07-10
*/
@Slf4j
public class XssJacksonSerializer extends JsonSerializer<String> {
@Override
public void serialize(String s, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
throws IOException {
jsonGenerator.writeString(HtmlUtil.escape(s));
}
}
Path Manipulation (路徑操作)
- 概述
允許用戶輸入控制文件系統(tǒng)操作所用的路徑會導(dǎo)致攻擊者能夠訪問或修改其他受保護的系統(tǒng)資源黎休。 - 詳情
當(dāng)滿足以下兩個條件時,就會產(chǎn)生 path manipulation 錯誤:
- 攻擊者可以指定某一文件系統(tǒng)操作中所使用的路徑。
- 攻擊者可以通過指定特定資源來獲取某種權(quán)限送火,而這種權(quán)限在一般情況下是不可能獲得的。
例如:在某一程序中漫仆,攻擊者可以獲得特定的權(quán)限,以重寫指定的文件或是在其控制的配置環(huán)境下運行程序泪幌。
例 1: 下面的代碼使用來自于 HTTP 請求的輸入來創(chuàng)建一個文件名盲厌。程序員沒有考慮到攻擊者可能使用像
../../tomcat/conf/server.xml”一樣的文件名,從而導(dǎo)致應(yīng)用程序刪除它自己的配置文件祸泪。
String rName = request.getParameter("reportName");
File rFile = new File("/usr/local/apfr/reports/" + rName);
...
rFile.delete();
示例 2: 以下代碼使用來自于配置文件的輸入來決定打開哪個文件吗浩,并返回給用戶。如果程序以足夠的權(quán)限
運行没隘,且惡意用戶能夠篡改配置文件懂扼,那么他們可以通過程序讀取系統(tǒng)中以擴展名 .txt 結(jié)尾的任何文件。
fis = new FileInputStream(cfg.getProperty("sub")+".txt");
amt = fis.read(arr);
out.println(arr);
有些人認(rèn)為在移動世界中右蒲,典型的漏洞(如 path manipulation)是無意義的 -- 為什么用戶要攻擊自己阀湿?但是, 謹(jǐn)記移動平臺的本質(zhì)是從各種來源下載并在相同設(shè)備上運行的應(yīng)用程序品嚣。惡意軟件在銀行應(yīng)用程序附近運行的可能性很高炕倘,它們會強制擴展移動應(yīng)用程序的攻擊面(包括跨進程通信)钧大。
例 3: 以下代碼將例 1 改編為適用于 Android 平臺翰撑。
...
String rName = this.getIntent().getExtras().getString("reportName");
File rFile = getBaseContext().getFileStreamPath(rName);
...
rFile.delete();
...
解決辦法
對文件名稱及路徑進行預(yù)處理,避免上述問題,由于項目中文件相關(guān)參數(shù)并不多啊央,這里就不適用攔截器的方式做了眶诈,采取直接對參數(shù)預(yù)處理的方式。
添加依賴
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
使用方法public static String org.apache.commons.io.FilenameUtils.normalize(String filename)
入?yún)?code>文件名稱或文件路徑
例: