国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Java代碼漏洞檢測(cè)-常見(jiàn)漏洞與修復(fù)建議

這篇具有很好參考價(jià)值的文章主要介紹了Java代碼漏洞檢測(cè)-常見(jiàn)漏洞與修復(fù)建議。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

背景:
在工作中,項(xiàng)目交付團(tuán)隊(duì)在交付項(xiàng)目時(shí),客戶方可能會(huì)有項(xiàng)目安全要求,會(huì)使用一些第三方工具(奇安信等)對(duì)項(xiàng)目代碼進(jìn)行掃描,特別是一些對(duì)安全性要求比較高的企業(yè),比如涉及到一些證券公司、銀行、金融等。他們會(huì)在項(xiàng)目上線前進(jìn)行代碼安全檢測(cè),通過(guò)了對(duì)方才會(huì)發(fā)布上線。

銀保等金融類企業(yè)信息安全處的安全掃描一般分為五項(xiàng),主機(jī)漏洞,主機(jī)基線漏洞,代碼檢測(cè)漏洞,滲透測(cè)試漏洞,WEB掃描漏洞,以下漏洞為代碼檢漏洞.

代碼檢測(cè)常用工具:奇安信代碼衛(wèi)士

java owasp.encoder.encode,WEB安全

跨站腳本

高危:存儲(chǔ)型XSS

存儲(chǔ)型XSS是指應(yīng)用程序通過(guò)Web請(qǐng)求獲取不可信賴的數(shù)據(jù),并且在未檢驗(yàn)數(shù)據(jù)是否存在XSS代碼的情況下,將其存入數(shù)據(jù)庫(kù)。當(dāng)程序下一次從數(shù)據(jù)庫(kù)中獲取該數(shù)據(jù)時(shí),致使頁(yè)面再次執(zhí)行XSS代碼。存儲(chǔ)型XSS可以持續(xù)攻擊用戶,在用戶提交了包含XSS代碼的數(shù)據(jù)存儲(chǔ)到數(shù)據(jù)庫(kù)后,每當(dāng)用戶在瀏覽網(wǎng)頁(yè)查詢對(duì)應(yīng)數(shù)據(jù)庫(kù)中的數(shù)據(jù)時(shí),那些包含XSS代碼的數(shù)據(jù)就會(huì)在服務(wù)器解析并加載,當(dāng)瀏覽器讀到XSS代碼后,會(huì)當(dāng)做正常的HTML和JS解析并執(zhí)行,于是發(fā)生存儲(chǔ)型XSS攻擊。

**例如**:下面JSP代碼片段的功能是根據(jù)一個(gè)已知用戶雇員ID(id)從數(shù)據(jù)庫(kù)中查詢出該用戶的地址,并顯示在JSP頁(yè)面上。

<%

...

Statement stmt = conn.createStatement();

ResultSet rs = stmt.executeQuery("select * from users where id =" + id);

String address = null;

if (rs != null) {

????rs.next();

????address = rs.getString("address");

}

%>

家庭地址: <%= address %>

如果address的值是由用戶提供的,且存入數(shù)據(jù)庫(kù)時(shí)沒(méi)有進(jìn)行合理的校驗(yàn),那么攻擊者就可以利用上面的代碼進(jìn)行存儲(chǔ)型XSS攻擊。

修復(fù)建議

為了避免存儲(chǔ)型XSS攻擊,建議采用以下方式進(jìn)行防御:

1.對(duì)從數(shù)據(jù)庫(kù)或其它后端數(shù)據(jù)存儲(chǔ)獲取不可信賴的數(shù)據(jù)進(jìn)行合理驗(yàn)證(如年齡只能是數(shù)字),對(duì)特殊字符(如`<、>、'、"`以及`<script>、javascript`等進(jìn)行過(guò)濾。

2.根據(jù)數(shù)據(jù)將要置于HTML上下文中的不同位置(HTML標(biāo)簽、HTML屬性、JavaScript腳本、CSS、URL),對(duì)所有不可信數(shù)據(jù)進(jìn)行恰當(dāng)?shù)妮敵鼍幋a。

**例如**:采用OWASP ESAPI對(duì)數(shù)據(jù)輸出HTML上下文中不同位置,編碼方法如下。

//HTML encode

ESAPI.encoder().encodeForHTML(inputData);

//HTML attribute encode

ESAPI.encoder().encodeForHTMLAttribute(inputData);

//JavaScript encode

ESAPI.encoder().encodeForJavaScript(inputData);

//CSS encode

ESAPI.encoder().encodeForCSS(inputData);

//URL encode

ESAPI.encoder().encodeForURL(inputData);

3.設(shè)置HttpOnly屬性,避免攻擊者利用跨站腳本漏洞進(jìn)行Cookie劫持攻擊。在Java EE中,給Cookie添加HttpOnly的代碼如下:

response.setHeader("Set-Cookie","cookiename=cookievalue; path=/; Domain=domainvaule; Max-age=seconds; HttpOnly");

Cookie屬性

Name:Cookie名

Value:Cookie值

Domain:Cookie的域。如果設(shè)成.test.com,那么子域名a.test.com和b.test.com,都可以使用.test.com的Cookie。

Path:Cookie的路徑。如果設(shè)成/path/,則只有路徑為/path/的頁(yè)面可以訪問(wèn)該Cookie。如果設(shè)為/,則本域名下的所有頁(yè)面都可以訪問(wèn)該Cookie。

Expires / Max-Age:Cookie的超時(shí)時(shí)間。若設(shè)置其值為一個(gè)時(shí)間,那么當(dāng)?shù)竭_(dá)此時(shí)間后,此Cookie失效。不設(shè)置的話默認(rèn)值是Session,意思是Cookie會(huì)和Session一起失效。當(dāng)瀏覽器關(guān)閉(不是瀏覽器標(biāo)簽頁(yè),而是整個(gè)瀏覽器)后,此Cookie失效。

Size:Cookie大小。

HttpOnly:若此屬性為true,則只有在http請(qǐng)求頭中會(huì)帶有此Cookie的信息,而不能通過(guò)document.cookie來(lái)訪問(wèn)此Cookie。

Secure:設(shè)置是否只能通過(guò)https來(lái)傳遞此條Cookie。

SameSite:用來(lái)防止 CSRF 攻擊和用戶追蹤??梢栽O(shè)置三個(gè)值:Strict、Lax 和 None。

Strict:Strict最為嚴(yán)格,完全禁止第三方 Cookie,跨站點(diǎn)時(shí),任何情況下都不會(huì)發(fā)送 Cookie。換言之,只有當(dāng)前網(wǎng)頁(yè)的 URL 與請(qǐng)求目標(biāo)一致,才會(huì)帶上 Cookie。

Lax:Lax規(guī)則稍稍放寬,大多數(shù)情況也是不發(fā)送第三方 Cookie,但是導(dǎo)航到目標(biāo)網(wǎng)址的 Get 請(qǐng)求除外。

None:關(guān)閉SameSite屬性,提是必須同時(shí)設(shè)置Secure屬性(Cookie 只能通過(guò) HTTPS 協(xié)議發(fā)送),否則無(wú)效。

Priority:優(yōu)先級(jí)。定義了三種優(yōu)先級(jí),Low/Medium/High,當(dāng)Cookie數(shù)量超出時(shí),低優(yōu)先級(jí)的Cookie會(huì)被優(yōu)先清除。

高危:反射型XSS

反射型XSS是指應(yīng)用程序通過(guò)Web請(qǐng)求獲取不可信賴的數(shù)據(jù),并在未檢驗(yàn)數(shù)據(jù)是否存在惡意代碼的情況下,將其發(fā)送給用戶。反射型XSS一般可以由攻擊者構(gòu)造帶有惡意代碼參數(shù)的URL來(lái)實(shí)現(xiàn),在構(gòu)造的URL地址被打開(kāi)后,其中包含的惡意代碼參數(shù)被瀏覽器解析和執(zhí)行。這種攻擊的特點(diǎn)是非持久化,必須用戶點(diǎn)擊包含惡意代碼參數(shù)的鏈接時(shí)才會(huì)觸發(fā)。

**例如**:下面JSP代碼片段的功能是從HTTP請(qǐng)求中讀取輸入的用戶名(username)并顯示到頁(yè)面。

<%String name= request.getParameter("username"); %>

姓名: <%= name%>

修復(fù)建議

如果name里有包含惡意代碼,那么Web瀏覽器就會(huì)像顯示HTTP響應(yīng)那樣執(zhí)行該代碼,應(yīng)用程序?qū)⑹艿椒瓷湫蚗SS攻擊。

為了避免反射型XSS攻擊,建議采用以下方式進(jìn)行防御:

1.對(duì)用戶的輸入進(jìn)行合理驗(yàn)證(如年齡只能是數(shù)字),對(duì)特殊字符(如`<、>、'、"`以及`<script>、javascript`等進(jìn)行過(guò)濾。

2.根據(jù)數(shù)據(jù)將要置于HTML上下文中的不同位置(HTML標(biāo)簽、HTML屬性、JavaScript腳本、CSS、URL),對(duì)所有不可信數(shù)據(jù)進(jìn)行恰當(dāng)?shù)妮敵鼍幋a。

**例如**:采用OWASP ESAPI對(duì)數(shù)據(jù)輸出HTML上下文中不同位置,編碼方法如下。

//HTML encode

ESAPI.encoder().encodeForHTML(inputData);

//HTML attribute encode

ESAPI.encoder().encodeForHTMLAttribute(inputData);

//JavaScript encode

ESAPI.encoder().encodeForJavaScript(inputData);

//CSS encode

ESAPI.encoder().encodeForCSS(inputData);

//URL encode

ESAPI.encoder().encodeForURL(inputData);

3.設(shè)置HttpOnly屬性,避免攻擊者利用跨站腳本漏洞進(jìn)行Cookie劫持攻擊。在Java EE中,給Cookie添加HttpOnly的代碼如下:

response.setHeader("Set-Cookie","cookiename=cookievalue; path=/; Domain=domainvaule; Max-age=seconds; HttpOnly");

Cookie屬性

Name:Cookie名

Value:Cookie值

Domain:Cookie的域。如果設(shè)成.test.com,那么子域名a.test.com和b.test.com,都可以使用.test.com的Cookie。

Path:Cookie的路徑。如果設(shè)成/path/,則只有路徑為/path/的頁(yè)面可以訪問(wèn)該Cookie。如果設(shè)為/,則本域名下的所有頁(yè)面都可以訪問(wèn)該Cookie。

Expires / Max-Age:Cookie的超時(shí)時(shí)間。若設(shè)置其值為一個(gè)時(shí)間,那么當(dāng)?shù)竭_(dá)此時(shí)間后,此Cookie失效。不設(shè)置的話默認(rèn)值是Session,意思是Cookie會(huì)和Session一起失效。當(dāng)瀏覽器關(guān)閉(不是瀏覽器標(biāo)簽頁(yè),而是整個(gè)瀏覽器)后,此Cookie失效。

Size:Cookie大小。

HttpOnly:若此屬性為true,則只有在http請(qǐng)求頭中會(huì)帶有此Cookie的信息,而不能通過(guò)document.cookie來(lái)訪問(wèn)此Cookie。

Secure:設(shè)置是否只能通過(guò)https來(lái)傳遞此條Cookie。

SameSite:用來(lái)防止 CSRF 攻擊和用戶追蹤??梢栽O(shè)置三個(gè)值:Strict、Lax 和 None。

Strict:Strict最為嚴(yán)格,完全禁止第三方 Cookie,跨站點(diǎn)時(shí),任何情況下都不會(huì)發(fā)送 Cookie。換言之,只有當(dāng)前網(wǎng)頁(yè)的 URL 與請(qǐng)求目標(biāo)一致,才會(huì)帶上 Cookie。

Lax:Lax規(guī)則稍稍放寬,大多數(shù)情況也是不發(fā)送第三方 Cookie,但是導(dǎo)航到目標(biāo)網(wǎng)址的 Get 請(qǐng)求除外。

None:關(guān)閉SameSite屬性,提是必須同時(shí)設(shè)置Secure屬性(Cookie 只能通過(guò) HTTPS 協(xié)議發(fā)送),否則無(wú)效。

Priority:優(yōu)先級(jí)。定義了三種優(yōu)先級(jí),Low/Medium/High,當(dāng)Cookie數(shù)量超出時(shí),低優(yōu)先級(jí)的Cookie會(huì)被優(yōu)先清除。

輸入驗(yàn)證

高危:路徑遍歷

應(yīng)用程序?qū)τ脩艨煽刂频妮斎胛唇?jīng)合理校驗(yàn),就傳送給一個(gè)文件API。攻擊者可能會(huì)使用一些特殊的字符(如`..`和`/`)擺脫受保護(hù)的限制,訪問(wèn)一些受保護(hù)的文件或目錄。

**例如**:下面代碼片段通過(guò)驗(yàn)證輸入路徑是否以`/safe_dir/`為開(kāi)頭,來(lái)判斷是否進(jìn)行創(chuàng)建、刪除操作。

String path = getInputPath();

if (path.startsWith("/safe_dir/")){

????File f = new File(path);

????f.delete()

}

攻擊者可能提供類似下面的輸入:

`/safe_dir/../important.dat`

程序假定路徑是有效的,因?yàn)樗且訿/safe_dir/`開(kāi)頭的,但是`../`將導(dǎo)致程序刪除`important.dat`文件的父目錄。

修復(fù)建議

預(yù)防路徑遍歷的威脅,有以下三種方法:

1. 程序?qū)Ψ鞘苄诺挠脩糨斎胱鲞^(guò)濾和驗(yàn)證,對(duì)網(wǎng)站用戶提交的文件路徑進(jìn)行硬編碼或統(tǒng)一編碼,過(guò)濾非法字符。

2. 對(duì)文件后綴進(jìn)行白名單控制,拒絕包含了惡意的符號(hào)或空字節(jié)。

3. 合理配置Web服務(wù)器的目錄訪問(wèn)權(quán)限。

高危:基于DOM的XSS[NodeJS]

應(yīng)用程序的客戶端代碼從

document.location

request.url

document.URL

document.referrer

或其他任何攻擊者可以修改的瀏覽器對(duì)象獲取數(shù)據(jù),如果未驗(yàn)證數(shù)據(jù)是否存在惡意代碼的情況下,就將其動(dòng)態(tài)更新到頁(yè)面的DOM節(jié)點(diǎn),應(yīng)用程序?qū)⒁子谑艿交贒OM的XSS攻擊。

**例如**:下面的JavaScript代碼片段可從URL中讀取msg信息,并將其顯示給用戶。

var url=document.URL;

document.write(url.substring(url.indexOf("msg=")+4,url.length);

該段腳本解析URL,讀取msg參數(shù)的值,并將其寫(xiě)入頁(yè)面。如果攻擊者設(shè)計(jì)一個(gè)惡意的URL,并以JavaScript代碼作為msg參數(shù),那么Web瀏覽器就會(huì)像顯示HTTP響應(yīng)那樣執(zhí)行該代碼,應(yīng)用程序?qū)⑹艿交贒OM的XSS攻擊。

修復(fù)建議

基于DOM的XSS是將用戶可控的JavaScript數(shù)據(jù)輸出到HTML頁(yè)面中而產(chǎn)生的漏洞,為了避免基于DOM的XSS攻擊,避免將用戶控制的數(shù)據(jù)直接輸出到DOM或腳本中執(zhí)行。如果不能避免,則應(yīng)進(jìn)行嚴(yán)格的過(guò)濾。

高危:重定向[Java]

重定向漏洞解決方案:Java中的URL重定向漏洞和防范方法-java教程-PHP中文網(wǎng)

應(yīng)用程序允許未驗(yàn)證的用戶輸入控制重定向中的URL,攻擊通過(guò)構(gòu)建URL,使用戶重定向到任意URL,利用這個(gè)漏洞可以誘使用戶訪問(wèn)某個(gè)頁(yè)面,掛馬、密碼記錄、下載任意文件等,常被用來(lái)釣魚(yú)。

**例如**:以下Servlet代碼會(huì)接收前臺(tái)的url參數(shù),然后Servlet進(jìn)行一系列業(yè)務(wù)操作后重定向到該鏈接,一般情況下這個(gè)鏈接可能是默認(rèn)的,例如登陸處登陸成功后跳到首頁(yè),但是這種情況沒(méi)有限制用戶輸入自定義的鏈接。

```java

public?class?RedirectServlet?extends?HttpServlet?{

????protected?void?doGet(HttpServletRequest?request,?HttpServletResponse?response)?throws???ServletException,IOException{

????????...

????????String?query?=?request.getQueryString();

????????if?(query.contains("url"))?{

????????????String?url?=?request.getParameter("url");

????????????response.sendRedirect(url);

????????}

????}

}

```

常見(jiàn)的場(chǎng)景是受害者收到一封電子郵件,指示該用戶打開(kāi)`http://trusted.example.com/ecommerce/redirect.asp?url=www.wilyhacker.com`鏈接,用戶有可能會(huì)打開(kāi)該鏈接,因?yàn)樗麜?huì)認(rèn)為這個(gè)鏈接將轉(zhuǎn)到可信賴的站點(diǎn)。然而,一旦用戶打開(kāi)該鏈接,上面的代碼會(huì)將瀏覽器重定向至`http://www.wilyhacker.com`。很多用戶都被告知,要始終監(jiān)視通過(guò)電子郵件收到的URL,以確保鏈接指向一個(gè)他們所熟知的可信賴站點(diǎn)。盡管如此,如果攻擊者對(duì)目標(biāo)URL進(jìn)行16進(jìn)制編碼:`http://trusted.example.com/ecommerce/redirect.asp?url=%77%69%6C%79%68%61%63%6B%65%72%2E%63%6F%6D`以提高用戶辨別URL的難度。更糟糕的是像這樣的url通過(guò)例如QQ等程序進(jìn)行傳輸?shù)臅r(shí)候,這些程序的安全機(jī)制是不能識(shí)別url參數(shù)中的危險(xiǎn)鏈接的。

修復(fù)建議

防止重定向漏洞的方法是創(chuàng)建一份合法URL列表,用戶只能從中進(jìn)行選擇,進(jìn)行重定向操作。

**例如**:以下Servlet代碼先對(duì)url進(jìn)行判斷,再?zèng)Q定是否重定向到該鏈接。

```java

public?class?RedirectServlet?extends?HttpServlet?{

????protected?void?doGet(HttpServletRequest?request,?HttpServletResponse?response)?throws???ServletException,IOException{

????????...

????????String?query?=?request.getQueryString();

????????if?(query.contains("url"))?{

????????????String?url?=?request.getParameter("url");

????????????if(safeUrls.contains(url)){

????????????????response.sendRedirect(url);

????????????}

????????????...

????????}

????}

}

```

高危:重定向[NodeJS]

應(yīng)用程序允許未驗(yàn)證的用戶輸入控制重定向中的URL,可能會(huì)導(dǎo)致攻擊者發(fā)動(dòng)釣魚(yú)攻擊。

**例1**:以下JavaScript代碼從用戶輸入表單的dest參數(shù)中讀取目的URL,然后在新窗口中打開(kāi)。

dsturl = myForm.dsturl.value;

window.open(dsturl,"newwin");

假如攻擊者可以控制這個(gè)表單,那么用戶就有可能打開(kāi)一個(gè)惡意站點(diǎn)。

**例2**:以下是Node.js可能出現(xiàn)的。

var express = require('express');

var app = express();

app.get('/', function (req, res) {

????res.redirect(req.url);

});

與例1一樣假如攻擊者控制了這個(gè)url,那么就會(huì)導(dǎo)致用戶可能打開(kāi)惡意站點(diǎn)。

修復(fù)建議

js和Node.js都要避免采用不可信數(shù)據(jù)源的數(shù)據(jù)來(lái)構(gòu)造重定向的URL,如果業(yè)務(wù)邏輯需要涉及到用戶輸入,那么就創(chuàng)建一份合法URL列表,用戶只能從中進(jìn)行選擇,進(jìn)行重定向操作。

**例如**:以下代碼中,用戶只能輸入數(shù)字來(lái)選擇URL。

dst = myForm.dst.value;

if(dst == "1"){

????dsturl = "http://www.1.com"

}else if(dst == "2"){

????dsturl = "http://www.2.com"

}else{

????dsturl = "http://www.3.com"

}

window.open(dsturl,"newwin");

中危:HTTP參數(shù)污染[Java]

HTTP參數(shù)污染(HPP)攻擊根據(jù)HTTP協(xié)議中允許同名參數(shù)出現(xiàn)多次,如果程序沒(méi)有正確地檢查用戶輸入,攻擊者可以在傳輸參數(shù)的時(shí)候傳輸key相同而value不同的參數(shù),從而達(dá)到繞過(guò)某些防護(hù)與參數(shù)校驗(yàn)。

如果向Web應(yīng)用程序提交參數(shù),并且如果這些參數(shù)與現(xiàn)有參數(shù)的名稱相同,Web應(yīng)用程序可能會(huì)有下列一種反應(yīng):Web程序可能從第一個(gè)參數(shù)或最后一個(gè)參數(shù)提取數(shù)據(jù),也可能從所有參數(shù)中獲取數(shù)據(jù)并連接起來(lái)。

下面這個(gè)表格列舉了一些常見(jiàn)的Web服務(wù)器對(duì)同樣名稱的參數(shù)出現(xiàn)多次的處理方式:

|Web服務(wù)器|獲取的參數(shù)|

|:-:|:-:|

|ASP.NET/IIS???????????????????????????????|所有參數(shù)組成用逗號(hào)分隔的字符串|

|ASP/IIS???????????????????????????????????|所有參數(shù)組成用逗號(hào)分隔的字符串|

|PHP/Apache????????????????????????????????|最后一個(gè)參數(shù)

|JSP?Servlet/Apache?Tomcat?????????????????|第一個(gè)參數(shù)|

|JSP?Servlet/Oracle?Application?Server?10g?|第一個(gè)參數(shù)|

|IBM?HTTP?Server???????????????????????????|第一個(gè)參數(shù)|

|mod_perl/Apache???????????????????????????|所有參數(shù)成為數(shù)組|

Spring?4?起,`UriTemplate`類可執(zhí)行用于阻止請(qǐng)求參數(shù)注入的編碼。

**例如**:下列代碼使用來(lái)自于HTTP?請(qǐng)求的輸入來(lái)呈現(xiàn)兩個(gè)超鏈接。

```java

????...

????String?lang?=?request.getParameter("lang");

????GetMethod?get?=?new?GetMethod("http://www.codesafe.com");

????get.setQueryString("lang="?+?lang?+?"&id="?+?id);

????get.execute();

????...

```

攻擊者可能會(huì)提供一個(gè)`lang`(例如`en&id=1`),然后攻擊者將可以隨意更改該`id`。

修復(fù)建議

在編譯URL時(shí),應(yīng)對(duì)用戶輸入進(jìn)行驗(yàn)證并過(guò)濾掉多余的參數(shù)(如`&`字符)。

中危:日志偽造[Java]

允許日志記錄未經(jīng)驗(yàn)證的用戶輸入,會(huì)導(dǎo)致日志偽造攻擊。

**例如**:下面代碼片段中,在接收到非法用戶請(qǐng)求時(shí),未進(jìn)行任何數(shù)據(jù)驗(yàn)證情況下,記錄用戶的用戶名。

```java

if?(loginSuccessful)?{

????logger.severe("User?login?succeeded?for:?"?+?username);

}?else?{

????logger.severe("User?login?failed?for:?"?+?username);

}

```

如果沒(méi)有經(jīng)過(guò)凈化處理,那么可能會(huì)出現(xiàn)日志注入攻擊。當(dāng)`username`是jack時(shí),日志信息如下:

```

2013-7-30?java.util.logging.LogManager?log

Server:User?login?failed?for:jack

```

如果日志`username`是一個(gè)多行字符串,如下所示:

```

jack

2013-7-30?java.util.logging.LogManager?log

Server:?User?login?succeeded?for:?Tom

```

那么日志中將記錄錯(cuò)誤信息,內(nèi)容如下:

```

2013-7-30?java.util.logging.LogManager?log

Server:User?login?failed?for:jack

2013-7-30?java.util.logging.LogManager?log

Server:?User?login?succeeded?for:?Tom

```

修復(fù)建議

防止日志偽造攻擊可以采用白名單、黑名單或驗(yàn)證用戶輸入數(shù)據(jù)的方式對(duì)不可信賴的數(shù)據(jù)進(jìn)行校驗(yàn)。

**例如**:下面代碼片段使用Encode工具類對(duì)`username`做安全編碼處理,防止日志偽造攻擊的發(fā)生。

```java

import?org.owasp.encoder.Encode;

...

username?=?Encode.forJava(username);

if?(loginSuccessful)?{

????logger.severe("User?login?succeeded?for:?"?+?username);

}?else?{

????logger.severe("User?login?failed?for:?"?+?username);

}

```

中危:服務(wù)器端請(qǐng)求偽造[Java]

很多Web應(yīng)用提供了從其他的服務(wù)器上獲取數(shù)據(jù)的功能,例如用戶指定URL讓W(xué)eb應(yīng)用加載圖片,下載文件等。如果惡意利用這個(gè)功能,可以讓存在缺陷的Web應(yīng)用作為代理攻擊遠(yuǎn)程和本地的服務(wù)器。這種形式的攻擊稱為服務(wù)端請(qǐng)求偽造攻擊`(Server-side?Request?Forgery,?SSRF)`。攻擊者利用SSRF可以實(shí)現(xiàn)的攻擊主要有5種:

1.?可以對(duì)外網(wǎng)、服務(wù)器所在內(nèi)網(wǎng)、本地進(jìn)行端口掃描,獲取一些服務(wù)器的banner信息;

2.?攻擊運(yùn)行在內(nèi)網(wǎng)或本地的應(yīng)用程序(比如溢出);

3.?對(duì)內(nèi)網(wǎng)web應(yīng)用進(jìn)行指紋識(shí)別,通過(guò)訪問(wèn)默認(rèn)文件實(shí)現(xiàn);

4.?攻擊內(nèi)外網(wǎng)的web應(yīng)用,主要是使用get參數(shù)就可以實(shí)現(xiàn)的攻擊(比如struts2,sqli等);

5.?利用file協(xié)議讀取本地文件等。

**例如**:下面的代碼片段中,攻擊者將能夠控制服務(wù)器連接URL。

```java

String?url?=?request.getParameter("url");

CloseableHttpClient?httpclient?=?HttpClients.createDefault();

HttpGet?httpGet?=?new?HttpGet(url);

CloseableHttpResponse?response1?=?httpclient.execute(httpGet);

```

這種使用用戶輸入影響的資源可能存在風(fēng)險(xiǎn)。

修復(fù)建議

修復(fù)方案通常有下面5種:

1.?過(guò)濾返回信息,驗(yàn)證遠(yuǎn)程服務(wù)器對(duì)請(qǐng)求的響應(yīng)是比較容易的方法。如果web應(yīng)用是去獲取某一種類型的文件。那么在把返回結(jié)果展示給用戶之前先驗(yàn)證返回的信息是否符合標(biāo)準(zhǔn)。

2.?統(tǒng)一錯(cuò)誤信息,避免用戶可以根據(jù)錯(cuò)誤信息來(lái)判斷遠(yuǎn)端服務(wù)器的端口狀態(tài)。

3.?限制請(qǐng)求的端口為http常用的端口,比如80,443,8080,8090。

4.?禁用不需要的協(xié)議。僅僅允許http和https請(qǐng)求。可以防止類似于`file:///,?gopher://?,?ftp://`?等引起的問(wèn)題。

5.?過(guò)濾內(nèi)網(wǎng)ip,限制訪問(wèn)內(nèi)網(wǎng)

?中危:路徑遍歷:ZIP條目覆蓋[Java]

程序在解壓zip文件時(shí),由于沒(méi)有對(duì)文件名進(jìn)行合法性的校驗(yàn),而是直接將文件名拼接在待解壓目錄后面,導(dǎo)致可以將文件解壓到正常解壓縮路徑之外并覆蓋可執(zhí)行文件,從而等待系統(tǒng)或用戶調(diào)用他們實(shí)現(xiàn)代碼執(zhí)行(也可能是覆蓋配置文件或其他可敏感文件)。

**例1**:以下代碼示例解壓zip文件。

```java

...

File?sourceFile?=?new?File(sourceName);

ZipFile?zipFile?=?null;

try?{

????zipFile?=?new?ZipFile(sourceFile,"UTF-8");

}?catch?(IOException?exception)?{

????exception.printStackTrace();

????System.out.println("解壓文件不存在!");

}

Enumeration?e?=?zipFile.getEntries();

while(e.hasMoreElements())?{

????ZipEntry?zipEntry?=?(ZipEntry)e.nextElement();

????System.out.println(`zipEntry.getName()`);

????File?f?=?new?File(targetFile,`zipEntry.getName()`);

????f.getParentFile().mkdirs();

????f.createNewFile();

????InputStream?is?=?zipFile.getInputStream(zipEntry);

????FileOutputStream?fos?=?new?FileOutputStream(f);

????int?length?=?0;

????byte[]?b?=?new?byte[1024];

????while((length=is.read(b,?0,?1024))!=-1)?{

????????fos.write(b,?0,?length);

????}

????is.close();

????fos.close();

}

if?(zipFile?!=?null)?{

????zipFile.close();

}

```

代碼示例未驗(yàn)證`zipEntry.getName()`,如果zip文件放在`/tmp/`目錄中,zip條目為`../etc/hosts`,且應(yīng)用程序在必要的權(quán)限下運(yùn)行,則會(huì)導(dǎo)致系統(tǒng)的hosts文件被覆蓋。

**例2**:以下代碼使用`org.zeroturnaround.zip.ZipUtil`解壓zip文件。

```java

public?void?unZip(String?zipPath,String?targetPath)?{

????...

????ZipUtil.unpack(new?File(zipPath),?new?File(targetPath));

????...

}

```

代碼示例中如果使用了`zt-zip?1.13`之前版本。攻擊者可借助帶有目錄遍歷名稱的zip文件利用該漏洞寫(xiě)入任意文件。

修復(fù)建議

防止ZIP條目覆蓋導(dǎo)致路徑遍歷可以通過(guò)判定zipEntry路徑是否在指定路徑內(nèi),或者使用一些最新的解壓jar包來(lái)解壓文件。

**例1**:下面的validateFileDir函數(shù)來(lái)限制zip條目文件路徑只在許可的目錄內(nèi)。

```java

//限制文件在許可的目錄內(nèi)

public?static?String?validateFileDir(String?fileName,?String?permitDirectory)?throws?IOException{

????File?file=?new?File(fileName);

????String?canonicalFilePath=?checkFile.getCanonicalPath();

????File?permitDir?=?new?File(permitDirectory);

????String?canonicalPermitDir?=?permitDir.getCanonicalPath();

????if?(canonicalFilePath.startsWith(canonicalPermitDir)){

????????return?canonicalFilePath;

????}else{

????????throw?new?IllegalStateException("文件不在許可的目錄內(nèi)");

????}

}

```

可以解壓zip文件過(guò)程中使用`validateFileDir`函數(shù)來(lái)限制zip條目文件只在許可目錄內(nèi)。

**例2**:使用當(dāng)前zt-zip?1.13以及之后的版本來(lái)進(jìn)行解壓文件。

中危:拒絕服務(wù):正則表達(dá)式

正則表達(dá)式引擎分成兩類:一類稱為DFA(確定性有限狀態(tài)自動(dòng)機(jī)),另一類稱為NFA(非確定性有限狀態(tài)自動(dòng)機(jī))。Java使用的是NFA正則引擎,使用正則式和文本比較,每碰到一個(gè)字符,就把它跟正則式比較,匹配就記下來(lái),然后接著往下比較。一旦不匹配,就會(huì)后退直到回到上一次匹配的地方。而不可信賴數(shù)據(jù)被傳遞至應(yīng)用程序并作為正則表達(dá)式使用,可能導(dǎo)致線程過(guò)度使用 CPU 資源,從而導(dǎo)致拒絕服務(wù)攻擊。

**例如**:

(e+)+

([a-zA-Z]+)*

(a|aa)+

(a|a?)+

^(a+)

+$

以`^(a+)+$`為例,該正則表達(dá)式對(duì)aaaax進(jìn)行匹配時(shí)需要經(jīng)歷2^4^次嘗試失敗才會(huì)確定這個(gè)字符串不符合要求,對(duì)aaaaaaaaax進(jìn)行匹配時(shí)則需要經(jīng)歷2^10^次嘗試,隨著長(zhǎng)度的增加,嘗試次數(shù)并不是線性增長(zhǎng)而是指數(shù)型的增長(zhǎng),當(dāng)長(zhǎng)度達(dá)到20、30時(shí)就會(huì)大量消耗cpu導(dǎo)致拒絕服務(wù)。目前已知的正則表達(dá)式實(shí)現(xiàn)方法均無(wú)法避免這種漏洞,所有平臺(tái)和語(yǔ)言都容易受到這種攻擊。

Java對(duì)于正則的支持:

String類中,很多方法是專門用來(lái)支持正則:

split()

replaceAll()

replaceFirst()

matches()

……

?java.util.regex包有兩個(gè)類:Pattren類、Matcher類

修復(fù)建議:

不要將不可信賴數(shù)據(jù)作為正則表達(dá)式使用。

中危:訪問(wèn)權(quán)限修飾符控制

AccessibleObject類是Field、Method和Constructor對(duì)象的基類,能夠允許反射對(duì)象修改訪問(wèn)權(quán)限修飾符,繞過(guò)由Java訪問(wèn)修飾符提供的訪問(wèn)控制檢查。它讓程序員能夠更改私有字段或調(diào)用私有方法,這在通常情況下是不允許的。

**例如**:以下代碼片段中,將Field將`accessible`標(biāo)記設(shè)置為true。

Class clazz = User.class;

Field field = clazz.getField("name");

field.setAccessible(true);

?修復(fù)建議:

通過(guò)有權(quán)限的類更改訪問(wèn)權(quán)限修飾符,并確保修改的訪問(wèn)權(quán)限修飾符參數(shù)不能被攻擊者控制。

中危:直接綁定敏感字段

目前大部分WEB框架支持將HTTP請(qǐng)求參數(shù)與類的屬性相匹配的而生成一個(gè)對(duì)象。因此,攻擊者能夠?qū)⒅捣湃際TTP請(qǐng)求參數(shù)中從而綁定系統(tǒng)對(duì)象。

**例如**:在以下代碼片段中, Spring MVC可以將 HTTP請(qǐng)求參數(shù)綁定到 User屬性:

@RequestMapping("/login" )

public String login(User user) {

}

其中,User 類定義為:

public class User {

????private String username;

????private String address;

????private int age;

????private boolean admin;

}

當(dāng)Spring MVC未配置為禁止綁定敏感屬性,則攻擊者可能會(huì)通過(guò)發(fā)送以下使普通用戶變?yōu)楣芾韱T。

name=張三&address=北京&age=22&admin=true

修復(fù)建議:

當(dāng)程序?qū)⒎菍TTP請(qǐng)求參數(shù)直接綁定給對(duì)象時(shí),應(yīng)該要控制綁定到對(duì)象的屬性,防止暴露敏感屬性。

**例1**:在以下代碼片段中,在 Spring MVC(3.0版本至最新)禁止綁定敏感屬性。

@InitBinder

public void initBinder(WebDataBinder binder) {

????binder.setDisallowedFields(new String[]{"admin"});

}

@RequestMapping("/login" )

public String login(User user) {

}

**例2**:在 Spring MVC(2.X版本)禁止綁定敏感屬性。

@Override

protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {

????binder.setDisallowedFields(new String[]{"admin"});

}

在使用`@RequestBody`注釋參數(shù)的 Spring MVC應(yīng)用程序中,綁定過(guò)程由`HttpMessageConverter`進(jìn)行處理,這些實(shí)例使用Jackson和JAXB等庫(kù)將 HTTP請(qǐng)求參數(shù)轉(zhuǎn)換為Java對(duì)象。這些庫(kù)提供了注釋來(lái)控制應(yīng)允許或禁止的字段。例如對(duì)于Jackson,可以使用`@JsonIgnore`注釋禁止將某個(gè)字段綁定到請(qǐng)求。

**例3**:在以下代碼片段中,Jackson禁止綁定敏感屬性。

@RequestMapping(value="/add/user", method=RequestMethod.POST, consumes="text/html")

public void addEmployee(@RequestBody User user){

}

public class User {

????private String username;

????private String address;

????@JsonIgnore

????private boolean admin;

????private int age;

}

同理,Jackson還可以使用`@JsonIgnoreProperties、@JsonIgnoreTyp和 @JsonInclude`等注解告訴框架忽略這些屬性,使用JAXB使用`@XmlAccessorType、@XmlAttribute、@XmlElement和 @XmlTransient`等注解告訴框架忽略這些屬性,然后使用`@XmlAttribute和@XmlElement`等注解選擇應(yīng)綁定的字段。

**例4**:在以下代碼片段中,Jackson使用`@XmlAttribute`選擇要綁定的字段。

@XmlRootElement

@XmlAccessorType(XmlAccessType.NONE)

public class User {

????private String username;

????private String address;

????@JsonIgnore

????private boolean admin;

????private int age;

????@XmlAttribute

????public String getUsername() {

????????return username;

????}

????public void setUsername(String username) {

????????this.username = username;

????}

????@XmlAttribute

????public String getAddress() {

????????return address;

????}

????public void setAddress(String address) {

????????this.address = address;

????}

????private boolean isAdmin() ?{

????????return admin;

????}

????private void setAdmin(boolean admin) ?{

????????this.admin = admin;

????}

}

**例5**:在以下代碼片段中,在Struts可以將某個(gè)屬性的`setter`方法設(shè)置為私有從而禁止綁定敏感屬性。

private boolean admin;

private void setAdmin(boolean admin) ?{

????this.admin = admin;

}

還有另一種方法是使用將 HTTP請(qǐng)求參數(shù)綁定到僅含有 Web表單或 API中定義的屬性DTO對(duì)象中,再將其映射到User中,防止敏感字段暴露。

低危:拒絕服務(wù):解析Double類型數(shù)據(jù)

程序調(diào)用Double的解析方法時(shí),可能導(dǎo)致線程被掛起。`java.lang.Double.parseDouble()`方法解析位于2^(-1022)^ - 2^(-1075)^到2^(-1022)^ - 2^(-1076)^范圍內(nèi)的任何數(shù)字時(shí)可能導(dǎo)致線程被掛起,攻擊者可以故意觸發(fā)該漏洞執(zhí)行拒絕服務(wù)攻擊。該漏洞在java6 update24或更高版本中進(jìn)行了修復(fù)。

**例如**:下面代碼片段中,使用了易受攻擊的方法。

Double d = Double.parseDouble(request.getParameter("d"));

攻擊者可發(fā)送d參數(shù)值位于該范圍(例如`0.0222507385850720119e-00306`)內(nèi)的請(qǐng)求,致使程序在處理該請(qǐng)求時(shí)被掛起。

修復(fù)建議:

修復(fù)該缺陷的方式如下:

1. 驗(yàn)證傳遞給parseDouble數(shù)據(jù)的合法性。

2. 升級(jí)JDK版本到6 Update 24或更高版本。

低危:有風(fēng)險(xiǎn)的資源使用

拒絕服務(wù)是攻擊者通過(guò)消耗應(yīng)用資源,以致程序崩潰使得其他用戶無(wú)法繼續(xù)正常使用的一種攻擊方式。

**例1**:下面代碼片段中,解壓文件前,未檢查文件大小,攻擊者可以通過(guò)提供一個(gè)超大文件來(lái)占用系統(tǒng)的計(jì)算資源從而實(shí)施DOS攻擊。

static final int SIZE= 512;

public static void unZip(BufferedInputStream bin){

????BufferedOutputStream ?bop= null;

????ZipInputStream zi = new ZipInputStream(bin);

????ZipEntry ?zentry;

????while ((zentry= zi.getNextEntry()) != null) {

????????int count;

????????byte data[] = new byte[SIZE];

????????FileOutputStream fos = new FileOutputStream(zentry.getName());

????????bop= new BufferedOutputStream(fos, SIZE);

????????while ((count = zi.read(data, 0, SIZE)) != -1) {

????????????bop.write(data, 0, count);

????????}

????????bop.flush();

????????bop.close();

????}

????zi.close();

}

**例2**:下面使用了`waitFor`方法,意味著直到該進(jìn)程結(jié)束才能繼續(xù)執(zhí)行后續(xù)代碼,不正確的處理輸入輸出流有可能發(fā)生死鎖,導(dǎo)致程序持續(xù)浪費(fèi)資源甚至崩潰。

process.waitFor();

修復(fù)建議:

拒絕服務(wù)攻擊是一種濫用資源性的攻擊。從代碼角度來(lái)考慮,對(duì)于涉及到需要占用系統(tǒng)資源的外部數(shù)據(jù)而言,代碼邏輯中應(yīng)該包含嚴(yán)格校驗(yàn),防止無(wú)限制的輸入。另外,謹(jǐn)慎使用線程阻塞的API,防止浪費(fèi)系統(tǒng)資源或發(fā)生系統(tǒng)崩潰。

**例如**:下面代碼片段中,對(duì)解壓文件進(jìn)行驗(yàn)證,超過(guò)50M,將拋出異常。

static final int MAX= 0x3200000; // 50MB

// write the files to the disk, but only if file is not insanely big

if (entry.getSize() > MAX) {

????throw new IllegalStateException("File to be unzipped is huge.");

}

if (entry.getSize() == -1) {

????throw new IllegalStateException("File to be unzipped might be huge.");

}

FileOutputStream fos = new FileOutputStream(entry.getName());

bop = new BufferedOutputStream(fos, SIZE);

while ((count = zis.read(data, 0, SIZE)) != -1) {

????bop.write(data, 0, count);

}

低危:數(shù)據(jù)跨越信任邊界

數(shù)據(jù)跨越信任邊界是指,數(shù)據(jù)從一個(gè)不可信賴域存儲(chǔ)到一個(gè)可信賴域?qū)е鲁绦蝈e(cuò)誤信賴未驗(yàn)證的數(shù)據(jù)。

**例如**:下面代碼片段中將用戶輸入的數(shù)據(jù)`name`存儲(chǔ)到Http Session中。

protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

????String name = req.getParameter("userName");

????HttpSession sess = req.getSession();

????sess.setAttribute("user", name);

}

修復(fù)建議:

數(shù)據(jù)跨越信任邊界時(shí)需要進(jìn)行合理的驗(yàn)證,保證信賴域中數(shù)據(jù)是安全的。

低危:文件上傳

允許用戶上傳文件可能導(dǎo)致危險(xiǎn)的文件或代碼被注入,并在服務(wù)器執(zhí)行。

**例如**:

<input type="file">

修復(fù)建議:

- 如果應(yīng)用程序不需要文件上傳功能,應(yīng)該禁用文件上傳功能。

- 如果應(yīng)用程序需要文件上傳功能,可以參考以下建議:

1. 文件上傳的目錄設(shè)置為不可執(zhí)行。

2. 采用白名單方式判斷文件類型。在判斷文件類型時(shí),可采用MIME Type、 后綴檢查等方式。

3. 使用隨機(jī)數(shù)改寫(xiě)文件名和文件路徑。 如果應(yīng)用程序采用隨機(jī)數(shù)改寫(xiě)了文件名和路徑,可以很大程度上增加攻擊的成本。

4. 對(duì)于圖片的處理,可以采用壓縮函數(shù)或者resize函數(shù),在處理圖片的同時(shí),破壞圖片中可能包含的腳本代碼。

代碼注入

高危:XML外部實(shí)體注入[Java]

XML作為一種使用較為廣泛的數(shù)據(jù)傳輸格式,很多應(yīng)用程序都包含有處理XML數(shù)據(jù)的代碼,默認(rèn)情況下,許多過(guò)時(shí)的或配置不當(dāng)?shù)?XML處理器都會(huì)對(duì)外部實(shí)體進(jìn)行引用。如果攻擊者可以上傳 XML文檔或者在 XML文檔中添加惡意內(nèi)容,通過(guò)易受攻擊的代碼、依賴項(xiàng)或集成,就能夠攻擊包含缺陷的XML處理器,從而造成拒絕服務(wù)攻擊或者程序崩潰。

**例1**:下面代碼片段使用Java原生的SAX對(duì)evil.xml文件進(jìn)行解析

```java

private static void receiveXMLStream(InputStream inStream){

????SAXParserFactory factory = SAXParserFactory.newInstance();

????SAXParser saxParser;

????try {

????????saxParser = factory.newSAXParser();

????????saxParser.parse(inStream,new DefaultHandler());

????????...

????} catch (ParserConfigurationException e) {

????????...

????} catch (SAXException e) {

????????...

????} catch (IOException e) {

????????...

????}

}

```

**例2**:下面代碼片段使用Java原生的DOM對(duì)evil.xml文件進(jìn)行解析

```java

private static void receiveXMLStream(InputStream stream){

????DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();

????DocumentBuilder documentBuilder;

????try {

????????documentBuilder = documentBuilderFactory.newDocumentBuilder();

????????documentBuilder.parse(stream);

????????...

????} catch (ParserConfigurationException e) {

????????...

????} catch (SAXException e) {

????????...

????} catch (IOException e) {

????????...

????}

}

```

當(dāng)使用不可信數(shù)據(jù)來(lái)源作為文件輸入流時(shí)

```java

String fileName = request.getParameter("filename");

receiveXMLStream(new FileInputStream(fileName));

```

如果evil.xml文件中包含以下文本

```xml

<?xml version="1.0"?>

<!DOCTYPE foo SYSTEM "file:/dev/tty">

<foo>bar</foo>

...

```

SAX或者DOM解析器會(huì)嘗試訪問(wèn)在SYSTEM屬性中標(biāo)識(shí)的URL,這意味著它將讀取本地/dev/tty文件的內(nèi)容。在POSIX系統(tǒng)中,讀取這個(gè)文件會(huì)導(dǎo)致程序阻塞,直到可以通過(guò)計(jì)算機(jī)控制臺(tái)得到輸入數(shù)據(jù)為止。這樣,攻擊者可以使用這個(gè)惡意的XML文件來(lái)導(dǎo)致系統(tǒng)掛起,程序會(huì)受到XML外部實(shí)體注入攻擊。

修復(fù)建議

對(duì)于使用Java原生DOM和SAX以及DOM4J有以下兩種修復(fù)方法(這里以`DocumentBuilderFactory`為例):

1.禁用DTD(doctypes),這樣可以阻止幾乎所有的XML實(shí)體攻擊

```java

//僅限

Xerces 2 ?- ?http://xerces.apache.org/xerces2-j/features.html#disallow-doctype-decl

documentBuilderFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl",true);

```

2.如果無(wú)法完全禁用DTD,可以采用以下操作一起使用

(1)禁用外部通用實(shí)體和參數(shù)實(shí)體(根據(jù)實(shí)際使用的jar包)

??```java

// Xerces 1 ?- ?http://xerces.apache.org/xerces-j/features.html#external-general-entities和http://xerces.apache.org/xerces-j/features.html#external-parameter-entities

// Xerces 2 ?- ?http://xerces.apache.org/xerces2-j/features.html#external-general-entities和http://xerces.apache.org/xerces2-j/features.html#external-parameter-entities

// JDK7 + ?- ?http://xml.org/sax/features/external-general-entities和http://xml.org/sax/features/external-parameter-entities

documentBuilderFactory.setFeature("http://xml.org/sax/features/external-general-entities",false);

documentBuilderFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);

```

(2)禁用外部DTD

```java

documentBuilderFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd",false);

```

(3)設(shè)置 XInclude 處理的狀態(tài)為false,禁止實(shí)體擴(kuò)展引用

```java

documentBuilderFactory.setXIncludeAware(false);

documentBuilderFactory.setExpandEntityReferences(false);

```

上述設(shè)置功能的方法`setFeature`也可以換成`setAttribute`,`setAttribute`方法用于用戶在底層設(shè)置特定屬性,使用方法和效果是一樣的。

上述防御需要Java 7 Update 67,Java 8 Update 20或更高版本,因?yàn)閌DocumentBuilderFactory`和`SAXParserFactory`的上述對(duì)策在早期Java版本中被破壞。

也可以從其他類上著手防范xxe漏洞:

如`XMLInputFactory、TransformerFactory、Validator、SchemaFactory、SAXTransformerFactory`。但這些類都是調(diào)用了`XMLConstants`中的屬性,故需要支持JAXP1.5.使用StAX解析xml文件時(shí),可使用下面方法進(jìn)行防范(這里僅用`XMLInputFactory`類做為例子:其他類的防護(hù)手段類似):

```java

//這將完全禁用該工廠的DTD

xmlInputFactory.setProperty(XMLInputFactory.SUPPORT_DTD,false);

//禁用外部實(shí)體

xmlInputFactory.setProperty("javax.xml.stream.isSupportingExternalEntities",false);

```

示例1還有一個(gè)解決方案是,定義一個(gè)`CustomResolver`類,這個(gè)類實(shí)現(xiàn)了`org.xml.sax.EntityResolver`接口。它可以讓SAX應(yīng)用定制對(duì)外部實(shí)體的處理。`setEntityResolver()`方法可以將對(duì)應(yīng)的SAX驅(qū)動(dòng)實(shí)例注冊(cè)進(jìn)來(lái)。這個(gè)定制的處理器使用的是一個(gè)為外部實(shí)體定義的簡(jiǎn)單的白名單。當(dāng)輸入不是任何指定的、安全地實(shí)體源路徑時(shí),`resolverEntity()`方法會(huì)返回一個(gè)空的`InputSource`對(duì)象。結(jié)果是,當(dāng)解析惡意輸入時(shí),這個(gè)由自定義的解析器返回的空的`InputStream`對(duì)象會(huì)拋出`java.net.MalformedURLException`異常。需要注意的是,必須創(chuàng)建一個(gè)`XMLReader`對(duì)象,以便通過(guò)這個(gè)對(duì)象來(lái)設(shè)置自定義的實(shí)體解析器。

以下為示例代碼:

```java

class CustomResolver implements EntityResolver {

????public InputSource resolveEntity(String publicId, String systemId)

????????????throws SAXException, IOException {

????????//check for known good entities

????????String entityPath = "/home/username/java/xxe/file";

????????if (systemId.equals(entityPath)) {

????????????System.out.println("Resolving entity: " + publicId + " " + systemId);

????????????return new InputSource(entityPath);

????????} else {

????????????return new InputSource(); // Disallow unknown entities by returning a blank path

????????}

????}

}

class XXE {

????private static void receiveXMLStream(InputStream inStream,DefaultHandler defaultHandler)

????????????throws ParserConfigurationException, SAXException, IOException {

????????SAXParserFactory factory = SAXParserFactory.newInstance();

????????SAXParser saxParser = null;

????????try {

????????????saxParser = factory.newSAXParser();

????????????XMLReader reader = saxParser.getXMLReader();

????????????reader.setEntityResolver(new CustomResolver());

????????????reader.setErrorHandler(new DefaultHandler());

????????????InputSource is = new InputSource(inStream);

????????????reader.parse(is);

????????????...

????????} catch (ParserConfigurationException e) {

????????????...

????????} catch (SAXException e) {

????????????...

????????} catch (IOException e) {

????????????...

????????}

????}

????...

}

```

高危:動(dòng)態(tài)解析代碼[NodeJS]

程序運(yùn)行時(shí)動(dòng)態(tài)解析源代碼指令將易于受到攻擊。

**例如**:下面代碼片段的作用是計(jì)算用戶輸入的表達(dá)式的值。

```javascript

...

expression?=?form.expInput.value;

result?=?eval(expression);

...

```

如果expression參數(shù)是合法的,程序?qū)?huì)正常運(yùn)行。

**例如**:當(dāng)該值為"1?+?1?*?2"?時(shí),result變量被賦予的值將為?3。

如果攻擊者提供一個(gè)惡意的輸入,程序在沒(méi)有進(jìn)行合理校驗(yàn)的情況,將可以執(zhí)行任意代碼。

修復(fù)建議

在任何時(shí)候,都應(yīng)盡可能地避免動(dòng)態(tài)的解析源代碼。如果程序的功能要求對(duì)代碼進(jìn)行動(dòng)態(tài)解析,應(yīng)用程序不應(yīng)該直接執(zhí)行和解析未驗(yàn)證的用戶輸入。建議創(chuàng)建一份合法操作和數(shù)據(jù)對(duì)象列表,用戶可以指定其中的內(nèi)容,并且只能從中進(jìn)行選擇。

**例如**:計(jì)算表達(dá)式的程序可以改為。

```javascript

...

expression?=?form.expInput.value;

if(/^[\d\-\+]*$/.test(expression)){

????result?=?eval(expression);

}

...

```

中危:JavaScript劫持[NodeJS]

使用JavaScript傳送敏感數(shù)據(jù)的應(yīng)用程序可能會(huì)存在JavaScript劫持的漏洞,該漏洞允許未經(jīng)授權(quán)的攻擊者從一個(gè)易受攻擊的應(yīng)用程序中讀取機(jī)密數(shù)據(jù)。

JavaScript劫持可以簡(jiǎn)單的理解為模擬授權(quán)的用戶,竊取用戶在服務(wù)器上的信息。Web瀏覽器使用同源策略(Same?Origin?Policy),以保護(hù)用戶免受惡意網(wǎng)站的攻擊。同源策略規(guī)定:如果要使用JavaScript來(lái)訪問(wèn)某個(gè)網(wǎng)頁(yè)的內(nèi)容的話,則JavaScript和網(wǎng)頁(yè)必須都來(lái)源于相同的域。若不采取同源策略,惡意網(wǎng)站便可以使用受害者的客戶端憑證來(lái)運(yùn)行?JavaScript,從其他網(wǎng)站加載的敏感信息,并對(duì)這些信息進(jìn)行處理,然后將其返回給攻擊者。

使用JSON傳輸數(shù)據(jù)的JavaScript應(yīng)用更容易受到JavaScript劫持攻擊。由于JSON使用JavaScript語(yǔ)法的子集表示對(duì)象、數(shù)組、簡(jiǎn)單值,JSON本身可以被當(dāng)做JavaScript執(zhí)行,且使用*eval*()函數(shù)對(duì)JSON數(shù)據(jù)結(jié)構(gòu)求值早被認(rèn)為是存在風(fēng)險(xiǎn)的,其可能執(zhí)行惡意代碼。

修復(fù)建議

盡量避免跨域的數(shù)據(jù)傳輸,對(duì)于同域的數(shù)據(jù)傳輸使用xmlhttp的方式作為數(shù)據(jù)獲取的方式。如果是跨域的數(shù)據(jù)傳輸,必須要對(duì)敏感的數(shù)據(jù)獲取做權(quán)限認(rèn)證,具體的方式可以包括:

1.?referer的來(lái)源限制,利用前端referer的不可偽造性來(lái)保障請(qǐng)求數(shù)據(jù)的應(yīng)用來(lái)源于可信的地方,此種方式力度較稀,完全依賴于referer,某些情況下(如存在XSS)可能導(dǎo)致被繞過(guò)。

2.?加入Token。利用Token對(duì)調(diào)用者的身份進(jìn)行認(rèn)證,這種方式對(duì)于調(diào)用者的身份會(huì)要求力度較細(xì),但是一旦出現(xiàn)XSS也可能導(dǎo)致前端Token的泄露,從而導(dǎo)致保護(hù)失效。

3.?避免直接執(zhí)行JavaScript響應(yīng):在響應(yīng)中加入一些額外的字符。這些響應(yīng)只有經(jīng)過(guò)了修改,才能成功地轉(zhuǎn)到JavaScript解釋器進(jìn)行處理。這樣可以防止攻擊者使用\<script\>標(biāo)簽來(lái)進(jìn)行劫持。比如,可以給響應(yīng)加上注釋符號(hào),使其無(wú)法直接執(zhí)行;或者是在真實(shí)的響應(yīng)前面,添加死循環(huán)語(yǔ)句,使其無(wú)法正常的直接運(yùn)行。

中危:XML實(shí)體擴(kuò)展注入[Java]

攻擊者主要試圖通過(guò)消耗目標(biāo)程序的服務(wù)器環(huán)境來(lái)進(jìn)行DOS攻擊的。這種攻擊基于XML實(shí)體擴(kuò)展實(shí)現(xiàn),通過(guò)在XML的DOCTYPE中創(chuàng)建自定義實(shí)體的定義實(shí)現(xiàn),比如,這種定義可以在內(nèi)存中生成一個(gè)比XML的原始允許大小大出很多的XML結(jié)構(gòu),來(lái)使這種攻擊得以耗盡網(wǎng)絡(luò)服務(wù)器正常有效運(yùn)行的必需內(nèi)存資源。

**例如**:下面代碼片段嘗試對(duì)外界輸入的流進(jìn)行解析

```java

class?XMLEntityExpansion?{

????private?static?void?receiveXMLStream(InputStream?inStream,DefaultHandler?defaultHandler)

????????????throws?ParserConfigurationException,?SAXException,?IOException?{

????????SAXParserFactory?factory?=?SAXParserFactory.newInstance();

????????SAXParser?saxParser?=?factory.newSAXParser();

????????saxParser.parse(inStream,?defaultHandler);

????}

????public?static?void?main(String[]?args)

????????????throws?ParserConfigurationException,?SAXException,?IOException?{

????????receiveXMLStream(new?FileInputStream("evil.xml"),

????????new?DefaultHandler());

????}

}

```

通過(guò)擴(kuò)展XML自定義實(shí)體以達(dá)到耗盡服務(wù)器資源的目標(biāo)的方法有以下幾種。

1.通用實(shí)體擴(kuò)展攻擊:

通用實(shí)體擴(kuò)展攻擊同樣被稱為`Quadratic?Blowup?Attack`,使用這種方式時(shí),自定義實(shí)體被定義為一個(gè)極長(zhǎng)的字符串。當(dāng)文件中大量使用這個(gè)實(shí)體時(shí),該實(shí)體在每次調(diào)用時(shí)都會(huì)進(jìn)行擴(kuò)展,生成一個(gè)大幅超出原XML所需內(nèi)存大小的XML結(jié)構(gòu)。

```xml

<?xml?version=""1.0""?>

<!DOCTYPE?results?[<!ENTITY?long?"SOME_SUPER_LONG_STRING">]>

<results>

????<result>Now?include?&long;?lots?of?times?to?expand

????the?in-memory?size?of?this?XML?structure</result>

????<result>&long;&long;&long;&long;&long;&long;&long;

????&long;&long;&long;&long;&long;&long;&long;&long;

????&long;&long;&long;&long;&long;&long;&long;&long;

????&long;&long;&long;&long;&long;&long;&long;&long;

????Keep?it?going...

????&long;&long;&long;&long;&long;&long;&long;...</result>

</results>

```

通過(guò)平衡自定義實(shí)體字符串大小和文檔主體內(nèi)使用實(shí)體數(shù)量,可以創(chuàng)建一個(gè)擴(kuò)展至占用服務(wù)器可預(yù)測(cè)內(nèi)存空間大小的XML文檔或字符串。通過(guò)這樣重復(fù)請(qǐng)求來(lái)占用服務(wù)器內(nèi)存,就可以發(fā)動(dòng)一次成功的拒絕服務(wù)攻擊。該方式的缺陷是,由于產(chǎn)生內(nèi)存消耗效果是基于簡(jiǎn)單數(shù)乘的,因此初始XML文檔或字符串本身需要足夠大。

2.遞歸實(shí)體擴(kuò)展攻擊:

通用實(shí)體擴(kuò)展攻擊需要足夠大的XML輸入數(shù)據(jù)量,而遞歸實(shí)體擴(kuò)展攻擊的平均輸入字節(jié)能產(chǎn)生更強(qiáng)力的攻擊效果。這種攻擊方式依賴于XML解析器來(lái)解析,從而完成小實(shí)體集的指數(shù)級(jí)增長(zhǎng)。通過(guò)這種指數(shù)爆炸性增長(zhǎng)方式,一個(gè)比通用實(shí)體擴(kuò)展攻擊使用小得多的輸入數(shù)據(jù)量實(shí)際可增長(zhǎng)得極大。因此這種方式被稱為`XML?Bomb`或是`Billion?Laughs?Attack`也是十分恰切的。

```xml

<?xml?version=""1.0""?>

????<!DOCTYPE?results?[

????<!ENTITY?x0?""BOOM!"">

????<!ENTITY?x1?""&x0;&x0;"">

????<!ENTITY?x2?""&x1;&x1;"">

????<!ENTITY?x3?""&x2;&x2;"">

????<!--?Add?the?remaining?sequence?from?x4...x100?(or?boom)?-->

????<!ENTITY?x99?""&x98;&x98;"">

????<!ENTITY?boom?""&x99;&x99;"">

]>

<results>

????<result>Explode?in?3...2...1...&boom;</result>

</results>

```

XML?Bomb攻擊并不需要可能會(huì)被程序限制的大量XML數(shù)據(jù)輸入。實(shí)體集像這樣指數(shù)倍增長(zhǎng),最終形成的擴(kuò)展后文本大小是初始&x0實(shí)體值的2的100次方倍。

3.遠(yuǎn)程實(shí)體擴(kuò)展攻擊:

常規(guī)和遞歸實(shí)體擴(kuò)展攻擊都依賴于XML文檔類型定義中定義在本地的實(shí)體,但是攻擊者同樣可以進(jìn)行外部實(shí)體定義。這很顯然需要XML解析器能夠像我們之前在描述XML外部實(shí)體注入式攻擊(XXE)時(shí)遇到的那樣,發(fā)起遠(yuǎn)程HTTP請(qǐng)求。而拒絕這種請(qǐng)求對(duì)你的XML解析器而言是一種基礎(chǔ)的安保措施。因此,防御XXE攻擊的措施同樣適用于此類XML實(shí)體擴(kuò)展攻擊。

雖說(shuō)可以通過(guò)上述方式進(jìn)行防御,遠(yuǎn)程實(shí)體擴(kuò)展通過(guò)使XML解析器發(fā)出遠(yuǎn)程HTTP請(qǐng)求來(lái)獲得被引用實(shí)體的擴(kuò)展值來(lái)進(jìn)行攻擊。返回結(jié)果將自行定義其他XML解析器必須另行HTTP請(qǐng)求的外部實(shí)體。如此一來(lái),一些看似并無(wú)攻擊性的請(qǐng)求會(huì)迅速脫離控制,并給服務(wù)器的可用資源帶來(lái)負(fù)擔(dān)。這種情況下,如果請(qǐng)求自包括一個(gè)遞歸擴(kuò)展攻擊,那最終結(jié)果會(huì)更加糟糕。

修復(fù)建議

對(duì)于使用Java原生DOM和SAX以及DOM4J有以下兩種修復(fù)方法(這里以SAXParserFactory為例):

1.禁用DTD(doctypes),這樣可以阻止幾乎所有的XML實(shí)體攻擊

```java

//僅限Xerces?2??-??http://xerces.apache.org/xerces2-j/features.html#disallow-doctype-decl

saxParserFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl",true);

```

2.如果無(wú)法完全禁用DTD,可以采用以下操作一起使用

(1)限制XML處理

```java

saxParserFactory.setFeature("http://javax.xml.XMLConstants/feature/secure-processing",?true);

```

(2)禁用外部DTD

```java

saxParserFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd",false);

```

(3)設(shè)置?XInclude?處理的狀態(tài)為false,禁止實(shí)體擴(kuò)展引用

```java

saxParserFactory.setXIncludeAware(false);

saxParserFactory.setExpandEntityReferences(false);

```

上述設(shè)置功能的方法`setFeature`也可以換成`setAttribute`,`setAttribute`方法用于用戶在底層設(shè)置特定屬性,使用方法和效果是一樣的。

上述防御需要Java?7?Update?67,Java?8?Update?20或更高版本,因?yàn)閌DocumentBuilderFactory`和`SAXParserFactory`的上述對(duì)策在早期Java版本中被破壞。

也可以從其他類上著手防范xxe漏洞:

如`XMLInputFactory、TransformerFactory、Validator、SchemaFactory、SAXTransformerFactory`。但這些類都是調(diào)用了`XMLConstants`中的屬性,故需要支持JAXP1.5.使用STAX解析xml文件時(shí),可使用下面方法進(jìn)行防范(這里僅用`XMLInputFactory`類做為例子:其他類的防護(hù)手段類似):

```java

//這將完全禁用該工廠的DTD

xmlInputFactory.setProperty(XMLInputFactory.SUPPORT_DTD,false);

//禁用替換內(nèi)部實(shí)體引用

xmlInputFactory.setProperty("javax.xml.stream.isReplacingEntityReferences",false);

```

中危:同源方法執(zhí)行[Java]

JSONP可以利用callback的特性,來(lái)跨域傳輸數(shù)據(jù),同域間也可以傳輸數(shù)據(jù)。攻擊者可以先創(chuàng)建一個(gè)惡意網(wǎng)站,再在該站點(diǎn)構(gòu)建一個(gè)頁(yè)面,當(dāng)用戶從此頁(yè)面點(diǎn)擊進(jìn)入另一此站點(diǎn)頁(yè)面時(shí),使第一個(gè)頁(yè)面重定向至目標(biāo)站點(diǎn)頁(yè)面,然后第二個(gè)頁(yè)面引用目標(biāo)站點(diǎn)漏洞頁(yè)面,則可以在該目標(biāo)站點(diǎn)頁(yè)面上執(zhí)行任意?JavaScript函數(shù)。

**例如**:下面代碼片段,構(gòu)造回調(diào)函數(shù)名稱可由用戶控制的JSONP響應(yīng)。

```java

@ControllerAdvice

public?class?JsonpAdvice?extends?AbstractJsonpResponseBodyAdvice?{

????public?JsonpAdvice()?{

????????super("callback");

????}

}

```

當(dāng)用戶發(fā)送`GET?/api/gerData?callback=myFunction`?的請(qǐng)求,控制器將生成如下響應(yīng):

```

HTTP/1.1?200?Ok

Content-Type:?application/json;?charset=utf-8

Date:?Thu,?28?Jun?2018?11:27:53?GMT

Server:?Apache

Content-Length:?300

Connection:?Close

myFunction({<data>})

```

攻擊者可以從JSONP端點(diǎn)加載該響應(yīng),從而執(zhí)行`myFunction`函數(shù)。攻擊者可以使用其他回調(diào)名稱調(diào)用DOM來(lái)交互。?**例如**:`window.opener.document.body.someElemnt.firstChild.nextElementSibling.submit`可用于查找目標(biāo)頁(yè)面中的表格并進(jìn)行提交。

修復(fù)建議

檢查程序邏輯,是否需要通過(guò)外界數(shù)據(jù)控制回調(diào)函數(shù),對(duì)數(shù)據(jù)進(jìn)行過(guò)濾或者構(gòu)建白名單來(lái)供用戶選擇,以避免攻擊者執(zhí)行任意代碼。

中危:HTTP響應(yīng)截?cái)郲Java]

程序從一個(gè)不可信賴的數(shù)據(jù)源獲取數(shù)據(jù),未進(jìn)行驗(yàn)證就置于HTTP頭文件中發(fā)給用戶,可能會(huì)導(dǎo)致HTTP響應(yīng)截?cái)喙簟?/p>

**例如**:下列代碼片段中,程序從HTTP請(qǐng)求中獲取`author`的值,并將其設(shè)置到HTTP響應(yīng)文件的cookie中。

String author = request.getParameter(AUTHOR_PARAM);

Cookie cookie = new Cookie("author", author);

cookie.setMaxAge(cookieExpiration);

response.addCookie(cookie);

如果請(qǐng)求中提交的是一個(gè)`Jane Smith`字符串,那么包含該cookie的HTTP響應(yīng)可能表現(xiàn)為以下形式:

HTTP/1.1 200 OK

...

Set-Cookie: author=Jane Smith

那么如果攻擊者提交的是一個(gè)惡意字符串,比如

`Wiley Hacker\r\nHTTP/1.1 200 OK\r\n...`

那么HTTP響應(yīng)就會(huì)被分割成以下形式的兩個(gè)響應(yīng):

HTTP/1.1 200 OK

...

Set-Cookie: author=Wiley Hacker

HTTP/1.1 200 OK

這樣第二個(gè)響應(yīng)已完全由攻擊者控制,攻擊者可以用所需的頭文件和正文內(nèi)容構(gòu)建該響應(yīng)實(shí)施攻擊。

修復(fù)建議

防止HTTP響應(yīng)截?cái)喙舻淖畎踩姆椒ㄊ莿?chuàng)建一份安全字符白名單,只接受完全由這些受認(rèn)可的字符組成的輸入出現(xiàn)在HTTP響應(yīng)頭文件中。

**例如**:以下代碼片段中,驗(yàn)證了`author`的值是否由標(biāo)準(zhǔn)的字母數(shù)字字符組成。

String author = request.getParameter(AUTHOR_PARAM);

if (Pattern.matches("[0-9A-Za-z]+", author)) {

????Cookie cookie = new Cookie("author", author);

????cookie.setMaxAge(cookieExpiration);

????response.addCookie(cookie);

}

中危:HTTP響應(yīng)截?cái)啵篊ookies[Java]

HTTP響應(yīng)截?cái)嗍怯捎趹?yīng)用程序未對(duì)用戶提交的數(shù)據(jù)進(jìn)行嚴(yán)格過(guò)濾,當(dāng)用戶惡意提交包含CR(回車,即URL編碼%0d或r)和LF(換行符,即URL編碼%0a或n)的HTTP請(qǐng)求,服務(wù)器可能會(huì)創(chuàng)建兩個(gè)?HTTP?響應(yīng),攻擊者可以控制第二個(gè)響應(yīng)并加載攻擊。攻擊者可控制響應(yīng)的內(nèi)容構(gòu)造?XSS?攻擊,其中響應(yīng)中包含惡意的?JavaScript?或其它代碼在用戶的瀏覽器中執(zhí)行,也有可能讓用戶重定向到攻擊者控制的Web內(nèi)容或在用戶的主機(jī)上執(zhí)行惡意操作。

**例1**:下列代碼片段中,程序讀取HTTP請(qǐng)求參數(shù)AUTHOR_PARAM的值,并將它設(shè)置到HTTP響應(yīng)的Cookie中。

```java

...

String?author?=?request.getParameter(AUTHOR_PARAM);

...

Cookie?cookie?=?new?Cookie("author",?author);

cookie.setMaxAge(cookieExpiration);

response.addCookie(cookie);

...

```

正常情況下,如果請(qǐng)求中提交參數(shù)是字符串`Jane?Smith`,那么包含Cookie的HTTP響應(yīng)頭格式如下:

```java

HTTP/1.1?200?OK

...

Set-Cookie:?author=Jane?Smith

...

```

但是如果攻擊者提交一個(gè)惡意字符串,比如`Wiley?Hacker\r\nHTTP/1.1?200?OK\r\n...`,那么HTTP應(yīng)答就會(huì)被分割成下面兩個(gè)響應(yīng):

```java

HTTP/1.1?200?OK

...

Set-Cookie:?author=Wiley?Hacker

HTTP/1.1?200?OK

...

```

這樣第二個(gè)響應(yīng)已完全由攻擊者控制,攻擊者可以用所需的頭文件和正文內(nèi)容構(gòu)建該響應(yīng)實(shí)施攻擊。

**例2**:以下Android代碼會(huì)從Activity中直接取值,并將其置于一個(gè)HTTP響應(yīng)的cookie頭文件中,而該值很可能是受用戶控制的。

```java

...

CookieManager?cookieManager?=?CookieManager.getInstance();

Intent?intent?=?activity.getIntent();

String?value?=?intent.getStringExtra("value");

cookieManager.setCookie("url",?value);

...

```

修復(fù)建議

防止HTTP響應(yīng)截?cái)喙舻淖畎踩姆椒ㄊ莿?chuàng)建一份安全字符白名單,只接受完全由這些受認(rèn)可的字符組成的輸入出現(xiàn)在HTTP響應(yīng)頭文件中。

**例如**:以下代碼片段中,使用URLEncoder工具類對(duì)`para`進(jìn)行安全編碼,防止攻擊。

```java

import?java.net.URLEncoder;

...

String?para?=?request.getParameter(para);

para?=?URLEncoder.encode(para,?"UTF-8");

Cookie?cookie?=?new?Cookie("para",?para);

cookie.setMaxAge(expirationAge);

response.addCookie(cookie);

...

```

中危:有風(fēng)險(xiǎn)的SQL查詢:MyBatis

SQL注入是一種數(shù)據(jù)庫(kù)攻擊手段。攻擊者通過(guò)向應(yīng)用程序提交惡意代碼來(lái)改變?cè)璖QL語(yǔ)句的含義,進(jìn)而執(zhí)行任意SQL命令,達(dá)到入侵?jǐn)?shù)據(jù)庫(kù)乃至操作系統(tǒng)的目的。在Mybatis Mapper Xml中,`#`變量名稱創(chuàng)建參數(shù)化查詢SQL語(yǔ)句,不會(huì)導(dǎo)致SQL注入。而`$`變量名稱直接使用SQL指令,而`$`變量名稱直接使用SQL指令,將會(huì)存在一定風(fēng)險(xiǎn),當(dāng)SQL指令所需的數(shù)據(jù)來(lái)源于不可信賴的數(shù)據(jù)源時(shí),可能會(huì)導(dǎo)致SQL注入。

**例如**:以下代碼片段采用`$`變量名稱動(dòng)態(tài)地構(gòu)造并執(zhí)行了SQL查詢。

<!--select user information by name-->

<select id="queryByUserName" resultMap="userResultMap" parameterType="String">

????select * from db_user where user_name=${username}

</select>

如果攻擊者能夠替代username中的任意字符串,它們可以使用下面的關(guān)于username的字符串進(jìn)行SQL注入。

`validuser' OR '1'='1`

當(dāng)其注入到命令時(shí),命令就會(huì)變成:

`select * from db_user where user_name ='validuser' OR '1'='1'`

即使所輸入字符串不是來(lái)源于不可信賴的數(shù)據(jù)源,程序仍然存在著一定風(fēng)險(xiǎn)。

修復(fù)建議:

造成SQL注入攻擊的根本原因在于攻擊者可以改變SQL查詢的上下文,使程序員原本要作為數(shù)據(jù)解析的數(shù)值,被篡改為命令了。防止SQL注入的方法如下:

1. 正確使用參數(shù)化API進(jìn)行SQL查詢。

2. 如果構(gòu)造SQL指令時(shí)需要?jiǎng)討B(tài)加入約束條件,可以通過(guò)創(chuàng)建一份合法字符串列表,使其對(duì)應(yīng)于可能要加入到SQL指令中的不同元素,來(lái)避免SQL注入攻擊。

**例如**:以下代碼片段采用`#`變量名稱,創(chuàng)建參數(shù)化查詢SQL語(yǔ)句。

<!--select user information by name-->

<select id="queryByUserName" resultMap="userResultMap" parameterType="String">

????select * from db_user where user_name=#{username}

</select>

中危:公式注入

微軟公司的Excel或 Apache OpenOffice的Calc等電子表格都支持公式運(yùn)算,如果攻擊者控制了這類表格的數(shù)據(jù),系統(tǒng)可能會(huì)導(dǎo)致任意命令執(zhí)行或泄漏敏感信息。

**例如**:下面代碼片段中,使用未經(jīng)檢查的數(shù)據(jù)來(lái)生成 CSV,并通過(guò)Spring控制器響應(yīng)。

@RequestMapping(value = "/download/count.csv")

public ResponseEntity<String> service(String username) {

????HttpHeaders responseHeaders = new HttpHeaders();

????responseHeaders.add("Content-Type", "application/csv; charset=utf-8");

????responseHeaders.add("Content-Disposition", "attachment;filename=count.csv");

????String data = getCSVDataForUserName(username);

????return new ResponseEntity<>(data, responseHeaders, HttpStatus.OK);

}

當(dāng)data中被注入`:=cmd|'/C calc.exe'!Z0`時(shí),當(dāng)用戶打開(kāi)此電子表格, Windows中的計(jì)算器將在其系統(tǒng)上運(yùn)行。

修復(fù)建議

防止公式注入的方法如下:

1. 程序?qū)Ψ鞘苄诺挠脩糨斎霐?shù)據(jù)進(jìn)行凈化,刪除不安全的字符。

2. 創(chuàng)建一份安全字符串列表,限制用戶只能輸入該列表中的數(shù)據(jù)。

中危:資源注入

使用用戶輸入控制資源標(biāo)識(shí)符,借此攻擊者可以訪問(wèn)或修改其他受保護(hù)的系統(tǒng)資源。當(dāng)滿足以下兩個(gè)條件時(shí),就會(huì)發(fā)生資源注入:

1. 攻擊者可以指定已使用的標(biāo)識(shí)符來(lái)訪問(wèn)系統(tǒng)資源。例如:攻擊者能夠指定用來(lái)連接到網(wǎng)絡(luò)資源的端口號(hào)。

2. 攻擊者可以通過(guò)指定特定資源來(lái)獲取某種權(quán)限,而這種權(quán)限在一般情況下是不可能獲得的。例如:程序可能會(huì)允許攻擊者把敏感信息傳輸?shù)降谌椒?wù)器。

**例1**:下面的代碼片段從HTTP請(qǐng)求獲取端口號(hào),并使用此端口號(hào)創(chuàng)建一個(gè)套接字,而不進(jìn)行任何驗(yàn)證。使用代理的用戶可以修改此端口并獲得與服務(wù)器的直接連接。

String port = request.getParameter("port");

ServerSocket serverSocket = new ServerSocket(port);

Socket socket = serverSocket.accept();

這種利用用戶輸入影響的資源可能存在風(fēng)險(xiǎn)。

**例2**:下面的代碼利用WebView的File域協(xié)議讀取任意可讀文件或受害應(yīng)用的私有文件。

WebView webView=(WebView) findViewById(R.id.webView);

String url= getIntent().getData().toString();

webView.loadUrl(url);

查看hosts文件:`adb shell am start -n com.mytest/.MainActivity -d file:///system/etc/hosts `

查看應(yīng)用私有文件:`adb shell am start -n /data/data/com.cn.test/databases/user.db`

修復(fù)建議:

為了避免資源注入漏洞攻擊,可以采用黑名單或白名單策略。黑名單會(huì)有選擇地拒絕或避免潛在的危險(xiǎn)字符。但是,任何這樣一份黑名單都不可能是完整的,而且將隨著時(shí)間的推移而過(guò)時(shí)。比較好的方法是創(chuàng)建白名單,允許其中的字符出現(xiàn)在資源名稱中,且只接受完全由這些被認(rèn)可的字符所組成的輸入。

中危:HTTP響應(yīng)截?cái)?/h3>

程序從一個(gè)不可信賴的數(shù)據(jù)源獲取數(shù)據(jù),未進(jìn)行驗(yàn)證就置于HTTP頭中發(fā)給用戶,可能會(huì)導(dǎo)致HTTP響應(yīng)截?cái)喙簟?/p>

**例如**:下列代碼片段中,程序從HTTP請(qǐng)求中獲取author的值,并將其設(shè)置到HTTP請(qǐng)求頭的cookie中。

insecureInfo = document.URL;

document.cookie = "author=" + insecureInfo + ";expires="+ cookieExpiration;

author是來(lái)自用戶輸入,未經(jīng)任何處理就存入了cookie中,使應(yīng)用有可能受到cookie篡改的攻擊。如果服務(wù)端解析了cookie,則可以造成其他攻擊。

修復(fù)建議:

創(chuàng)建一份安全字符白名單,只接受完全由這些受認(rèn)可的字符組成的輸入出現(xiàn)在HTTP頭中。

**例如**:以下代碼片段中,驗(yàn)證了author的值是否由標(biāo)準(zhǔn)的字母數(shù)字字符組成。

insecureInfo = document.URL;

var exp = /[0-9A-Za-z]/;

var objExp = new RegExp(exp);

if (objExp.test(insecureInfo)==true) {

????document.cookie = "author=" + insecureInfo + ";expires="+ cookieExpiration;

}

低危:有風(fēng)險(xiǎn)的反序列化

某些協(xié)議如RMI和JMX會(huì)在傳輸層后臺(tái)使用Java序列化。當(dāng)遠(yuǎn)程調(diào)用這些方法時(shí),應(yīng)用程序會(huì)在服務(wù)器上對(duì)參數(shù)進(jìn)行反序列化,此時(shí)攻擊者可以注入惡意對(duì)象。

**例1**:下列代碼是public的RMI接口的示例,其包含的方法具有一個(gè)或多個(gè)參數(shù)。

public interface MyWebService extends Remote {

????public Object doSomething (Object arg0) throws RemoteException;

}

**例2**:JMX MBeans也使用 Java序列化傳輸調(diào)用參數(shù)。在下面的示例中:MyManagedBean中的方法將會(huì)暴露給客戶端。

MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();

ObjectName name = new ObjectName("com.example:type=MyManagedBean");

MyManagedBean myManagedBean = new MyManagedBean();

mBeanServer.registerMBean(myManagedBean, name);

而一些類如RedisTemplate使用默認(rèn)的序列化器存在著不足,攻擊者可以注入惡意對(duì)象,從而使反序列化產(chǎn)生非預(yù)期的對(duì)象,非預(yù)期的對(duì)象有可能帶來(lái)意想不到的結(jié)果。

**例3**:下列代碼是直接返回RedisTemplate,未對(duì)RedisTemplate設(shè)置序列化器。

public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {

????RedisTemplate<Object, Object> template = new RedisTemplate<Object, Object>();

????template.setConnectionFactory(redisConnectionFactory);

????return template;

}

修復(fù)建議:

檢查程序邏輯,確定是否需要使用RMI和JMX等存在反序列化問(wèn)題的協(xié)議,對(duì)于一些序列化器要設(shè)定可選擇策略,以避免產(chǎn)生Java反序列化漏洞。

**例如**:以下代碼對(duì)RedisTemplate設(shè)置了序列化器`Jackson2JsonRedisSerializer`。

public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {

????RedisTemplate<Object, Object> template = new RedisTemplate<Object, Object>();

????template.setConnectionFactory(redisConnectionFactory);

????Jackson2JsonRedisSerializer jacksonSeial = new Jackson2JsonRedisSerializer(Object.class);

????ObjectMapper om = new ObjectMapper();

????om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);

????om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

????jacksonSeial.setObjectMapper(om);

????template.setValueSerializer(jacksonSeial);

????template.setKeySerializer(new StringRedisSerializer());

????template.setHashKeySerializer(new StringRedisSerializer());

????template.setHashValueSerializer(jacksonSeial);

????template.afterPropertiesSet();

????return template;

}

低危:JavaScript劫持:易受攻擊的框架

使用JavaScript傳送敏感數(shù)據(jù)的應(yīng)用程序可能會(huì)存在JavaScript劫持的漏洞,該漏洞允許未經(jīng)授權(quán)的攻擊者從一個(gè)易受攻擊的應(yīng)用程序中讀取機(jī)密數(shù)據(jù)。

JavaScript劫持可以簡(jiǎn)單的理解為模擬授權(quán)的用戶,竊取用戶在服務(wù)器上的信息。Web瀏覽器使用同源策略(Same Origin Policy),以保護(hù)用戶免受惡意網(wǎng)站的攻擊。同源策略規(guī)定:如果要使用JavaScript來(lái)訪問(wèn)某個(gè)網(wǎng)頁(yè)的內(nèi)容的話,則JavaScript和網(wǎng)頁(yè)必須都來(lái)源于相同的域。若不采取同源策略,惡意網(wǎng)站便可以使用受害者的客戶端憑證來(lái)運(yùn)行 JavaScript,從其他網(wǎng)站加載的敏感信息,并對(duì)這些信息進(jìn)行處理,然后將其返回給攻擊者。

使用JSON傳輸數(shù)據(jù)的JavaScript應(yīng)用更容易受到JavaScript劫持攻擊。由于JSON使用JavaScript語(yǔ)法的子集表示對(duì)象、數(shù)組、簡(jiǎn)單值,JSON本身可以被當(dāng)做JavaScript執(zhí)行,且使用*eval*()函數(shù)對(duì)JSON數(shù)據(jù)結(jié)構(gòu)求值早被認(rèn)為是存在風(fēng)險(xiǎn)的,其可能執(zhí)行惡意代碼。

應(yīng)該注意的是,某些過(guò)時(shí)的第三方Javascript框架也可能存在上述的問(wèn)題,使用它們將導(dǎo)致Javascript劫持。

修復(fù)建議:

不使用過(guò)時(shí)的有風(fēng)險(xiǎn)的Javascript框架。

API誤用

中危:依賴未經(jīng)驗(yàn)證和完整性檢查的cookie[Java]

應(yīng)用程序當(dāng)執(zhí)行安全性非常重要的操作時(shí),依賴Cookies的存在或它的值,而有沒(méi)有正確地保證這些設(shè)置對(duì)相關(guān)的用戶是有效的。攻擊者可以很容易地在瀏覽器中或?yàn)g覽器外的客戶端代碼修改cookie。依賴未經(jīng)驗(yàn)證和完整性檢查的cookie可以允許攻擊者繞過(guò)驗(yàn)證,執(zhí)行像SQL注入這樣的注入攻擊和跨站腳本攻擊或者以不期待的方式修改輸入。

**例如**:下面代碼片段中,依賴未經(jīng)驗(yàn)證和完整性檢查的`cookie`進(jìn)行身份鑒別。

```java

public?class?Example?{

????public?void?doGet(HttpServletRequest?request,?HttpServletResponse?response)?throws?ServletException,?IOException?{

????????Cookie[]?cookies?=?request.getCookies();

????????if?(cookies?!=?null)?{

????????????for?(int?i=0;?i<?cookies.length;?i++)?{

????????????????if?("isAdmin".equals(cookies[i].getName()))?{

????????????????????String?isAdmin?=?cookies[i].getValue();

????????????????????//?用cookie存儲(chǔ)的isAdmin字段來(lái)判斷用戶是否為管理員

????????????????????if?("true".equals(isAdmin))?{

????????????????????????...

????????????????????}

????????????????????...

????????????????????break;

????????????????}

????????????}

????????}

????????...

????}

```

修改建議

在做一個(gè)安全相關(guān)的決定時(shí),依賴服務(wù)器端存儲(chǔ)的數(shù)據(jù),避免依賴客戶端傳過(guò)來(lái)的Cookie數(shù)據(jù)。

**例如**:下面代碼片段中,根據(jù)服務(wù)器端存儲(chǔ)的session進(jìn)行身份鑒別。

```java

public?class?Example?{

????public?void?doGet(HttpServletRequest?request,?HttpServletResponse?response)?throws?ServletException,?IOException?{

????????HttpSession?session?=?request.getSession();

????????String?isAdmin?=?(String)?session.getAttribute("isAdmin");

????????if?("true".equals(isAdmin))?{?//?根據(jù)session判斷用戶是否為管理員

????????????...

????????}

????????...

????}

}

```

中危:不安全的框架綁定

目前大部分WEB框架支持將HTTP請(qǐng)求參數(shù)與類的屬性相匹配的而生成一個(gè)對(duì)象。因此,攻擊者能夠?qū)⒅捣湃際TTP請(qǐng)求參數(shù)中從而綁定系統(tǒng)對(duì)象。

**例如**:在以下代碼片段中, Spring MVC可以將 HTTP請(qǐng)求參數(shù)綁定到User所有屬性。

@RequestMapping("/login" )

public String login(User user) {

}

其中,User 類定義為:

public class User {

????private String username;

????private String address;

????private boolean admin;

????private int age;

}

修復(fù)建議:

當(dāng)程序?qū)⒎菍TTP請(qǐng)求參數(shù)直接綁定給對(duì)象時(shí),應(yīng)該要控制綁定到對(duì)象的屬性,防止暴露所有屬性。

在Spring MVC中,可以配置綁定器使用`setAllowedFields`和`setDisallowedFields`方法控制屬性綁定過(guò)程以控制應(yīng)綁定的屬性。

**例1**:在以下代碼片段中,在 Spring MVC(3.0版本至最新)通過(guò)`setDisallowedFields`方法禁止綁定敏感屬性。

@InitBinder

public void initBinder(WebDataBinder binder) {

????binder.setDisallowedFields(new String[]{"admin"});

}

@RequestMapping("/login" )

public String login(User user) {

}

**例2**:在 Spring MVC(2.X版本)通過(guò)`setDisallowedFields`方法禁止綁定敏感屬性。

@Override

protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {

????binder.setDisallowedFields(new String[]{"admin"});

}

而在使用 `@RequestBody`注釋參數(shù)的 Spring MVC應(yīng)用程序中,綁定過(guò)程由HttpMessageConverter進(jìn)行處理,這些實(shí)例使用Jackson和JAXB等庫(kù)將 HTTP請(qǐng)求參數(shù)轉(zhuǎn)換為Java對(duì)象。這些庫(kù)提供了注釋來(lái)控制應(yīng)允許或禁止的字段。例如對(duì)于Jackson,可以使用`@JsonIgnore`注釋禁止將某個(gè)字段綁定到請(qǐng)求。

**例3**:在以下代碼片段中,Jackson禁止綁定敏感屬性。

@RequestMapping(value="/add/user", method=RequestMethod.POST, consumes="text/html")

public void addEmployee(@RequestBody User user){

}

public class User {

????private String username;

????private String address;

????@JsonIgnore

????private boolean admin;

????private int age;

}

同理,Jackson還可以使用`@JsonIgnoreProperties、@JsonIgnoreType和 @JsonInclude`等注解告訴框架忽略這些屬性,使用JAXB使用`@XmlAccessorType、@XmlAttribute、@XmlElement和 @XmlTransient`等注解告訴框架忽略這些屬性,然后使用`@XmlAttribute和@XmlElement`等注解選擇應(yīng)綁定的字段。

**例4**:在以下代碼片段中,Jackson使用`@XmlAttribute`選擇要綁定的字段。

@XmlRootElement

@XmlAccessorType(XmlAccessType.NONE)

public class User {

????private String username;

????private String address;

????@JsonIgnore

????private boolean admin;

????private int age;

????@XmlAttribute

????public String getUsername() {

????????return username;

????}

????public void setUsername(String username) {

????????this.username = username;

????}

????@XmlAttribute

????public String getAddress() {

????????return address;

????}

????

????public void setAddress(String address) {

????????this.address = address;

????}

????private boolean isAdmin() ?{

????????return admin;

????}

????private void setAdmin(boolean admin) ?{

????????this.admin = admin;

????}

}

在Struts 1和 2 中,如果某個(gè)屬性不應(yīng)綁定到請(qǐng)求,則應(yīng)將其 `setter`方法設(shè)置為私有即可。

**例5**:在以下代碼片段中,在Struts可以將某個(gè)屬性的`setter`方法設(shè)置為私有從而禁止綁定敏感屬性。

private boolean admin;

private void setAdmin(boolean admin) ?{

????this.admin = admin;

}

還有另一種方法是使用將 HTTP請(qǐng)求參數(shù)綁定到僅含有Web表單或API中定義的屬性DTO對(duì)象中,再將其映射到User中,防止敏感字段暴露。

低危:忽略返回值

一般在開(kāi)發(fā)過(guò)程中,程序員憑借經(jīng)驗(yàn)可以斷言某些用戶事件或條件,例如某個(gè)函數(shù)永遠(yuǎn)不會(huì)執(zhí)行失敗。但是,攻擊者往往會(huì)故意觸發(fā)一些異常情況,導(dǎo)致沖破了程序員的斷言,給系統(tǒng)帶來(lái)了不穩(wěn)定性,利用不正確的行為觸發(fā)出發(fā)程序的漏洞。**例如**:程序調(diào)用刪除權(quán)限函數(shù),但不檢查返回值判斷是否成功刪除權(quán)限,則程序?qū)⒗^續(xù)以更高權(quán)限運(yùn)行。

**例如**:在下面的代碼片段中,程序沒(méi)有對(duì)`read()`返回值做判斷。

int bytesToRead = 1024;

byte[] byteArray = new byte[bytesToRead];

streamFileInput = new FileInputStream("C:\\file.txt");

streamFileInput.read(byteArray);

修復(fù)建議:

程序應(yīng)檢查方法的返回值,確保方法返回的是期望的數(shù)據(jù),再進(jìn)行下一步操作。

低危:HTTP響應(yīng)完成后繼續(xù)操作輸出流

轉(zhuǎn)發(fā)`HttpServletRequest`、重定向`HttpServletResponse`或刷新servlet的輸出流緩沖區(qū)會(huì)導(dǎo)致提交相關(guān)的數(shù)據(jù)流,程序后續(xù)再執(zhí)行到緩沖區(qū)重置或數(shù)據(jù)流提交,將會(huì)拋出`IllegalStateException`異常。

此外,servlets允許使用`ServletOutputStream`或`PrintWriter`將數(shù)據(jù)寫(xiě)入響應(yīng)數(shù)據(jù)流。如果在調(diào)用`getOutputStream()`之后再調(diào)用`getWriter()`或者反向調(diào)用,會(huì)導(dǎo)致拋出`IllegalStateException`異常,使其中斷響應(yīng)。

**例如**:在下面代碼片段中,會(huì)在servlet的輸出流緩沖區(qū)刷新之后進(jìn)行重定向,會(huì)拋出`IllegalStateException`異常。

public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

????OutputStream os = response.getOutputStream();

????os.flush();

????os.close();

????response.sendRedirect("http://www.codesafe.cn");

}

修復(fù)建議:

避免HTTP響應(yīng)完成后繼續(xù)操作輸出流,應(yīng)注意:

1. 提交servlet的輸出流之后,不要重置數(shù)據(jù)流緩沖區(qū)或執(zhí)行重新提交該數(shù)據(jù)流。

2. 避免在調(diào)用`getOutputStream()`之后調(diào)用`getWriter()`,或者在調(diào)用`getWriter()`后調(diào)用`getOutputStream()`。

低危:缺少對(duì)方法返回值的null檢查

程序沒(méi)有對(duì)有可能返回null的方法返回值進(jìn)行檢查,可能會(huì)導(dǎo)致NullPointException。

**例如**:下列代碼片段中,未對(duì)`getenv()`方法的返回值data進(jìn)行null檢查,可能會(huì)拋出NullPointException。

String data = System.getenv("ADD");

if (data.equalsIgnoreCase("XXX") ){

????...

}

修復(fù)建議:

程序應(yīng)對(duì)可能返回null的方法的返回值進(jìn)行檢查,避免產(chǎn)生NullPointException。

密碼管理

中危:不安全的隨機(jī)數(shù)

Java API中提供了`java.util.Random`類實(shí)現(xiàn)`PRNG()`,該P(yáng)RNG是可移植和可重復(fù)的,如果兩個(gè)`java.util.Random`類的實(shí)例使用相同的種子,會(huì)在所有Java實(shí)現(xiàn)中生成相同的數(shù)值序列。

**例如**:下面代碼片段中,使用了`java.util.Random`類,該類對(duì)每一個(gè)指定的種子值生成同一個(gè)序列。

import java.util.Random;

public static void main (String args[]) {

????for (int i = 0; i < 10; i++) {

????????Random random = new Random(123456);

????????int number = random.nextInt(21);

????}

}

修復(fù)建議:

在安全性要求較高的應(yīng)用中,應(yīng)使用更安全的隨機(jī)數(shù)生成器,如`java.security.SecureRandom`類。

**例如**:下面代碼片段中,使用`java.security.SecureRandom`來(lái)生成更安全的隨機(jī)數(shù)。

import java.security.SecureRandom;

import java.security.NoSuchAlgorithmException;

public static void main (String args[]) {

????try {

????????SecureRandom random = SecureRandom.getInstance("SHA1PRNG");

????????for (int i = 0; i < 10; i++) {

????????????int number = random.nextInt(21);

????????}

????} catch (NoSuchAlgorithmException nsae) {

????}

}

中危:空密碼

程序中使用了空的密碼值,系統(tǒng)安全性將會(huì)受到威脅。

**例如**:下列代碼中采用了空的密碼。

public Connection getConnection(){

????String url = "localhost";

????String name = "admin";

????String password = "";

}

修復(fù)建議:

程序中不應(yīng)使用空的密碼值,程序所需密碼應(yīng)從配置文件中獲取加密的密碼值。

**例如**:下列代碼中從配置文件中獲取經(jīng)過(guò)加密的密碼值并解密使用。

public Connection getConnection(){

????String url = EncryptUtil.decrypt(PropertiesUtil.get("connection.url"));

????String name = EncryptUtil.decrypt(PropertiesUtil.get("connection.username"));

????String password = EncryptUtil.decrypt(PropertiesUtil.get("connection.password"));

}

中危:硬編碼密碼

程序中采用硬編碼方式處理密碼,一方面會(huì)降低系統(tǒng)安全性,另一方面不易于程序維護(hù)。

**例如**:下列代碼中采用硬編碼方式處理密碼。

public class ConnectionConfig{

????String url = "localhost";

????String name = "admin";

????String password = "123456";

}

修復(fù)建議:

程序中不應(yīng)對(duì)密碼進(jìn)行硬編碼,可以使用配置文件或數(shù)據(jù)庫(kù)存儲(chǔ)的方式來(lái)存儲(chǔ)系統(tǒng)所需的數(shù)據(jù);并且錄入數(shù)據(jù)時(shí),還可以在對(duì)敏感數(shù)據(jù)做加密處理之后再進(jìn)行數(shù)據(jù)的錄入。

**例如**:下列代碼中從配置文件中獲取經(jīng)過(guò)加密的密碼值并解密使用。

public class ConnectionConfig{

????String url = EncryptUtil.decrypt(PropertiesUtil.get("connection.url"));

????String name = EncryptUtil.decrypt(PropertiesUtil.get("connection.username"));

????String password = EncryptUtil.decrypt(PropertiesUtil.get("connection.password"));

}

中危:弱加密

在安全性要求較高的系統(tǒng)中,使用不安全的加密算法(如DES、RC4、RC5等),將無(wú)法保證敏感數(shù)據(jù)的保密性。

**例如**:下面代碼片段中,采用DES對(duì)數(shù)據(jù)進(jìn)行加密。

BufferedReader bufread2 = null;

InputStreamReader inread2 = null;

try {

????inread2 = new InputStreamReader(System.in);

????bufread2 = new BufferedReader(inread2);

????String str = bufread2.readLine();

????/* FLAW: Insecure cryptographic algorithm (DES) */

????Cipher des = Cipher.getInstance("DES");

????SecretKey key = KeyGenerator.getInstance("DES").generateKey();

????des.init(Cipher.ENCRYPT_MODE, key);

????byte[] enc_str = des.doFinal(str.getBytes());

????IO.writeLine(IO.toHex(enc_str));

} catch(IOException e) {

????log_bsnk.warning("Error reading from console");

} finally{

}

修復(fù)建議:

在安全性要求較高的系統(tǒng)中,建議應(yīng)使用安全的加密算法(如AES、RSA)對(duì)敏感數(shù)據(jù)進(jìn)行加密。

**例如**:下面代碼片段中,使用AES取代DES保證數(shù)據(jù)完整性。

BufferedReader bufread2 = null;

InputStreamReader inread2 = null;

try {

????inread2 = new InputStreamReader(System.in);

????bufread2 = new BufferedReader(inread2);

????String str = bufread2.readLine();

????/* FIX: Secure cryptographic algorithm (AES) */

????Cipher aes = Cipher.getInstance("AES");

????KeyGenerator kg = KeyGenerator.getInstance("AES");

????kg.init(128);

????SecretKey key = kg.generateKey();

????aes.init(Cipher.ENCRYPT_MODE, key);

????byte[] enc_str = aes.doFinal(str.getBytes());

????IO.writeLine(IO.toHex(enc_str));

} catch(IOException e) {

????log_gsnk.warning("Error reading from console");

} finally{

}

中危:配置文件中的明文密碼

配置文件中采用明文存儲(chǔ)密碼,所有能夠訪問(wèn)該文件的人都能訪問(wèn)該密碼,將會(huì)降低系統(tǒng)安全性。

**例如**:下列配置文件中采用明文存儲(chǔ)密碼。

jdbc.username=user

jdbc.password=123456

修復(fù)建議:

即使不能阻止應(yīng)用程序被那些可以訪問(wèn)配置文件的攻擊者入侵,也可以通過(guò)加密密碼提升攻擊者入侵難度,故配置文件中的密碼應(yīng)進(jìn)行加密存儲(chǔ)。

**例如**:下列配置文件中采用jasypt加密的密碼存儲(chǔ)密碼。

jdbc.username=user

jdbc.password=ENC(AaDVxaWVcgnN4lZswvK46QQkaxCfD7Xa)

中危:硬編碼加密密鑰

當(dāng)程序中使用硬編碼加密密鑰時(shí),所有項(xiàng)目開(kāi)發(fā)人員都可以查看該密鑰,甚至如果攻擊者可以獲取到程序class文件,可以通過(guò)反編譯得到密鑰,硬編碼加密密鑰會(huì)大大降低系統(tǒng)安全性。

**例如**:下列代碼使用硬編碼加密密鑰執(zhí)行AES加密。

private static String encryptionKey = "dfashsdsdfsdgagascv";

byte[] keyBytes = encryptionKey.getBytes();

SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");

Cipher encryptCipher = Cipher.getInstance("AES");

encryptCipher.init(Cipher.ENCRYPT_MODE, key);

修復(fù)建議:

程序應(yīng)采用不小于8個(gè)字節(jié)的隨機(jī)生成的字符串作為密鑰。

**例如**:以下代碼使用KeyGenerator來(lái)生成密鑰。

KeyGenerator keyGen = KeyGenerator.getInstance("AES");

keyGen.init(128, new SecureRandom(password.getBytes()));

SecretKey secretKey = kgen.generateKey();

byte[] keyBytes = secretKey.getEncoded();

SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");

Cipher encryptCipher = Cipher.getInstance("AES");

encryptCipher.init(Cipher.ENCRYPT_MODE, key);

低危:注釋中的密碼

應(yīng)用程序注釋中保留密碼等敏感信息,將使敏感信息對(duì)任何能夠獲取到該文件的人員可見(jiàn)。

修復(fù)建議:

應(yīng)用程序注釋中不應(yīng)保留密碼等敏感信息。

低危:不安全的哈希算法

在安全性要求較高的系統(tǒng)中,不應(yīng)使用被業(yè)界公認(rèn)的不安全的哈希算法(如MD2、MD4、MD5、SHA、SHA1等)來(lái)保證數(shù)據(jù)的完整性。

**例如**:下面代碼片段中,采用MD5算法來(lái)保證數(shù)據(jù)的完整性。

byte[] b = str.getBytes();

MessageDigest md = null;

try {

????md = MessageDigest.getInstance("MD5");

????md.update(b);

}catch (NoSuchAlgorithmException e){

}

修復(fù)建議:

在安全性要求較高的系統(tǒng)中,應(yīng)采用散列值>=224比特的SHA系列算法(如SHA-224、SHA-256、SHA-384和SHA-512)來(lái)保證敏感數(shù)據(jù)的完整性。

**例如**:下面代碼片段中,使用SHA-256算法取代MD5算法保證數(shù)據(jù)完整性。

byte[] b = str.getBytes();

MessageDigest md = null;

try {

????md = MessageDigest.getInstance("SHA-256");

????md.update(b);

} catch (NoSuchAlgorithmException e) {

????...

}

低危:弱加密:不安全的塊密碼加密模式

塊密碼又稱為分組加密,一次加密明文中的一個(gè)塊。將明文按一定的位長(zhǎng)分組,明文組經(jīng)過(guò)加密運(yùn)算得到密文組,密文組經(jīng)過(guò)解密運(yùn)算(加密運(yùn)算的逆運(yùn)算),還原成明文組。這種加密算法共有四種操作模式用于描述如何重復(fù)地應(yīng)用密碼的單塊操作來(lái)安全的轉(zhuǎn)換大于塊的數(shù)據(jù)量,分別是電子代碼(ECB)、密碼塊鏈(CBC)、密碼反饋(CFB)以及輸出反饋(OFB)。其中ECB模式下相同的明文塊總是會(huì)得到相同的密文,故不能抵擋回放攻擊,而CBC模式則沒(méi)有這個(gè)缺陷。

**例如**:以下代碼將AES密碼用于ECB模式。

Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");

cipher.init(Cipher.ENCRYPT_MODE, createSecretKey(seed));

修復(fù)建議:

加密大于塊的數(shù)據(jù)時(shí),應(yīng)該避免使用ECB模式,因?yàn)镋CB模式下相同的明文塊總是會(huì)得到相同的密文,有回放攻擊的風(fēng)險(xiǎn)。CBC模式可以避免回放攻擊,但是其效率較低,并且在和SSL一起使用時(shí)會(huì)造成嚴(yán)重風(fēng)險(xiǎn)。故可以改用`CCM(Counter with CBC-MAC)`模式,如果更注重性能,在可用的情況下則使用`GCM(Galois/Counter)`模式。

**例如**:以下代碼將AES密碼用于GCM模式。

GCMParameterSpec s = new GCMParameterSpec(tLen, src);

Cipher cipher = Cipher.getInstance("AES/OFB8/PKCS5Padding");

cipher.init(Cipher.ENCRYPT_MODE, createSecretKey(seed), s);

低危:不安全的隨機(jī)數(shù)

JavaScript的`Math.random()`實(shí)現(xiàn)PRNG(偽隨機(jī)數(shù)序列發(fā)生器),該P(yáng)RNG是可移植和可重復(fù)的,因此如果兩個(gè)

`Math.random()`使用相同的種子,會(huì)生成相同的數(shù)值序列。

**例如**:下面的代碼使用

Math.random()

創(chuàng)建的Token很容易被猜到。

function getToken (){

????var token = Math.random();

????return token;

}

修復(fù)建議:

JavaScript在安全性要求較高的環(huán)境中生成隨機(jī)數(shù),常規(guī)的建議是使用 Mozilla API 中的`window.crypto.getRandomValues()`函數(shù),但這種方法受限于瀏覽器的兼容性,只在較新的版本(Chrome>=11.0, Firefox>=21, Edge, IE>=11, Safari>=3.1)可以使用。如果考慮到舊版本瀏覽器,則應(yīng)在javascript之外處理PRNG功能。

**例如**:缺陷描述中的例子可以改寫(xiě)為。

function getToken (){

????var array = new Uint32Array(1);

????window.crypto.getRandomValues(array);

????var token = array[0];

????return token;

}

低危:注釋中的密碼

應(yīng)用程序注釋中保留密碼等敏感信息,將使敏感信息對(duì)任何能夠獲取到該文件的人員可見(jiàn)。

**例如**:

//password:123

修復(fù)建議:

應(yīng)用程序注釋中不應(yīng)保留密碼等敏感信息。

低危:不安全的提交

使用HTTP GET的方式提交敏感信息如密碼,可能造成密碼被顯示,記錄等。

**例如**:以下示例使用HTTP GET的方式提交表單中的密碼。

<form method="get">

密碼: <input type="password" >

<input type="submit" name="" value="提交" >

</form>

修復(fù)建議:

避免使用HTTP GET的方式提交敏感數(shù)據(jù),應(yīng)使用HTTP POST傳輸敏感數(shù)據(jù)。

**例1**:以下示例通過(guò)HTTP POST的方式提交用戶的密碼。

<form method="post">

????密碼: <input type="password" >

????<input type="submit" name="" value="提交" >

</form>

HTML5新增了一項(xiàng)功能,可以將formmethod屬性作為 submit 和 image 輸入標(biāo)簽一部分的功能,并且該屬性值會(huì)覆蓋相應(yīng)form標(biāo)簽中 method 屬性值。

**例2**:以下示例用戶使用HTTP POST的方式提交密碼,是由submit輸入標(biāo)簽 formmethod 的屬性值所指定。

<form method="get">

????密碼: <input type="password" >

????<input type="submit" name="" value="提交" ?formmethod="post">

</form>

注意,如果將formmethod的值設(shè)為get,form的method的無(wú)論為什么,都會(huì)通過(guò)HTTP GET的方式提交表單。

資源管理

中危:路徑訪問(wèn)控制[Java]

程序未進(jìn)行恰當(dāng)?shù)脑L問(wèn)控制,使用用戶控制的值作為路徑,可能會(huì)導(dǎo)致攻擊者訪問(wèn)未經(jīng)授權(quán)的文件。

**例如**:下面代碼片段直接通過(guò)外部輸入id下載相應(yīng)圖片。

```java

...

String?id?=?request.getParameter("id");

File?f?=?new?File("/user/"+Integer.valueOf(id)+".png");

download(f);

...

```

以上代碼將通過(guò)用戶ID獲取文件,其正常的使用方式是:

`http://www.example.com/download?id=00001`

當(dāng)攻擊者訪問(wèn)如下網(wǎng)址,服務(wù)器將會(huì)獲取其他用戶文件,導(dǎo)致信息泄露:

`http://www.example.com/download?id=00002`

修復(fù)建議

任何情況下都不允許用戶在沒(méi)有取得相應(yīng)權(quán)限的情況下獲取或修改文件。可以通過(guò)把當(dāng)前被授權(quán)的用戶信息作為獲取文件方式來(lái)實(shí)現(xiàn)。

**例如**:下面代碼片段通過(guò)當(dāng)前用戶id下載相應(yīng)圖片。

```java

...

Object?principal?=?SecurityContextHolder.getContext().getAuthentication().getPrincipal();

User?user?=?(User)principal;

File?f?=?new?File("/user/"+user.getId()+".png");

download(f);

...

```

中危:?jiǎn)卫蓡T變量[Java]

`javax.servlet.http.HttpServlet`和`org.apache.struts.action.Action`的對(duì)象不是線程安全的。對(duì)于同一個(gè)Servlet對(duì)象(或struts1的Action對(duì)象)的多個(gè)請(qǐng)求,Servlet對(duì)象(或struts1的Action對(duì)象)將在一個(gè)多線程的環(huán)境中并發(fā)執(zhí)行。Web容器默認(rèn)采用單實(shí)例多線程的方式來(lái)處理Http請(qǐng)求,這將導(dǎo)致Servlet對(duì)象(或struts1的Action對(duì)象)成員變量訪問(wèn)的線程安全問(wèn)題。

**例如**:下面是一段JAVA?EE的Servlet代碼片斷,變量`username`為成員變量,當(dāng)LoginServlet的對(duì)象處理多個(gè)請(qǐng)求時(shí),變量`username`將被多個(gè)請(qǐng)求共享,這將導(dǎo)致線程間數(shù)據(jù)泄露。

```java

...

import?javax.servlet.http.HttpServlet;

public?class?LoginServlet?extends?HttpServlet?{

????String?username;

????protected?void?doPost(HttpServletRequest?req,HttpServletResponse?res)?{

????????username?=?req.getParameter("username");

????????...

????????out.println(?"?歡迎您,"+username+"?!");

????}

}

...

```

修復(fù)建議

使用Java?EE的Servlet或struts1的Action時(shí),必須保證其是線程安全的。修復(fù)方式舉例如下:

**例如**:下面代碼示例,使用局部變量,因?yàn)榫植孔兞吭诿總€(gè)線程中都有各自的實(shí)例,從而保證線程安全。

```java

...

import?javax.servlet.http.HttpServlet;

public?class?LoginServlet?extends?HttpServlet?{

????protected?void?doPost(HttpServletRequest?req,HttpServletResponse?res)?{

????????String?username?=?req.getParameter("username");

????????...

????????out.println("歡迎您,"+username+"!");

????}

}

...

```

另外,也可以使用同步代碼塊訪問(wèn)servlet實(shí)例變量。但使用同步代碼塊可能會(huì)導(dǎo)致性能問(wèn)題。

中危:反射型文件下載[NodeJS]

反射型文件下載(RFD)是一種攻擊技術(shù),通過(guò)從受信任的域(例如Google.com和Bing.com)虛擬下載文件,攻擊者可以使攻擊者獲得對(duì)受害者計(jì)算機(jī)的完全訪問(wèn)權(quán)限。

**例如**:以下示例直接獲取網(wǎng)絡(luò)上的資源。

```javascript

jQuery.getJSON("http://example.com",?function(a)?{

});

```

修復(fù)建議

可以使用以下方式防止反射型文件的下載。

1.?使用`Content-Disposition`強(qiáng)行限制文件名;

2.?使用?CSRF?令牌;

3.?為所有API實(shí)現(xiàn)安全的請(qǐng)求頭信息。

中危:格式化缺陷[Java]

格式化對(duì)象是非線程安全的,java.text.Format中的`parse()`和`format()`方法包含一個(gè)可導(dǎo)致用戶看到其他用戶數(shù)據(jù)的race?condition。

**例如**:下面代碼片段中,定義了一個(gè)成員變量(靜態(tài)的日期格式對(duì)象)。

```java

public?class?DateFormat?extends?Thread{

????private?static?SimpleDateFormat?sdf?=?new?SimpleDateFormat("yyyy-MM-dd");

????private?String?name;

????private?String?dateStr;

????public?DateFormat(String?name,?String?dateStr)?{

????????this.name?=?name;

????????this.dateStr?=?dateStr;

????}

????@Override

????public?void?run()?{

????????try?{

????????????Date?date?=?sdf.parse(dateStr);

????????????System.out.println("線程"+name+"運(yùn)行日期:"+date);

????????}?catch?(ParseException?e)?{

????????????e.printStackTrace();

????????}

????}

????public?static?void?main(String[]?args)?{

????????ExecutorService?executorService?=?Executors.newFixedThreadPool(3);

????????executorService.execute(new?DateFormat("A",?"2017-06-10"));

????????executorService.execute(new?DateFormat("B",?"2016-06-06"));

????????executorService.shutdown();

????}

}

```

如上代碼中輸出會(huì)有兩種情況,一種情況是報(bào)錯(cuò),還有一種情況是兩個(gè)線程輸出一致。出現(xiàn)這種情況的原因是因?yàn)镾impleDateFormat類內(nèi)部有一個(gè)Calendar對(duì)象引用,它用來(lái)儲(chǔ)存和這個(gè)SimpleDateFormat相關(guān)的日期信息。這樣就會(huì)導(dǎo)致一個(gè)問(wèn)題,如果SimpleDateFormat是static的,?那么多個(gè)thread之間就會(huì)共享SimpleDateFormat,?同時(shí)也是共享Calendar引用。在高并發(fā)的情況下,容易出現(xiàn)幻讀成員變量的現(xiàn)象。

修復(fù)建議

有如下四種解決方法

1.?將格式化對(duì)象定義成局部變量,但是每調(diào)用一次方法意味創(chuàng)建一個(gè)格式化對(duì)象,浪費(fèi)內(nèi)存。

2.?方法加同步鎖synchronized,在同一時(shí)刻,只有一個(gè)線程可以執(zhí)行類中的某個(gè)方法。這樣性能較差,每次都要等待鎖釋放后其他線程才能進(jìn)入。

3.?使用第三方庫(kù)joda-time,由第三方考慮線程不安全的問(wèn)題。

4.?使用ThreadLocal:每個(gè)線程擁有自己的格式化對(duì)象。

中危:數(shù)據(jù)庫(kù)訪問(wèn)控制

程序未進(jìn)行恰當(dāng)?shù)脑L問(wèn)控制,執(zhí)行了一個(gè)包含用戶控制主鍵的SQL語(yǔ)句,可能會(huì)導(dǎo)致攻擊者訪問(wèn)未經(jīng)授權(quán)的記錄。

**例如**:下面代碼片段中的SQL語(yǔ)句用于查詢與指定標(biāo)識(shí)符相匹配的清單。

id = Integer.decode(request.getParameter("invoiceID"));

String query = "SELECT * FROM invoices WHERE id = ?";

PreparedStatement stmt = conn.prepareStatement(query);

stmt.setInt(1, id);

ResultSet results = stmt.execute();

在上面代碼中,攻擊者可以通過(guò)為`invoiceID`設(shè)置不同的值,獲取所需的任何清單信息。

修復(fù)建議:

任何情況下都不允許用戶在沒(méi)有取得相應(yīng)權(quán)限的情況下獲取或修改數(shù)據(jù)庫(kù)中的記錄??梢酝ㄟ^(guò)把當(dāng)前被授權(quán)的用戶名作為查詢語(yǔ)句的一部分來(lái)實(shí)現(xiàn)。

**例如**:下面代碼片段中,通過(guò)把當(dāng)前被授權(quán)的用戶名作為查詢語(yǔ)句的一部分來(lái)限制用戶對(duì)清單的訪問(wèn)。

userName = ctx.getAuthenticatedUserName();

id = Integer.decode(request.getParameter("invoiceID"));

String query = "SELECT * FROM invoices WHERE id = ? AND user = ?";

PreparedStatement stmt = conn.prepareStatement(query);

stmt.setString(1, id);

stmt.setString(2, userName);

ResultSet results = stmt.execute();

中危:資源未釋放:Sockets[Java]

程序創(chuàng)建或分配Socket后,不進(jìn)行合理釋放,將會(huì)降低系統(tǒng)性能。攻擊者可能會(huì)通過(guò)耗盡資源池的方式發(fā)起拒絕服務(wù)攻擊。

**例如**:下面代碼片段中,創(chuàng)建了一個(gè)套接字socket對(duì)象,未進(jìn)行合理釋放。

```java

public?void?getSocket(String?host,int?port){

????try?{

????????Socket?socket?=?new?Socket(host,port);

????????BufferedReader?reader?=?new?BufferedReader(new?InputStreamReader(socket.getInputStream()));

????????while(reader.readLine()!=null){

????????????...

????????}

????}?catch?(UnknownHostException?e)?{

????????e.printStackTrace();

????}?catch?(IOException?e)?{

????????e.printStackTrace();

????}

}

```

修復(fù)建議

程序不應(yīng)依賴于虛擬機(jī)的`finalize()`方法來(lái)自動(dòng)回收Socket資源,而需要手動(dòng)在finally代碼塊中做Socket資源的釋放操作。

**例如**:下面代碼片段中,使用完之前創(chuàng)建的socket套接字資源后,在finally代碼塊中進(jìn)行了釋放。

```java

public?void?getSocket(String?host,int?port){

????Socket?socket?=?null;

????try?{

????????socket?=?new?Socket(host,port);

????????BufferedReader?reader?=?new?BufferedReader(new?InputStreamReader(socket.getInputStream()));

????????while(reader.readLine()!=null){

????????????...

????????}

????}?catch?(UnknownHostException?e)?{

????????e.printStackTrace();

????}?catch?(IOException?e)?{

????????e.printStackTrace();

????}finally{

????????if(socket!=null){

????????????try?{

????????????????socket.close();

????????????}?catch?(IOException?e)?{

????????????????e.printStackTrace();

????????????}

????????}

????}

?}

```

中危:資源未釋放:流

程序創(chuàng)建或分配流資源后,不進(jìn)行合理釋放,將會(huì)降低系統(tǒng)性能。攻擊者可能會(huì)通過(guò)耗盡資源池的方式發(fā)起拒絕服務(wù)攻擊。

**例如**:在下面Java方法中,創(chuàng)建I/O流對(duì)象后未進(jìn)行合理釋放,程序依靠Java虛擬機(jī)的垃圾回收機(jī)制釋放I/O流資源,事實(shí)上,程序不能確定何時(shí)調(diào)用虛擬機(jī)的`finalize()`方法。在繁忙的程序環(huán)境下,可能導(dǎo)致Java虛擬機(jī)不能有效的使用I/O對(duì)象。

public void processFile(String filePath){

????try {

????????FileInputStream fis = new FileInputStream(filePath);

????????InputStreamReader isr = new InputStreamReader(fis);

????????BufferedReader br = new BufferedReader(isr);

????????String line="";

????????while((line=br.readLine())!=null){

????????????processLine(line);

????????}

????} catch (FileNotFoundException e) {

????????log(e);

????} catch (IOException e){

????????log(e);

????}

}

程序不應(yīng)依賴于Java虛擬機(jī)的`finalize()`方法來(lái)自動(dòng)回收流資源,而需要手動(dòng)在finally代碼塊中進(jìn)行流資源的釋放。

**例如**:下面代碼片段中,在finally代碼塊中對(duì)流資源進(jìn)行了合理的釋放。

public void processFile(String filePath){

????FileInputStream fis = null;

????InputStreamReader isr = null;

????BufferedReader br = null;

????try {

????????fis = new FileInputStream(filePath);

????????isr = new InputStreamReader(fis);

????????br = new BufferedReader(isr);

????????String line="";

????????while((line=br.readLine())!=null){

????????????//processLine(line);

????????}

????} catch (FileNotFoundException e) {

????????//log(e);

????} catch (IOException e){

????????//log(e);

????}finally{

????????if(br!=null){

????????????try {

????????????????br.close();

????????????} catch (IOException e) {

????????????????//log(e);

????????????}

????????}

????????if(isr!=null){

????????????try {

????????????????isr.close();

????????????} catch (IOException e) {

????????????????//log(e);

????????????}

????????}

????????if(fis!=null){

????????????try {

????????????????fis.close();

????????????} catch (IOException e) {

????????????????//log(e);

????????????}

????????}

????}

}

中危:使用不安全的target blank

在 `<a>`標(biāo)簽中使用target屬性,值設(shè)置為`_blank`攻擊者會(huì)針對(duì)`window.opener`API進(jìn)行惡意行為的攻擊,有可能導(dǎo)致釣魚(yú)安全漏洞問(wèn)題。

**例如**:以下示例使用的`targer`屬性,但是沒(méi)有設(shè)置`rel`屬性。

<a href="www.example.com" target="_blank"/>

修復(fù)建議:

建議使用`target="_blank"`時(shí),配合使用`rel="noopenner noreferrer"`。

**例如**:配合使用`rel`屬性。

<a href="www.example.com" target="_blank" rel="noopenner noreferrer"/>

代碼質(zhì)量

高危:郵件服務(wù)器建立未加密的連接[Java]

郵件服務(wù)器使用的是未加密的連接,使用未加密網(wǎng)絡(luò)發(fā)送敏感信息可能會(huì)被惡意攻擊者通過(guò)攔截網(wǎng)絡(luò)通信讀取并修改信息。

**例如**:下面代碼示例中:AuthenticatingSMTPClient未使用TLS進(jìn)行數(shù)據(jù)的發(fā)送。

```java

AuthenticatingSMTPClient?client?=?new?AuthenticatingSMTPClient();

client.connect(url);

...

Writer?writer?=?client.sendMessageData();

...

```

修復(fù)建議

可使用SSL/TLS對(duì)通過(guò)網(wǎng)絡(luò)發(fā)送的所有數(shù)據(jù)進(jìn)行加密,或者將現(xiàn)有的未加密連接升級(jí)到SSL/TLS。

**例如**:下面代碼示例中:AuthenticatingSMTPClient未使用TLS進(jìn)行數(shù)據(jù)的發(fā)送。

```java

AuthenticatingSMTPClient?client?=?new?AuthenticatingSMTPClient();

client.connect(url);

...

client.execTLS();

Writer?writer?=?client.sendMessageData();

...

```

中危:webpack源碼泄露[NodeJS]

通過(guò)打印或日志記錄功能將系統(tǒng)數(shù)據(jù)或調(diào)試信息發(fā)送到本地文件、控制臺(tái)或屏幕時(shí),就會(huì)發(fā)生內(nèi)部信息泄露。

webpack項(xiàng)目源碼在泄漏的情況下,可以在瀏覽器控制臺(tái)中的Sources—>?Page—>?webpack://中查看源代碼。

使用webpack打包應(yīng)用程序會(huì)在網(wǎng)站js同目錄下生成js.map文件。

1.直接查看網(wǎng)站的js文件,可以在末尾處有js.map文件名。

2.直接在當(dāng)前訪問(wèn)的js后面拼接.map即可訪問(wèn)下載

通過(guò)以上兩種方式可以判斷目標(biāo)網(wǎng)站存在webpack源碼泄露問(wèn)題。

js.map文件可以配合使用reverse-sourcemap或SourceDetector進(jìn)行js.map文件還原操作,從而泄露源代碼

修復(fù)建議

1.在項(xiàng)目路徑下修改config/index.js中build對(duì)象productionSourceMap:?false;

2.建議刪除或禁止訪問(wèn)正式環(huán)境中的js.map文件;

中危:不安全的信息傳輸[Java]

程序使用HTTP、FTP等協(xié)議進(jìn)行通信,未對(duì)通信信息進(jìn)行加密和驗(yàn)證,可能會(huì)受到危害,尤其是移動(dòng)設(shè)備利用WiFi連接不安全的、公共的無(wú)線網(wǎng)絡(luò)。

**例如**:下面代碼片段中表示將使用HTTP進(jìn)行連接,傳遞的敏感信息容易被攻擊者竊取。

```java

...

HttpHost?httppost?=?HttpHost(inetAddress,port,"http");

...

```

修復(fù)建議

程序應(yīng)盡可能基于HTTPS等安全協(xié)議與服務(wù)器進(jìn)行通信,尤其是進(jìn)行敏感信息的傳遞。

中危:未設(shè)置httpOnly[NodeJS]

目前主流的瀏覽器都支持cookie的httpOnly屬性,該屬性設(shè)置為true的時(shí)候表示cookie只能由web服務(wù)器訪問(wèn),如果不設(shè)置該屬性的話默認(rèn)為false這樣攻擊者就可以很容易的訪問(wèn)到cookie信息,從而獲取authentication標(biāo)記或者一些會(huì)話信息。

**例如**:下面代碼段創(chuàng)建cookie,但是沒(méi)有設(shè)置httpOnly屬性。

```javascript

var??info?=?{domain:?'secure.com',?path:?'/userInfo',secure:true};

response.cookie("cookieName",data,info)

```

修復(fù)建議

在發(fā)送cookie的時(shí)候應(yīng)該設(shè)置httpOnly屬性,

**例如**:

```javascript

var??info?=?{domain:?'secure.com',?path:?'/userInfo',secure:true,httpOnly:true};

response.cookie("cookieName",data,info)

```

中危:Cookie:未經(jīng)過(guò)SSL加密[Java]

使用未加密的網(wǎng)絡(luò)傳輸通道發(fā)送Cookie易受到網(wǎng)絡(luò)截取攻擊。創(chuàng)建Cookie時(shí),需要將secure標(biāo)記設(shè)置為true,表明瀏覽器必須通過(guò)HTTPS來(lái)加密傳輸Cookie。

**例如**:下面代碼片段中,將Cookie添加到HTTP響應(yīng)中時(shí),未設(shè)置secure標(biāo)記。

```java

...

Cookie?cookie?=?new?Cookie("SessionID",?sessionID);

response.addCookie(cookie);

...

```

修改建議

為Cookie添加secure標(biāo)記,要求瀏覽器通過(guò)HTTPS發(fā)送Cookie,這樣有助于保護(hù)Cookie值的保密性。

中危:硬編碼IP[NodeJS]

程序中采用硬編碼方式處理IP地址,一方面會(huì)降低系統(tǒng)安全性,另一方面不易于程序維護(hù)。

**例如**:下列代碼中采用硬編碼方式處理IP地址。

```javascript

var??ConnectionConfig?=?{

??????"url"?:?"42.81.56.36";

??????"name"?:?"admin";

??????"password"?:?"123456";

????...

}

```

修復(fù)建議

程序中不應(yīng)對(duì)IP地址進(jìn)行硬編碼,可以使用配置文件或數(shù)據(jù)庫(kù)存儲(chǔ)的方式來(lái)存儲(chǔ)系統(tǒng)所需的數(shù)據(jù);并且錄入數(shù)據(jù)時(shí),還可以做加密處理之后再進(jìn)行數(shù)據(jù)的錄入,從而防止敏感數(shù)據(jù)泄露。

**例如**:下列代碼中從配置文件中獲取經(jīng)過(guò)加密的IP地址并解密使用。

```javascript

var??ConnectionConfig?=?{

??????"url"?:?EncryptUtil.decrypt(PropertiesUtil.get("connection.url"));;

??????"name"?:?EncryptUtil.decrypt(PropertiesUtil.get("connection.username"));

??????"password"?:?EncryptUtil.decrypt(PropertiesUtil.get("connection.password"));

????...

}

```

中危:硬編碼手機(jī)號(hào)碼[NodeJS]

程序中采用硬編碼方式處理手機(jī)號(hào)碼,一方面會(huì)降低系統(tǒng)安全性,另一方面不易于程序維護(hù)。

**例如**:下面是某系統(tǒng)對(duì)用戶信息管理的源碼片段。

```javascript

var?emps?=?[

????{

????????"id":?"1001",

????????"name":?"周衛(wèi)國(guó)",

????????"age":?22,

????????"tel":?"18911295900",

????????"email":?"meiya@cn-meiya.com"

????},

????{

????????"id":?"1002",

????????"name":?"馬東強(qiáng)",

????????"age":?30,

????????"tel":?"18911295766",

????????"email":?"meiyahr@163.com"

????},

????{

????????"id":?"1003",

????????"name":?"黃毅",

????????"age":?27,

????????"tel":?"18911297366",

????????"email":?"chingpeplo@sina.com"

????}

]

```

在上面的源碼片段中,程序直接將用戶的手機(jī)號(hào)碼等個(gè)人信息以硬編碼的方式進(jìn)行存儲(chǔ),這樣做會(huì)讓數(shù)據(jù)與程序直接綁定,提高了系統(tǒng)的耦合性,使得系統(tǒng)和數(shù)據(jù)的維護(hù)變得困難。同時(shí),如果對(duì)程序的執(zhí)行文件做反編譯操作,很容易就能夠得到雇員的真實(shí)信息,導(dǎo)致敏感數(shù)據(jù)泄露,大大降低了系統(tǒng)的安全性。

修復(fù)建議

程序中不應(yīng)對(duì)手機(jī)號(hào)進(jìn)行硬編碼,可以使用配置文件或數(shù)據(jù)庫(kù)存儲(chǔ)的方式來(lái)存儲(chǔ)系統(tǒng)所需的數(shù)據(jù);并且錄入數(shù)據(jù)時(shí),還可以做加密處理之后再進(jìn)行數(shù)據(jù)的錄入,從而防止敏感數(shù)據(jù)泄露。

**例如**:下面代碼采用了從后端接口查詢手機(jī)號(hào)并解密。

```javascript

var?emps?=?[

????{

????????"id":?decrypt(getIdByUserId(1001)),

????????"name":?"周衛(wèi)國(guó)",

????????"age":?22,

????????"tel":??decrypt(getPhoneByUserId(1001)),

????????"email":??decrypt(getEmailByUserId(1001)),

????},

????{

???????"id":?decrypt(getIdByUserId(1002)),

????????"name":?"馬東強(qiáng)",

????????"age":?30,

????????"tel":??decrypt(getPhoneByUserId(1002)),

????????"email":??decrypt(getEmailByUserId(1001)),

????},

????{

????????"id":??decrypt(getIdByUserId(1003)),

????????"name":?"黃毅",

????????"age":?27,

????????"tel":??decrypt(getPhoneByUserId(1003)),

????????"email":??decrypt(getEmailByUserId(1001)),

????}

]

```

中危:硬編碼郵箱地址[Java]

程序中采用了硬編碼方式處理郵箱地址,一方面會(huì)降低系統(tǒng)安全性,另一方面不易于程序維護(hù)。

**例如**:下面代碼采用了硬編碼方式處理郵箱地址。

```java

public?class?UserDAO?{

????private?static?Map<Integer,?User>?users?=?new?LinkedHashMap<Integer,?User>();

????static?{

????????users.put(1001,?new?User(1001,?"周衛(wèi)國(guó)",?22,?"18911295900",?"meiya@cn-meiya.com"));

????????users.put(1002,?new?User(1002,?"馬東強(qiáng)",?30,?"18911295766",?"meiyahr@163.com"));

????????users.put(1003,?new?User(1003,?"黃毅",?27,?"18911297366",?"chingpeplo@sina.com"));

????????//?...

????}

????//?用戶信息的增刪改查方法

????//?...

}

public?class?User?{

????private?int?id;

????private?String?name;

????private?int?age;

????private?String?tel;

????private?String?email;

????public?User()?{}

????public?User(int?id,?String?name,?int?age,?String?tel,?String?email)?{

????????this.id?=?id;

????????this.name?=?name;

????????this.age?=?age;

????????this.tel?=?tel;

????????this.email?=?email;

????}

????//?Getter?and?Setter

????//?...

}

```

在上面的源碼片段中,程序直接將用戶的郵箱地址等個(gè)人信息以硬編碼的方式進(jìn)行存儲(chǔ),這樣做會(huì)讓數(shù)據(jù)與程序直接綁定,提高了系統(tǒng)的耦合性,使得系統(tǒng)和數(shù)據(jù)的維護(hù)變得困難。同時(shí),如果對(duì)程序的執(zhí)行文件做反編譯操作,很容易就能夠得到雇員的真實(shí)信息,導(dǎo)致敏感數(shù)據(jù)泄露,大大降低了系統(tǒng)的安全性。

修復(fù)建議

程序中不應(yīng)對(duì)郵箱地址進(jìn)行硬編碼,可以使用配置文件或數(shù)據(jù)庫(kù)存儲(chǔ)的方式來(lái)存儲(chǔ)系統(tǒng)所需的數(shù)據(jù);并且錄入數(shù)據(jù)時(shí),還可以在對(duì)敏感數(shù)據(jù)做加密處理之后再進(jìn)行數(shù)據(jù)的錄入。

**例如**:下面代碼采用了從數(shù)據(jù)庫(kù)查詢郵箱地址并解密。

```java

public?class?UserDAO?{

????private?static?Map<Integer,?User>?users?=?new?LinkedHashMap<Integer,?User>();

????static?{

????????users.put(1001,?new?User(1001,?"周衛(wèi)國(guó)",?22,?EncryptUtil.encrypt(phoneDAO.getPhoneById(1001)),?EncryptUtil.encrypt(emailDAO.getEmailById(1001))));

????????users.put(1002,?new?User(1002,?"馬東強(qiáng)",?30,?EncryptUtil.encrypt(phoneDAO.getPhoneById(1002)),?EncryptUtil.encrypt(emailDAO.getEmailById(1002))));

????????users.put(1003,?new?User(1003,?"黃毅",?27,?EncryptUtil.encrypt(phoneDAO.getPhoneById(1003)),?EncryptUtil.encrypt(emailDAO.getEmailById(1003))));

????????//?...

????}

????//?用戶信息的增刪改查方法

????//?...

}

public?class?User?{

????private?int?id;

????private?String?name;

????private?int?age;

????private?String?tel;

????private?String?email;

????public?User()?{}

????public?User(int?id,?String?name,?int?age,?String?tel,?String?email)?{

????????this.id?=?id;

????????this.name?=?name;

????????this.age?=?age;

????????this.tel?=?tel;

????????this.email?=?email;

????}

????//?Getter?and?Setter

????//?...

}

```

中危:請(qǐng)求參數(shù)自動(dòng)填充數(shù)據(jù)庫(kù)實(shí)體[Java]

持久性框架(如?Hibernate或JPA)通常會(huì)自動(dòng)更新數(shù)據(jù)庫(kù)實(shí)體,當(dāng)系統(tǒng)允許請(qǐng)求參數(shù)可以直接自動(dòng)填充數(shù)據(jù)庫(kù)持久實(shí)體時(shí),攻擊者將能夠通過(guò)提供附加的請(qǐng)求參數(shù)向數(shù)據(jù)庫(kù)中注入非預(yù)期的值。

**例如**:在下面的示例中:Order、User都是?Hibernate持久類。

```java

public?class?Order?{

????String?orderId;

????List?goods;

????User?User;

????...

}

public?class?User?{

????String?userId;

????String?username;

????String?password;

????...

}

```

OrderController是處理該請(qǐng)求的Spring控制器類:

```java

@Controller

public?class?OrderController?{

????...

????@RequestMapping("/updateOrder")

????public?String?updateOrder(Order?order)?{

????????...

????????session.save(order);

????}

}

```

當(dāng)系統(tǒng)允許請(qǐng)求自動(dòng)綁定到數(shù)據(jù)庫(kù)實(shí)體時(shí),攻擊者可以通過(guò)在該請(qǐng)求中添加如下請(qǐng)求參數(shù)來(lái)更新其他用戶的密碼:`https://www.shopwebsite.com/myOrder/updateOrder?order.user.userId=1234&order.user.password=newpassword`

修復(fù)建議

程序?qū)Ψ鞘苄诺挠脩糨斎霐?shù)據(jù)進(jìn)行凈化,不要直接填充給數(shù)據(jù)庫(kù)實(shí)體。

中危:非靜態(tài)內(nèi)部類實(shí)現(xiàn)序列化接口[Java]

非靜態(tài)內(nèi)部類(包括普通內(nèi)部類、Local內(nèi)部類和匿名內(nèi)部類)的實(shí)例持有一個(gè)外部類實(shí)例的隱式引用。非靜態(tài)內(nèi)部類實(shí)現(xiàn)序列化接口,當(dāng)其被序列化時(shí)會(huì)出現(xiàn)運(yùn)行時(shí)異常或泄露外部類中的信息。

下面代碼示例中:內(nèi)部類間接實(shí)現(xiàn)序列化接口

```java

public?class?SuperSer?implements?Serializable{

????//...

}

public?class?OuterSer{

????private?int?rank;

????class?InnerSer?extends?SuperSer{

????????protected?String?name;

????}

}

```

**例1**:下面代碼示例中:內(nèi)部類實(shí)現(xiàn)或間接實(shí)現(xiàn)序列化接口,外部類沒(méi)有實(shí)現(xiàn)序列化,當(dāng)內(nèi)部類被序列化時(shí),程序會(huì)報(bào)出NotSerializableException

```java

public?class?OuterSer{

????private?int?rank;

????class?InnerSer?implements?Serializable{

????????protected?String?name;

????}

}

```

修復(fù)建議

內(nèi)部類不要實(shí)現(xiàn)或間接實(shí)現(xiàn)Serializable接口,或?qū)?nèi)部類聲明為靜態(tài)的。

**例1**:下面代碼示例中:內(nèi)部類沒(méi)有實(shí)現(xiàn)序列化接口。

```java

public?class?OuterSer?implements?Serializable?{

????private?int?rank;

????class?InnerSer{

????????protected?String?name;

????}

}

```

**例2**:下面代碼示例中:將內(nèi)部類聲明為靜態(tài)內(nèi)部類。

```java

public?class?OuterSer?implements?Serializable?{

????private?int?rank;

????static?class?InnerSer?implements?Serializable{

????????protected?String?name;

????}

}

```

中危:使用==或!=比較基本數(shù)據(jù)類型的包裝類

不能直接使用`==`或`!=`操作符來(lái)比較的兩個(gè)基本數(shù)據(jù)類型的包裝類型的值,因?yàn)檫@些操作符比較的是對(duì)象的引用而不是對(duì)象的值。

不過(guò)由于Java的緩存機(jī)制,所以如果基本類型的包裝類是一個(gè)整數(shù)且在-128和127之間,或是布爾類型true或false,或者是'\u0000'和'\u007f'之間的字符文本,可以使用`==`或`!=`進(jìn)行比較。也就是說(shuō),如果使用了基本類型的包裝類型(除去Boolean或Byte),則會(huì)緩存或記住一個(gè)值區(qū)間。對(duì)于值區(qū)間內(nèi)的值,使用`==`或`!=`會(huì)返回正確的值,而對(duì)于值區(qū)間外的值,將返回對(duì)象地址的比較結(jié)果。

**例如**:在這個(gè)不符合規(guī)范的代碼示例中:使用`==`操作符來(lái)比較兩個(gè)Integer對(duì)象的值。然而,這個(gè)`==`操作比較的是對(duì)象的引用,而不是對(duì)象的值。

public class Wrapper {

????public static void main(String[] args){

????????Integer i1 = 100;

????????Integer i2 = 100;

????????Integer i3 = 1000;

????????Integer i4 = 1000;

????????System.out.println(i1 == i2);

????????System.out.println(i1 != i2);

????????System.out.println(i3 == i4);

????????System.out.println(i3 != i4);

????}

}

Integer類只能保證緩存介入-128~127的整型數(shù)值,當(dāng)使用相等操作符的時(shí)候,這會(huì)導(dǎo)致在這個(gè)范圍之外的等價(jià)數(shù)值的比較是不相等的。比如,在那些不緩存任何值的JVM虛擬機(jī)中,運(yùn)行程序會(huì)產(chǎn)生以下結(jié)果:

true

false

false

true

修復(fù)建議:

不能直接使用`==`或`!=`操作符來(lái)比較的兩個(gè)基本數(shù)據(jù)類型的包裝類的值,因?yàn)檫@些操作符比較的是對(duì)象的引用而不是對(duì)象的值。

符合規(guī)范的方案使用`equals()`而不是`==`操作符來(lái)比較兩個(gè)對(duì)象的值。這個(gè)程序在所有的平臺(tái)運(yùn)行時(shí)都會(huì)打印true、false、true、false的結(jié)果,這符合預(yù)期。

**例如**:以下代碼使用`equals()`方法比較兩個(gè)Integer對(duì)象的值。

public class Wrapper {

????public static void main(String[] args) {

????????Integer i1 = 100;

????????Integer i2 = 100;

????????Integer i3 = 1000;

????????Integer i4 = 1000;

????????System.out.println(i1.equals(i2));

????????System.out.println(!i1.equals(i2));

????????System.out.println(i3.equals(i4));

????????System.out.println(!i3.equals(i4));

????}

}

中危:比較Locale相關(guān)的數(shù)據(jù)未指定適當(dāng)?shù)腖ocale

在比較數(shù)據(jù)時(shí),如果可能與Locale設(shè)置相關(guān),則應(yīng)指定相應(yīng)的Locale。

**例1**:下面代碼示例中:使用了Locale相關(guān)的`String.toUpperCase()`將字符轉(zhuǎn)換為大寫(xiě)字符。在英文Locale中,會(huì)將`title`轉(zhuǎn)換為`TITLE`;在土耳其Locale中,會(huì)將`title`轉(zhuǎn)換為`T?TLE`,其中的`?`是拉丁字母的`I`。

"title".toUpperCase();

"TITLE".toLowerCase();

修復(fù)建議:

在比較數(shù)據(jù)時(shí),如果可能與Locale設(shè)置相關(guān),則應(yīng)指定相應(yīng)的Locale。

**例1**:下面代碼示例將Locale設(shè)置為英文,從而避免產(chǎn)生意外的問(wèn)題。

"title".toUpperCase(Locale.ENGLISH);

"TITLE".toLowerCase(Locale.ENGLISH);

**例2**:可以在對(duì)字符串處理前,將默認(rèn)的Locale設(shè)置為English。

Locale.setDefault(Locale.ENGLISH);

"title".toUpperCase();

"TITLE".toLowerCase();

中危:null引用

程序間接引用了可能為null的變量,從而引發(fā)空指針異常。

**例如**:下面代碼片段中,在使用變量data之前沒(méi)有判斷它是否為null。

Data data = null

data.setId(id);

修復(fù)建議:

程序在間接引用可能為null的對(duì)象之前應(yīng)對(duì)其進(jìn)行判斷。

**例如**:下面代碼片段中,程序data設(shè)置為null,使用之前進(jìn)行判斷是否為null。

Data ?data = null

if(data != null){

????data.setId(id);

}

中危:系統(tǒng)信息泄露:外部[Java]

系統(tǒng)數(shù)據(jù)或調(diào)試信息通過(guò)網(wǎng)絡(luò)流向遠(yuǎn)程機(jī)器時(shí),發(fā)生外部信息泄露。

**例如**:以下代碼泄露了HTTP響應(yīng)中的異常信息:

```java

protected?void?doGet(HttpServletRequest?req,?HttpServletResponse?res)?throws?IOException?{

????PrintWriter?out?=?res.getWriter();

????try?{

????????//...

????}?catch?(Exception?e)?{

????????out.println(e.getMessage());

????}

}

```

修復(fù)建議

程序不應(yīng)通過(guò)系統(tǒng)輸出流或程序日志將系統(tǒng)數(shù)據(jù)或調(diào)試信息輸出程序。

中危:系統(tǒng)信息泄露:Session傳遞

在localStorage和sessionStorage之間傳輸值會(huì)不知不覺(jué)地暴露敏感信息。

實(shí)現(xiàn)了Web Storage的HTML5瀏覽器提供了localStorage和sessionStorage兩個(gè)對(duì)象用于存儲(chǔ)數(shù)據(jù)。 localStorage和sessionStorage的區(qū)別在于存儲(chǔ)的作用域和有效期不同。兩者的作用域都限定在文檔源級(jí)別,sessionStorage還被限定在窗口中。localStorage存儲(chǔ)的數(shù)據(jù)是永久性的,除非Web應(yīng)用刻意刪除這些存儲(chǔ)的數(shù)據(jù),或者用戶通過(guò)瀏覽器配置來(lái)刪除,否則數(shù)據(jù)將一直存儲(chǔ)在用戶的電腦上。sessionStorage在當(dāng)前頁(yè)面實(shí)例和當(dāng)前瀏覽器會(huì)話期間為頁(yè)面提供存儲(chǔ),一旦窗口或者標(biāo)簽頁(yè)被永久關(guān)閉,所有通過(guò)sessionStorage存儲(chǔ)的數(shù)據(jù)會(huì)被刪除。將數(shù)據(jù)在localStorage和sessionStorage之間傳輸,會(huì)將瀏覽器生命周期以內(nèi)的數(shù)據(jù)和本地永久數(shù)據(jù)互相暴露。

**例如**:以下代碼中,為了免重復(fù)輸入,開(kāi)發(fā)人員將用戶的手機(jī)號(hào)存儲(chǔ)在sessionStorage對(duì)象中。但是,在存儲(chǔ)用戶信息到localStorage時(shí),又錯(cuò)誤的將手機(jī)號(hào)碼一并存了進(jìn)去。這樣將導(dǎo)致敏感信息被存儲(chǔ)到localStorage。

sessionStorage.setItem("phone", phone_number);

var userInfo = {};

var userInfo["phone"] = sessionStorage.getItem("phone");

localStorage.setItem("phone", userInfo);

修復(fù)建議:

不要將敏感數(shù)據(jù)存儲(chǔ)在localStorage和sessionStorage中。將數(shù)據(jù)從一種存儲(chǔ)格式遷移至另一種存儲(chǔ)格式時(shí),需要考慮遷移對(duì)于數(shù)據(jù)的隱私性和依賴該數(shù)據(jù)的業(yè)務(wù)邏輯的影響。

低危:JavaEE程序:直接使用線程

JAVA EE標(biāo)準(zhǔn)禁止在某些環(huán)境下使用Web應(yīng)用程序中的線程管理,因?yàn)榇藭r(shí)使用線程管理非常容易出錯(cuò)。線程管理起來(lái)很困難,可能還會(huì)以不可預(yù)知的方式干擾應(yīng)用程序容器。即使容器沒(méi)有受到干擾,線程管理通常還會(huì)導(dǎo)致各種難以發(fā)現(xiàn)的錯(cuò)誤,如死鎖、競(jìng)爭(zhēng)條件及其他同步錯(cuò)誤等。

**例如**:下面代碼片段中,在Servlet的`doGet()`方法中,直接創(chuàng)建了一個(gè)線程對(duì)象。

public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

????// Perform servlet tasks.

????// Create a new thread to handle background processing.

????Runnable r = new Runnable() {

????????public void run() {

????????// Process and store request statistics.

????????...

????????}

????};

????new Thread(r).start();

}

修復(fù)建議:

建議使用框架(如EJB、Spring等)提供的線程管理功能來(lái)替代直接使用操作線程。

低危:JavaEE程序:遺留的調(diào)試代碼

應(yīng)用程序中的測(cè)試代碼會(huì)建立一些意想不到的入口,這些入口可能會(huì)被攻擊者作為“后門”進(jìn)行利用

**例如**:JAVA EE程序中的`main()`方法。

public static void main(String[] args) {

...

}

修復(fù)建議:

系統(tǒng)在發(fā)布之前應(yīng)刪除測(cè)試代碼。

低危:日志記錄:使用系統(tǒng)輸出流

使用`System.out`或`System.err`進(jìn)行程序日志輸出,會(huì)導(dǎo)致程序的運(yùn)行狀況難以監(jiān)控。

**例如**:下列代碼中使用`System.out`進(jìn)行程序日志輸出

System.out.println(log);

修復(fù)建議:

建議使用日志記錄工具代替`System.out`或`System.err`記錄程序日志。

**例如**:下列代碼中使用Log4j工具類進(jìn)行程序日志輸出

logger.info(log);

低危:使用==或!=比較字符串

程序中使用`==`或`!=`比較兩個(gè)字符串是否相等,其實(shí)比較的是兩個(gè)對(duì)象在內(nèi)存中的地址值,而不是字符串的值。

**例如**:下面代碼片段中,將request中獲取的參數(shù)值與"admin"使用`==`做比較,`dosomething()`方法將永遠(yuǎn)不會(huì)被執(zhí)行。

String username = (String)request.getAttribute("usernamae");

if(username=="admin"){

????dosomething();

}

修復(fù)建議:

程序中應(yīng)采用`equals()`方法來(lái)對(duì)字符串進(jìn)行比較,而不是通過(guò)==或!=運(yùn)算符的方式來(lái)操作。

低危:硬編碼文件分隔符

路徑分割符號(hào)問(wèn)題,不同的操作系統(tǒng)不同。在程序中不要硬性編碼與平臺(tái)相關(guān)的任何常量,比如行分隔符,文件分隔符,路徑分隔符等等。例如文件分隔符,Windows系統(tǒng)使用"\"或"/",而UNIX系統(tǒng)則使用"/"。應(yīng)用程序需要在不同的平臺(tái)上運(yùn)行時(shí),使用硬編碼文件分隔符會(huì)導(dǎo)致應(yīng)用程序邏輯執(zhí)行錯(cuò)誤,并有可能導(dǎo)致拒絕服務(wù)。

**例如**:以下代碼使用硬編碼文件分隔符來(lái)打開(kāi)文件:

File file = new File(dirName + "\\" + fileName);

修復(fù)建議:

不應(yīng)使用硬編碼文件分隔符,而應(yīng)使用語(yǔ)言庫(kù)提供的獨(dú)立于平臺(tái)的API,如`java.io.File.separator`,也可以通過(guò)使用`java.lang.System.getProperty("file.separator")`來(lái)獲取。

**例如**:針對(duì)示例代碼的修改方法是:

File file = new File(dirName + File.separator + fileName);

低危:使用浮點(diǎn)數(shù)進(jìn)行精確計(jì)算

Java中浮點(diǎn)數(shù)采用的是IEEE 754標(biāo)準(zhǔn),所以在精確計(jì)算中使用浮點(diǎn)類型會(huì)發(fā)生精度缺失從而產(chǎn)生不正確的數(shù)值。

**例如**:下面代碼輸出為false和0.060000000000000005

public static void main(String[] args){

????double a = 0.05 + 0.01;

????System.out.println(a == 0.06);

????System.out.println(a);

}

修復(fù)建議:

程序中避免使用浮點(diǎn)數(shù)進(jìn)行精確計(jì)算,可以考慮采用整數(shù)類型或用于精確表達(dá)小數(shù)的BigDecimal類型替代。

低危:系統(tǒng)信息泄露:內(nèi)部

通過(guò)系統(tǒng)輸出流(非標(biāo)準(zhǔn)錯(cuò)誤流)打印或日志功能將系統(tǒng)數(shù)據(jù)或調(diào)試信息輸出到本地文件或屏幕時(shí),發(fā)生內(nèi)部信息泄露。

**例如**:下面代碼片段中,通過(guò)日志對(duì)象輸出異常的堆棧信息,攻擊者可能會(huì)利用這些堆棧信息制定相應(yīng)的攻擊計(jì)劃。

try{

????...

}catch(Exception e){

????logger.error("程序發(fā)生異常:", e);

}

修復(fù)建議:

程序不應(yīng)通過(guò)系統(tǒng)輸出流或程序日志將系統(tǒng)數(shù)據(jù)或調(diào)試信息輸出顯示。

低危:試圖重寫(xiě)靜態(tài)方法

靜態(tài)方法無(wú)法覆蓋,在子類中覆蓋父類的靜態(tài)方法,這樣容易產(chǎn)生混淆,從而導(dǎo)致錯(cuò)誤。

**例如**:下面代碼示例中:子類不能覆蓋父類的方法,`choose("user")`和`choose("admin")`都調(diào)用了父類中的方法。

class GrantAccess {

????public static void displayAccountStatus() {

????????System.out.println("Account details for admin: XX");

????}

}

class GrantUserAccess extends GrantAccess {

????public static void displayAccountStatus() {

????????System.out.println("Account details for user: XX");

????}

}

public class StatMethod {

????public static void choose(String username) {

????????GrantAccess admin = new GrantAccess();

????????GrantAccess user = new GrantUserAccess();

????????if (username.equals("admin")) {

????????????admin.displayAccountStatus();

????????} else {

????????????user.displayAccountStatus();

????????}

????}

????public static void main(String[] args) {

????????choose("user"); // Account details for admin: XX

????????choose("admin"); // Account details for admin: XX

????}

}

修復(fù)建議:

應(yīng)該盡量避免靜態(tài)方法的命名與超類中的命名相同,以避免產(chǎn)生混淆。在開(kāi)發(fā)中,可以將靜態(tài)方法放入單獨(dú)的final類中, 因?yàn)閒inal類不會(huì)創(chuàng)建子類,還可以創(chuàng)建私有的構(gòu)造函數(shù),以防止針對(duì)類的實(shí)例而非類來(lái)調(diào)用靜態(tài)方法。

**例如**:下面代碼示例中:去掉了static關(guān)鍵字,將`displayAccountStatus()`方法聲明為實(shí)例方法,`choose("user")`和`choose("admin")`調(diào)用實(shí)現(xiàn)了預(yù)期的程序邏輯。

class GrantAccess {

????public void displayAccountStatus() {

????????System.out.println("Account details for admin: XX");

????}

}

class GrantUserAccess extends GrantAccess {

????@Override

????public void displayAccountStatus() {

????????System.out.println("Account details for user: XX");

????}

}

public class StatMethod {

????public static void choose(String username) {

????????GrantAccess admin = new GrantAccess();

????????GrantAccess user = new GrantUserAccess();

????????if (username.equals("admin")) {

????????????admin.displayAccountStatus();

????????} else {

????????????user.displayAccountStatus();

????????}

????}

????public static void main(String[] args) {

????????choose("user"); // Account details for user: XX

????????choose("admin"); // Account details for admin: XX

????}

}

低危:系統(tǒng)信息泄露:標(biāo)準(zhǔn)錯(cuò)誤流

通過(guò)系統(tǒng)輸出流(標(biāo)準(zhǔn)錯(cuò)誤流)打印或日志功能將系統(tǒng)數(shù)據(jù)或調(diào)試信息輸出到本地文件或屏幕時(shí),在一些類似Eclipse的程序,為了讓錯(cuò)誤信息更加顯眼,會(huì)將錯(cuò)誤信息以紅色文本的形式通過(guò)System.err輸出到控制臺(tái)上,更容易發(fā)生內(nèi)部信息泄露。

**例如**:下面代碼片段中,`printStackTrace()`方法內(nèi)部使用了標(biāo)準(zhǔn)錯(cuò)誤流輸出異常的堆棧信息,攻擊者可能會(huì)利用這些堆棧信息制定相應(yīng)的攻擊計(jì)劃。

try{

????...

}catch(Exception e){

????e.printStackTrace();

}

修復(fù)建議:

程序不應(yīng)通過(guò)系統(tǒng)輸出流或程序日志將系統(tǒng)數(shù)據(jù)或調(diào)試信息輸出程序。

低危:泛化的捕獲異常

使用一個(gè)catch塊捕獲泛化的異常類(如Exception),可能會(huì)混淆那些需要特殊處理的異常,或是捕獲了不應(yīng)在該程序點(diǎn)捕獲的異常。捕獲范圍過(guò)大的異常與“Java的異常處理機(jī)制”是相違背的。

**例如**:下面的代碼片段中,程序捕獲了一個(gè)泛化的Exception異常。

try {

????doExchange();

} catch(Exception e){

????logger.error("doExchange failed", e);

}

修復(fù)建議:

不應(yīng)捕獲范圍過(guò)大的異常類,比如Exception、SystemException或ApplicationException,除非是級(jí)別非常高的程序或線程。

低危:泛化的拋出異常

Java語(yǔ)言通過(guò)面向?qū)ο蟮漠惓L幚頇C(jī)制來(lái)解決運(yùn)行期間的錯(cuò)誤,可以預(yù)防錯(cuò)誤的程序代碼或系統(tǒng)錯(cuò)誤所造成的不可預(yù)期的結(jié)果發(fā)生。減少編程人員的工作,增加了程序的靈活性,增加程序的可讀性和健壯性。如果程序只是拋出一個(gè)泛化的過(guò)于籠統(tǒng)的異常,不僅違反了該系統(tǒng)還會(huì)使調(diào)用者很難處理和修復(fù)發(fā)生的異常。

**例如**:下面代碼片段中,程序拋出了一個(gè)Exception異常,而不是具體的FileNotFoundException子類型異常,這樣使得調(diào)用者很難理解和處理可能發(fā)生的異常。

public void doExchange() throws Exception {

????FileInputStream fis = new FileInputStream("filename.txt");

}

修復(fù)建議:

不應(yīng)泛化的拋出Exception或Throwable類型的異常。

低危:表達(dá)式永遠(yuǎn)為false

表達(dá)式的計(jì)算結(jié)果永遠(yuǎn)為false,表明基于該表達(dá)式的代碼快將永遠(yuǎn)不會(huì)被執(zhí)行,是程序中的死代碼或用于調(diào)試的代碼,這些死代碼會(huì)增加代碼的閱讀、理解和維護(hù)難度,甚至該段代碼可能是調(diào)試過(guò)程中用來(lái)發(fā)現(xiàn)程序錯(cuò)誤的,這樣該代碼塊可能被攻擊者利用。

**例如**:下列代碼中,if的條件表達(dá)式為false,if代碼塊永遠(yuǎn)都不會(huì)被執(zhí)行。

if (false){

????//doSomething

}

修復(fù)建議:

程序異常中斷了預(yù)期中的程序流程,應(yīng)恰當(dāng)?shù)剡M(jìn)行異常處理,要么從異常中恢復(fù),將異常重新拋出,由下一個(gè)和try語(yǔ)句對(duì)應(yīng)的catch段來(lái)處理,要么根據(jù)catch程序段的上下文拋出另一個(gè)合適的異常。

低危:表達(dá)式永遠(yuǎn)為true

表達(dá)式的計(jì)算結(jié)果永遠(yuǎn)為true,表明程序中基于該表達(dá)式的段代碼永遠(yuǎn)被執(zhí)行,因此沒(méi)有必要進(jìn)行條件判斷。

**例如**:下列代碼中,if的條件表達(dá)式為true,if代碼塊將永遠(yuǎn)被執(zhí)行。

if (true){

????//doSomething

}

修復(fù)建議:

檢查程序邏輯,修改表達(dá)式判斷條件。

低危:未使用的字段

未使用的變量在程序中沒(méi)有起到任何作用,是程序中的死代碼或者是被注釋掉的調(diào)試代碼。這些死代碼會(huì)增加代碼的閱讀、理解和維護(hù)難度。

**例如**:如下代碼中MyClass類中的字段`userName`從未使用過(guò)

public class MyClass {

????private String userName="admin";

????public static void main(String[] args) {

????????System.out.println("UnusedField");

????}

}

修復(fù)建議:

檢查程序邏輯,如果確定程序中的死代碼沒(méi)有作用,應(yīng)該將其刪除。

低危:未使用的方法

未使用的方法在程序中沒(méi)有起到任何作用,是程序中的死代碼或者是被注釋掉的調(diào)試代碼。這些死代碼會(huì)增加代碼的閱讀、理解和維護(hù)難度。

**例如**:如下代碼中MyClass類中的`unusedMethod()`方法從未使用過(guò)

public class MyClass {

????private String unusedMethod(){

????????return "myclass";

????}

????public static void main(String[] args) {

????????System.out.println("UnusedMethod");

????}

}

修復(fù)建議:

檢查程序邏輯,如果確定程序中的死代碼沒(méi)有作用,應(yīng)該將其刪除。

低危:冗余的初始化

程序未使用變量的初始值,變量初始化后,被重新賦值或者轉(zhuǎn)向作用域之外。

**例如**:下列程序聲明一個(gè)變量`total`并賦值,后續(xù)并未使用所賦的值,再次賦值。

double total = getTotal();

total = getOtherTotal();

修復(fù)建議:

為了使代碼易于理解和維護(hù),刪除不必要的賦值。

低危:未使用的值

變量賦值后,程序未使用該變量。

**例如**:下列程序聲明一個(gè)字符串并賦值,后續(xù)一直未使用

String username = "張三";

修復(fù)建議:

為了使代碼易于理解和維護(hù),刪除不必要的賦值。

低危:冗余的null檢查

程序?qū)σ粋€(gè)引用的變量進(jìn)行了null檢查,但是在這之前,程序中已經(jīng)對(duì)該變量進(jìn)行了null檢查,或是對(duì)該變量進(jìn)行了一些可能會(huì)引發(fā)null異常的操作(取值、轉(zhuǎn)換)?;蛘叱绦?qū)ψ兞窟M(jìn)行了null檢查但是并未返回或者拋出異常,后續(xù)使用該變量仍然可能引發(fā)null異常。

**例1**:如下代碼先調(diào)用字符串string的`length()`方法,此時(shí)如果string如果為null就已經(jīng)會(huì)拋出空指針的異常,所以之后對(duì)string是否為null的判斷完全是多余的。

System.out.println(string.length());

if(string!=null){

????...

}

**例2**:如下代碼先對(duì)string進(jìn)行null校驗(yàn),但是并未返回或者拋出異常。后續(xù)繼續(xù)調(diào)用字符串string的`length()`方法,此時(shí)如果string如果為null就已經(jīng)會(huì)拋出空指針的異常,所以之前對(duì)string是否為null的判斷完全是多余的。

if(string == null){

????...

}

System.out.println(string.length());

修復(fù)建議:

檢查程序邏輯,刪除不必要的null檢查代碼。

低危:使用equals()來(lái)判斷字符串是否為空

程序中使用equals方法來(lái)判斷字符串是否為空,這樣會(huì)降低系統(tǒng)性能。

修復(fù)建議:

使用判斷字符串長(zhǎng)度的方法,判斷字符串是否為空,這樣會(huì)提升系統(tǒng)性能。

低危:循環(huán)中拼接字符串

字符串對(duì)象是不可改變的,拼接和修改字符串對(duì)象,最后都會(huì)創(chuàng)建一個(gè)新的字符串對(duì)象。而在循環(huán)中拼接字符串將會(huì)產(chǎn)生很多的對(duì)象,浪費(fèi)系統(tǒng)運(yùn)行時(shí)間和空間。

**例如**:在下面代碼片段中,在循環(huán)中拼接字符串。

String string = ""

for (int i < 0;i < 10;i++) {

????string = string + i;

}

在上面的循環(huán)中產(chǎn)生了10個(gè)StringBuilder對(duì)象,每次都會(huì)調(diào)用兩次`append`方法分別將string和i的值追加至StringBuilder對(duì)象中,最后調(diào)用toStirng方法將StringBuilder對(duì)象內(nèi)容轉(zhuǎn)化為字符串并賦值給string變量。

修復(fù)建議:

在循環(huán)語(yǔ)句結(jié)構(gòu)中,需要保證線程安全可以使用StringBuffer代替String進(jìn)行拼接,不需要時(shí)可以使用StringBuilder代替String進(jìn)行拼接。

**例如**:在下面代碼片段中,在循環(huán)中使用StringBuilder拼接字符串。

StringBuilder stringBuilder = new StringBuilder();

for (int i < 0;i < 10;i++) {

????stringBuilder.append(i);

}

String string = stringBuilder.toString();

低危:創(chuàng)建Boolean對(duì)象

程序中采用`new Boolean(boolean expression)`或`new Boolean(String expression)`創(chuàng)建對(duì)象,該方法產(chǎn)生的額外對(duì)象將占用更多空間、降低性能。

修復(fù)建議:

使用`Boolean.valueOf(boolean expression)`或`Boolean.valueOf(String expression)`或`Boolean.TRUE、Boolean.FALSE`代替`new Boolean`方法。

低危:byte數(shù)組轉(zhuǎn)String時(shí)未指定編碼

在將字節(jié)數(shù)組的數(shù)據(jù)轉(zhuǎn)換為String時(shí)如果未設(shè)定轉(zhuǎn)換編碼,可能會(huì)導(dǎo)致數(shù)據(jù)丟失。

**例如**:下面代碼片段中,將數(shù)據(jù)轉(zhuǎn)換為字符串,以便創(chuàng)建hash值。

byte[] byteArray = byte[BUFSIZE];

FileInputStream fileInputStream = new FileInputStream("fileName");

int count = fileInputStream.read(byteArray);

String fileString = new String(byteArray);

String fileSHA256Hex = DigestUtils.sha256Hex(fileString);

當(dāng)文件的大小小于字節(jié)數(shù)組容量SIZE時(shí),只要文件myFile中的信息已編碼為與默認(rèn)字符集相同,此方式正確。但是,如果使用不同的編碼方式,或者為二進(jìn)制文件,則信息將會(huì)丟失。進(jìn)而導(dǎo)致生成的SHA散列值的可靠性降低。

修復(fù)建議:

應(yīng)避免將可能包含非字符數(shù)據(jù)的byte數(shù)組轉(zhuǎn)換為String對(duì)象,如果必須將byte數(shù)組轉(zhuǎn)String,應(yīng)對(duì)其進(jìn)行編碼。

**例1**:下面代碼片段中,避免了將可能包含非字符數(shù)據(jù)的byte數(shù)組轉(zhuǎn)換為String對(duì)象。

byte[] byteArray = byte[BUFSIZE];

FileInputStream fileInputStream = new FileInputStream("fileName");

int count = fileInputStream.read(byteArr);

byte[] fileSHA256 = DigestUtils.sha256(byteArray);

**例2**:下面代碼片段中,byte數(shù)組轉(zhuǎn)String時(shí)指定了編碼。

byte[] byteArray = byte[BUFSIZE];

FileInputStream fileInputStream = new FileInputStream("fileName");

int count = fileInputStream.read(byteArray);

String fileString = new String(byteArray,"utf-8");

String fileSHA256Hex = DigestUtils.sha256Hex(fileString);

低危:侵犯隱私

程序?qū)γ舾行畔ⅲㄈ缬脩裘艽a或身份證號(hào)等個(gè)人信息)處理不當(dāng)可能導(dǎo)致用戶的個(gè)人信息泄露,這是一種非法行為。

**例如**:以下代碼可讀取存儲(chǔ)在Android WebView上的給定站點(diǎn)的用戶名和密碼,并廣播給所有注冊(cè)的接收者。

webView.setWebViewClient(new WebViewClient(){

????public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler httphandler, String url, String field) {

????????...

????????Intent intent = new Intent();

????????String[] credentials= view.getHttpAuthUsernamePassword(url, field);

????????String name = credentials[0];

????????String password = credentials[1];

????????intent.putExtra("username", name);

????????intent.putExtra("password", password);

????????intent.setAction("SEND_CREDENTIALS");

????????...

????????view.getContext().sendBroadcast(intent);

????}

});

修復(fù)建議:

當(dāng)安全和隱私的需要發(fā)生矛盾時(shí),通常應(yīng)優(yōu)先考慮隱私的需要。為滿足這一要求,同時(shí)又保證信息安全的需要,應(yīng)在退出程序前清除所有私人信息。

保護(hù)私人數(shù)據(jù)的最好做法就是最大程度地減少私人數(shù)據(jù)的暴露。不應(yīng)允許應(yīng)用程序、流程處理以及員工訪問(wèn)任何私人數(shù)據(jù),除非是出于職責(zé)以內(nèi)的工作需要。正如最小授權(quán)原則一樣,不應(yīng)該授予訪問(wèn)者超出其需求的權(quán)限,對(duì)私人數(shù)據(jù)的訪問(wèn)權(quán)限應(yīng)嚴(yán)格限制在盡可能小的范圍內(nèi)。

對(duì)于移動(dòng)應(yīng)用程序,請(qǐng)確保它們從不與在設(shè)備上運(yùn)行的其他應(yīng)用程序進(jìn)行任何敏感數(shù)據(jù)通信。存儲(chǔ)私人數(shù)據(jù)時(shí),通常都應(yīng)加密。對(duì)于Android以及其他任何使用SQLite數(shù)據(jù)庫(kù)的平臺(tái)來(lái)說(shuō),SQLCipher是一個(gè)好選擇——對(duì)SQLite數(shù)據(jù)庫(kù)的擴(kuò)展為數(shù)據(jù)庫(kù)文件提供了透明的256位AES加密。因此,憑證可以存儲(chǔ)在加密的數(shù)據(jù)庫(kù)中。

**例1**:以下代碼演示了在將所需的二進(jìn)制碼和存儲(chǔ)憑證下載到數(shù)據(jù)庫(kù)文件后,將SQLCipher集成到Android應(yīng)用程序中的方法。

import net.sqlcipher.database.SQLiteDatabase;

...

SQLiteDatabase.loadLibs(this);

File dbFile = getDatabasePath("credentials.db");

dbFile.mkdirs();

dbFile.delete();

SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(dbFile, "credentials", null);

db.execSQL("create table credentials(u, p)");

db.execSQL("insert into credentials(u, p) values(?, ?)", new Object[]{username, password});

請(qǐng)注意,對(duì)`android.database.sqlite.SQLiteDatabase`的引用可以使用`net.sqlcipher.database.SQLiteDatabase`代替。

要在WebView存儲(chǔ)上啟用加密,需要使用sqlcipher.so庫(kù)重新編譯WebKit。

**例2**:以下代碼從Android WebView存儲(chǔ)讀取給定站點(diǎn)的用戶名和密碼,而不是將其廣播到所有注冊(cè)的接收器,它僅在內(nèi)部廣播,以便廣播只能由同一應(yīng)用程序的其他部分看到。

webview.setWebViewClient(new WebViewClient() {

????public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) {

????????String[] credentials = view.getHttpAuthUsernamePassword(host, realm);

????????String username = credentials[0];

????????String password = credentials[1];

????????Intent i = new Intent();

????????i.setAction("SEND_CREDENTIALS");

????????i.putExtra("username", username);

????????i.putExtra("password", password);

????????LocalBroadcastManager.getInstance(view.getContext()).sendBroadcast(i);

????}

});

低危:switch語(yǔ)句中缺少default語(yǔ)句

程序中switch語(yǔ)句缺少default語(yǔ)句,而所有可能的變量值不一定都會(huì)被給定的case語(yǔ)句處理,導(dǎo)致一些情況未處理并產(chǎn)生問(wèn)題。

修復(fù)建議:

檢查程序邏輯,為switch語(yǔ)句添加所需的default語(yǔ)句

低危:可序列化類中存在可序列化的敏感信息

在可序列化類中存在敏感信息,當(dāng)對(duì)象被序列化時(shí),類中的敏感信息將會(huì)存儲(chǔ)。攻擊者可能會(huì)序列化該對(duì)象,并獲取敏感信息。

**例如**:下列代碼中類實(shí)現(xiàn)了序列化,且存在敏感信息`password`。攻擊者獲取該對(duì)象序列化的文件后,將會(huì)獲取此用戶密碼。

class Person implements Serializable{

????private String name;

????private String password;

????public Person(String name,String password) {

????????this.setName(name);

????????this.setPassword(password);

????}

????...

}

修復(fù)建議:

在存在敏感信息的可序列化類中,當(dāng)序列化對(duì)象時(shí),忽略,拒絕或者加密敏感信息。

**例1**:以下代碼敏感信息使用transient關(guān)鍵字修飾,將不會(huì)參與序列化過(guò)程:

class Person implements Serializable{

????private String name;

????private transient String password;

????public Person(String name,String password) {

????????this.setName(name);

????????this.setPassword(password);

????}

????...

}

**例2**:以下代碼將會(huì)在序列化時(shí)拒絕序列化:

class Person implements Serializable {

????private String name;

????private String password;

????public Person(String name,String password) {

????????this.setName(name);

????????this.setPassword(password);

????}

????...

????private final void writeObject(ObjectOutputStream out) throws IOException {

????????throw new NotSerializableException();

????}

????private final void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {

????????throw new NotSerializableException();

????}

????private final void readObjectNoData() throws ObjectStreamException {

????????throw new NotSerializableException();

????}

}

```

低危:空的方法

程序中存在空的方法。

修復(fù)建議:

檢測(cè)程序邏輯,是否存在未完成的代碼。

低危:空的代碼塊

程序中存在空的代碼塊。

**例如**:下面代碼片段中,程序中存在空的代碼塊,在程序中毫無(wú)意義。

public final class EmptyBlock{

????{

????????//空的代碼塊

????}

????...

????public void bad() {

????????{

????????????//空的代碼塊

????????}

????????...

????}

}

修復(fù)建議:

檢測(cè)程序邏輯,是否存在未完成的代碼。

低危:無(wú)用的分號(hào)

程序中存在無(wú)用的分號(hào)

修復(fù)建議:

檢測(cè)程序邏輯,是否需要?jiǎng)h除無(wú)用的分號(hào)。

低危:錯(cuò)誤的參數(shù)順序

調(diào)用方法時(shí),使用錯(cuò)誤的參數(shù)順序可能導(dǎo)致應(yīng)用程序以意想不到的方式運(yùn)行。

**例如**:下面代碼片段中,copy方法定義了src參數(shù)為第一個(gè),而dest為第二個(gè),最后調(diào)用時(shí)卻將dest作為第一個(gè)參數(shù)。

public static void main(String[] args) throws Exception {

????Object src = null;

????Object dest = null;

????...

????copy(dest, src);

}

public static void copy(Object src,Object dest) {

????...

}

修復(fù)建議:

檢查程序邏輯,正確的進(jìn)行方法調(diào)用,明確參數(shù)順序。

低危:空的if代碼塊

程序中存在空的if代碼塊,可能是程序員的邏輯出現(xiàn)問(wèn)題。

**例如**:

if(flag){}

修復(fù)建議:

檢測(cè)程序邏輯,是否存在未完成的代碼。

低危:隱藏的表單字段

隱藏字段是不安全的參數(shù),攻擊者能夠在一個(gè)post請(qǐng)求中改變隱藏字段的值。

**例如**:

<input type="hidden">

修復(fù)建議:

將隱藏字段視為不可信賴的輸入,不要在隱藏字段中存儲(chǔ)敏感信息。

低危:侵犯隱私:自動(dòng)補(bǔ)全

在啟用自動(dòng)補(bǔ)全功能的情況下,一些瀏覽器會(huì)在整個(gè)會(huì)話中保留用戶輸入,這將允許在初始化用戶之后使用計(jì)算機(jī)來(lái)查看先前提交的信息。

**例如**:

<form name="form02" action="" method="post" autocomplete="on">

????密碼: <input type="password" >

????<input type="submit" name="" value="提交" >

</form>

修復(fù)建議:

在使用HTML5時(shí)建議不要打開(kāi)autocomplete屬性。

**例1**:在表單中,將autocomplete的屬性值顯示設(shè)置為off,會(huì)禁用所有的input的自動(dòng)補(bǔ)全功能。

<form name="form02" action="" method="post" autocomplete="off">

????密碼: <input type="password" >

????<input type="submit" name="" value="提交" >

</form>

**例2**:或者在相應(yīng)的input標(biāo)簽上將autocomplete的屬性值顯示設(shè)置為off,禁用指定的input的自動(dòng)補(bǔ)全功能。

<form name="form02" action="" method="post">

????密碼: <input type="password" autocomplete="off">

????<input type="submit" name="" value="提交" >

</form>

低危:遺留的調(diào)試代碼

應(yīng)用程序中的測(cè)試代碼會(huì)建立一些意想不到的入口,這些入口可能會(huì)被攻擊者作為“后門”進(jìn)行利。有的測(cè)試代碼本身并不會(huì)帶來(lái)危害,但它表明了程序未進(jìn)行嚴(yán)格的清理,攻擊者很可能會(huì)查找到另外一些可利用的測(cè)試代碼。

**例如**:

console.log(message);

修復(fù)建議:

應(yīng)用程序在發(fā)布之前應(yīng)刪除測(cè)試代碼。

異常處理

低危:捕獲NullPointerException

應(yīng)用程序中不應(yīng)該捕獲`NullPointerException`或者任何它的基類。因?yàn)椴东@`NullPointerException`只可能掩蓋潛在的空引用,降低應(yīng)用性能,并造成難以理解和維護(hù)的代碼。

**例如**:如下代碼對(duì)空指針異常進(jìn)行了捕獲

String name=null;

try {

????name=request.getParameter("name");

????if(name.equals("admin")){

????????...

????}

} catch(NullPointerException e) { //程序捕獲NullPointerException

????...

}

修復(fù)建議:

檢查程序邏輯,刪除捕獲`NullPointerException`的代碼。

低危:finally代碼塊中拋出異常

在finally代碼塊中拋出異常時(shí)會(huì)消除從try或catch程序段拋出的任何異常,并影響后續(xù)代碼的執(zhí)行

**例如**:下面代碼中在finally代碼塊中拋出了異常

public static void doOperation throws IOException{

????FileInputStream fis = null;

????try{

????????fis = new FileInputStream("Reader.txt");

????????...

????} finally {

????????fis.close();

????????...

????}

}

當(dāng)Reader.txt不存在,且程序并未對(duì)異常進(jìn)行捕獲時(shí),程序只會(huì)拋出finally代碼塊中產(chǎn)生的`NullPointerException`,try代碼塊中產(chǎn)生的`FileNotFoundException`將不會(huì)顯示,后續(xù)代碼將不會(huì)執(zhí)行。

修復(fù)建議:

不應(yīng)在finally代碼塊中拋出異常,應(yīng)直接處理掉可能發(fā)生的異常

**例如**:下面代碼中在finally代碼塊中處理了異常,其后續(xù)代碼的執(zhí)行不會(huì)被影響

public static void doOperation throws IOException{

????FileInputStream fis = null;

????try{

????????fis = new FileInputStream("Reader.txt");

????????...

????} finally {

????????if(fis !=null) {

????????????try {

????????????????fis.close();

????????????} catch (IOException e) {

????????????...

????????}

????????...

????}

????...

}

低危:空的catch代碼塊(1)

忽略或消除程序異常會(huì)導(dǎo)致不一致的程序狀態(tài),**例如**:在try程序段中,不會(huì)執(zhí)行在異常拋出之后的表達(dá)式或語(yǔ)句。

**例如**:下面這段不符合規(guī)則的代碼示例捕獲并消除了`InterruptedException`。

class Foo implements Runnable{

????public void run(){

????????try{

????????????Thread.sleep(1000);

????????}catch(InterruptedException e){

????????????//Ignore

????????}

????}

}

上面程序中,妨礙了`run()`方法的調(diào)用者判斷是否發(fā)生一個(gè)中斷異常。

修復(fù)建議:

程序異常中斷了預(yù)期中的程序流程,應(yīng)恰當(dāng)?shù)剡M(jìn)行異常處理,要么從異常中恢復(fù),將異常重新拋出,由下一個(gè)和try語(yǔ)句對(duì)應(yīng)的catch段來(lái)處理,要么根據(jù)catch程序段的上下文拋出另一個(gè)合適的異常。

低危:空的catch代碼塊(2)

忽略或消除程序異常會(huì)導(dǎo)致不一致的程序狀態(tài),例如在try程序段中,不會(huì)執(zhí)行在異常拋出之后的表達(dá)式或語(yǔ)句。

**例如**:

try{

????var a = 1;

} catch(e){

}

修復(fù)建議:

程序異常中斷了預(yù)期中的程序流程,應(yīng)恰當(dāng)?shù)剡M(jìn)行異常處理,要么從異常中恢復(fù),將異常重新拋出,由下一個(gè)和try語(yǔ)句對(duì)應(yīng)的catch段來(lái)處理,要么根據(jù)catch程序段的上下文拋出另一個(gè)合適的異常。

跨站腳本

高危:反射型XSS[Java]

反射型XSS是指應(yīng)用程序通過(guò)Web請(qǐng)求獲取不可信賴的數(shù)據(jù),并在未檢驗(yàn)數(shù)據(jù)是否存在惡意代碼的情況下,將其發(fā)送給用戶。反射型XSS一般可以由攻擊者構(gòu)造帶有惡意代碼參數(shù)的URL來(lái)實(shí)現(xiàn),在構(gòu)造的URL地址被打開(kāi)后,其中包含的惡意代碼參數(shù)被瀏覽器解析和執(zhí)行。這種攻擊的特點(diǎn)是非持久化,必須用戶點(diǎn)擊包含惡意代碼參數(shù)的鏈接時(shí)才會(huì)觸發(fā)。

**例如**:下面JSP代碼片段的功能是從HTTP請(qǐng)求中讀取輸入的用戶名(username)并顯示到頁(yè)面。

```java

<%

String?name=?request.getParameter("username");?%>

...

姓名:?<%=?name%>

...

```

如果name里有包含惡意代碼,那么Web瀏覽器就會(huì)像顯示HTTP響應(yīng)那樣執(zhí)行該代碼,應(yīng)用程序?qū)⑹艿椒瓷湫蚗SS攻擊。

修復(fù)建議

為了避免反射型XSS攻擊,建議采用以下方式進(jìn)行防御:

1.對(duì)用戶的輸入進(jìn)行合理驗(yàn)證(如年齡只能是數(shù)字),對(duì)特殊字符(如`<、>、'、"`以及`<script>、javascript`等進(jìn)行過(guò)濾。

2.根據(jù)數(shù)據(jù)將要置于HTML上下文中的不同位置(HTML標(biāo)簽、HTML屬性、JavaScript腳本、CSS、URL),對(duì)所有不可信數(shù)據(jù)進(jìn)行恰當(dāng)?shù)妮敵鼍幋a。

?**例如**:采用OWASP?ESAPI對(duì)數(shù)據(jù)輸出HTML上下文中不同位置,編碼方法如下。

```java

//HTML?encode

ESAPI.encoder().encodeForHTML(inputData);

//HTML?attribute?encode

ESAPI.encoder().encodeForHTMLAttribute(inputData);

//JavaScript?encode

ESAPI.encoder().encodeForJavaScript(inputData);

//CSS?encode

ESAPI.encoder().encodeForCSS(inputData);

//URL?encode

ESAPI.encoder().encodeForURL(inputData);

```

3.設(shè)置HttpOnly屬性,避免攻擊者利用跨站腳本漏洞進(jìn)行Cookie劫持攻擊。在Java?EE中,給Cookie添加HttpOnly的代碼如下:

```java

...

response.setHeader("Set-Cookie","cookiename=cookievalue;?path=/;?Domain=domainvaule;?Max-age=seconds;?HttpOnly");

...

```

高危:存儲(chǔ)型XSS[Java]

存儲(chǔ)型XSS是指應(yīng)用程序通過(guò)Web請(qǐng)求獲取不可信賴的數(shù)據(jù),并且在未檢驗(yàn)數(shù)據(jù)是否存在XSS代碼的情況下,將其存入數(shù)據(jù)庫(kù)。當(dāng)程序下一次從數(shù)據(jù)庫(kù)中獲取該數(shù)據(jù)時(shí),致使頁(yè)面再次執(zhí)行XSS代碼。存儲(chǔ)型XSS可以持續(xù)攻擊用戶,在用戶提交了包含XSS代碼的數(shù)據(jù)存儲(chǔ)到數(shù)據(jù)庫(kù)后,每當(dāng)用戶在瀏覽網(wǎng)頁(yè)查詢對(duì)應(yīng)數(shù)據(jù)庫(kù)中的數(shù)據(jù)時(shí),那些包含XSS代碼的數(shù)據(jù)就會(huì)在服務(wù)器解析并加載,當(dāng)瀏覽器讀到XSS代碼后,會(huì)當(dāng)做正常的HTML和JS解析并執(zhí)行,于是發(fā)生存儲(chǔ)型XSS攻擊。

**例如**:下面JSP代碼片段的功能是根據(jù)一個(gè)已知用戶雇員ID(id)從數(shù)據(jù)庫(kù)中查詢出該用戶的地址,并顯示在JSP頁(yè)面上。

```java

<%

...

Statement?stmt?=?conn.createStatement();

ResultSet?rs?=?stmt.executeQuery("select?*?from?users?where?id?="?+?id);

String?address?=?null;

if?(rs?!=?null)?{

????rs.next();

????address?=?rs.getString("address");

}

%>

家庭地址:?<%=?address?%>

```

如果address的值是由用戶提供的,且存入數(shù)據(jù)庫(kù)時(shí)沒(méi)有進(jìn)行合理的校驗(yàn),那么攻擊者就可以利用上面的代碼進(jìn)行存儲(chǔ)型XSS攻擊。

修復(fù)建議

為了避免存儲(chǔ)型XSS攻擊,建議采用以下方式進(jìn)行防御:

1.對(duì)從數(shù)據(jù)庫(kù)或其它后端數(shù)據(jù)存儲(chǔ)獲取不可信賴的數(shù)據(jù)進(jìn)行合理驗(yàn)證(如年齡只能是數(shù)字),對(duì)特殊字符(如`<、>、'、"`以及`<script>、javascript`等進(jìn)行過(guò)濾。

2.根據(jù)數(shù)據(jù)將要置于HTML上下文中的不同位置(HTML標(biāo)簽、HTML屬性、JavaScript腳本、CSS、URL),對(duì)所有不可信數(shù)據(jù)進(jìn)行恰當(dāng)?shù)妮敵鼍幋a。

**例如**:采用OWASP?ESAPI對(duì)數(shù)據(jù)輸出HTML上下文中不同位置,編碼方法如下。

```java

//HTML?encode

ESAPI.encoder().encodeForHTML(inputData);

//HTML?attribute?encode

ESAPI.encoder().encodeForHTMLAttribute(inputData);

//JavaScript?encode

ESAPI.encoder().encodeForJavaScript(inputData);

//CSS?encode

ESAPI.encoder().encodeForCSS(inputData);

//URL?encode

ESAPI.encoder().encodeForURL(inputData);

```

3.設(shè)置HttpOnly屬性,避免攻擊者利用跨站腳本漏洞進(jìn)行Cookie劫持攻擊。在Java?EE中,給Cookie添加HttpOnly的代碼如下:

```java

...

response.setHeader("Set-Cookie","cookiename=cookievalue;?path=/;?Domain=domainvaule;?Max-age=seconds;?HttpOnly");

...

```

低危:跨站請(qǐng)求偽造

跨站請(qǐng)求偽造(CSRF)是偽造客戶端請(qǐng)求的一種攻擊。應(yīng)用程序允許用戶提交不包含任何nonce(與用戶Session關(guān)聯(lián)的加密隨機(jī)值)的請(qǐng)求,將可能導(dǎo)致CSRF攻擊。

**例如**:以下代碼片段用于銀行轉(zhuǎn)賬功能,對(duì)于該重要敏感的操作沒(méi)有進(jìn)行相應(yīng)防護(hù),將易于導(dǎo)致跨站請(qǐng)求偽造攻擊。

var req = new XMLHttpRequest();

req.open("POST", "/transferFunds", true);

body = "to_account=Bill&amount=10000";

req.send(body);

**例2**:下面是通過(guò)表單發(fā)送請(qǐng)求。

<form method="GET" action="/transferFunds ">

????cash: <input type="text" name="cash">

????to: <input type=" text " name=“to">

????<input type="submit" name="action" value="TransferFunds">

</form>

修復(fù)建議:

防止跨站請(qǐng)求偽造攻擊的方法如下:

防御策略

1、驗(yàn)證HTTP Refer字段

2、在請(qǐng)求地址中添加token驗(yàn)證

3、在http頭中自定義屬性并驗(yàn)證

4、Chrome瀏覽器端啟用 SameSite cookie

防御手段

1、盡量使用POST, 限制GET

2、調(diào)整瀏覽器Cookie策略

3、加驗(yàn)證碼,強(qiáng)制用戶必須與應(yīng)用進(jìn)行交互,才能完成最終請(qǐng)求。在通常情況下,驗(yàn)證碼能很好遏制CSRF攻擊。但是出于用戶體驗(yàn)考慮,網(wǎng)站不能給所有的操作都加上驗(yàn)證碼。因此驗(yàn)證碼只能作為一種輔助手段,不能作為主要解決方案

4、Referer Check在Web最常見(jiàn)的應(yīng)用就是“防止圖片盜鏈”。

同理,Referer Check也可以被用于檢查請(qǐng)求是否來(lái)自合法的“源”(Referer值是否是指定頁(yè)面,或者網(wǎng)站的域),如果都不是,那么就可能是CSRF攻擊

5、Anti CSRF token 業(yè)界推薦

Anti CSRF token

1、用戶訪問(wèn)某個(gè)表單頁(yè)面。

2、服務(wù)端生成一個(gè)Token,放在用戶的Session中,或者瀏覽器的Cookie中。

3、在頁(yè)面表單附帶上Token參數(shù)。

4、用戶提交請(qǐng)求后, 服務(wù)端驗(yàn)證表單中的Token是否與用戶Session(或Cookies)中的Token一致,一致為合法請(qǐng)求,不是則非法請(qǐng)求。

這個(gè)Token的值必須是隨機(jī)的,不可預(yù)測(cè)的。由于Token的存在,攻擊者無(wú)法再構(gòu)造一個(gè)帶有合法Token的請(qǐng)求實(shí)施CSRF攻擊。

另外使用Token時(shí)應(yīng)注意Token的保密性,盡量把敏感操作由GET改為POST,以form或AJAX形式提交,避免Token泄露。

**例如**:下面代碼片段中,在表單中增加了一個(gè)Token。

req.open("POST", "/transferFunds", true);

body = "to_account=Bill&amount=10000&token=" + token;

//token為與會(huì)話相關(guān)的一次性隨機(jī)數(shù)。

req.send(body);

這樣,服務(wù)器端程序響應(yīng)用戶請(qǐng)求前先驗(yàn)證Token,判斷請(qǐng)求的合法性。對(duì)于Token,越難被猜出攻擊者攻擊成功的概率就越低。

配置管理

中危:JavaEE配置錯(cuò)誤:特定HTTP方法[Java]

Web應(yīng)用程序指定?HTTP方法的安全限制可能得不到預(yù)期的效果,攻擊者可以通過(guò)篡改HTTP命令來(lái)繞過(guò)應(yīng)用程序的安全限制。

**例如**:下面配置文件片段中,?以下安全限制可應(yīng)用于?HTTP?GET方法,但不能應(yīng)用于其他?HTTP?命令:

```xml

...

<security-constraint>

????<web-resource-collection>

????????<web-resource-name>Protected?Area</web-resource-name>

????????<url-pattern>/myWeb/create</url-pattern>

????????<http-method>GET</http-method>

????</web-resource-collection>

????<auth-constraint>

????????<role-name>Create</role-name>

????</auth-constraint>

</security-constraint>

...

```

修復(fù)建議

Web應(yīng)用程序應(yīng)該在web.xml中不要指定?HTTP方法的安全限制,防止攻擊者篡改HTTP命令來(lái)繞過(guò)應(yīng)用程序的安全限制。

**例如**:下面配置文件片段中,以下安全限制將應(yīng)用于所有HTTP方法。

```xml

...

<security-constraint>

????<web-resource-collection>

????????<web-resource-name>Protected?Area</web-resource-name>

????????<url-pattern>/myWeb/create</url-pattern>

????</web-resource-collection>

????<auth-constraint>

????????<role-name>Create</role-name>

????</auth-constraint>

</security-constraint>

...

```

參考鏈接:https://blog.csdn.net/qq_39560975/article/details/131956264

高等級(jí)缺陷

代碼質(zhì)量:郵件服務(wù)器建立未加密的連接

代碼注入:XML外部實(shí)體注入

代碼注入:動(dòng)態(tài)解析代碼

跨站腳本:存儲(chǔ)型XSS

跨站腳本:反射型XSS

輸入驗(yàn)證:基于DOM的XSS

輸入驗(yàn)證:路徑遍歷

輸入驗(yàn)證:重定向

輸入驗(yàn)證:重定向

中等級(jí)缺陷

API誤用:不安全的框架綁定

API誤用:依賴未經(jīng)驗(yàn)證和完整性檢查的cookie

代碼質(zhì)量:Cookie:未經(jīng)過(guò)SSL加密

代碼質(zhì)量:null引用

代碼質(zhì)量:webpack源碼泄露

代碼質(zhì)量:比較Locale相關(guān)的數(shù)據(jù)未指定適當(dāng)?shù)腖ocale

代碼質(zhì)量:不安全的信息傳輸

代碼質(zhì)量:非靜態(tài)內(nèi)部類實(shí)現(xiàn)序列化接口

代碼質(zhì)量:請(qǐng)求參數(shù)自動(dòng)填充數(shù)據(jù)庫(kù)實(shí)體

代碼質(zhì)量:未設(shè)置httpOnly

代碼質(zhì)量:系統(tǒng)信息泄露:Session傳遞

代碼質(zhì)量:系統(tǒng)信息泄露:外部

代碼質(zhì)量:硬編碼IP

代碼質(zhì)量:硬編碼手機(jī)號(hào)碼

代碼質(zhì)量:硬編碼郵箱地址

代碼注入:HTTP響應(yīng)截?cái)?/p>

代碼注入:HTTP響應(yīng)截?cái)啵篊ookies

代碼注入:JavaScript劫持

代碼注入:XML實(shí)體擴(kuò)展注入

代碼注入:同源方法執(zhí)行

代碼注入:資源注入

密碼管理:不安全的隨機(jī)數(shù)

密碼管理:配置文件中的明文密碼

密碼管理:硬編碼密碼

配置管理:JavaEE配置錯(cuò)誤:特定HTTP方法

輸入驗(yàn)證:HTTP參數(shù)污染

輸入驗(yàn)證:服務(wù)器端請(qǐng)求偽造

輸入驗(yàn)證:拒絕服務(wù):正則表達(dá)式

輸入驗(yàn)證:路徑遍歷:ZIP條目覆蓋

輸入驗(yàn)證:日志偽造

輸入驗(yàn)證:文件上傳

資源管理:?jiǎn)卫蓡T變量

資源管理:反射型文件下載

資源管理:格式化缺陷

資源管理:路徑訪問(wèn)控制

資源管理:使用不安全的targetblank

資源管理:數(shù)據(jù)庫(kù)訪問(wèn)控制

資源管理:資源未釋放:Sockets

資源管理:資源未釋放:流

低等級(jí)缺陷

API誤用:忽略返回值

API誤用:缺少對(duì)方法返回值的null檢查

API誤用:使用不必要的線程安全類

API誤用:誤用String.toString()

代碼質(zhì)量:byte數(shù)組轉(zhuǎn)String時(shí)未指定編碼

代碼質(zhì)量:Cookie:持久

代碼質(zhì)量:Cookie:未經(jīng)過(guò)SSL加密

代碼質(zhì)量:HTML中包含硬編碼域名

代碼質(zhì)量:img中缺少alt屬性

代碼質(zhì)量:JavaEE程序:遺留的調(diào)試代碼

代碼質(zhì)量:switch語(yǔ)句中缺少default語(yǔ)句

代碼質(zhì)量:switch語(yǔ)句中缺少返回語(yǔ)句

代碼質(zhì)量:變量和方法同名

代碼質(zhì)量:表達(dá)式永遠(yuǎn)為false

代碼質(zhì)量:表達(dá)式永遠(yuǎn)為true

代碼質(zhì)量:不應(yīng)重復(fù)編譯相同的正則表達(dá)式

代碼質(zhì)量:創(chuàng)建String對(duì)象

代碼質(zhì)量:方法返回參數(shù)類型為泛型通配符類型

代碼質(zhì)量:浮點(diǎn)數(shù)的字符串比較

代碼質(zhì)量:構(gòu)造方法中調(diào)用可覆寫(xiě)的方法

代碼質(zhì)量:過(guò)于寬松的CORS策略

代碼質(zhì)量:可序列化類中存在可序列化的敏感信息

代碼質(zhì)量:空的if代碼塊

代碼質(zhì)量:空的if代碼塊

代碼質(zhì)量:空的方法

代碼質(zhì)量:列表標(biāo)簽誤用

代碼質(zhì)量:沒(méi)有使用正則表達(dá)式時(shí)應(yīng)該使用replace方法而不是replaceAll方法

代碼質(zhì)量:侵犯隱私

代碼質(zhì)量:侵犯隱私:String對(duì)象

代碼質(zhì)量:侵犯隱私:自動(dòng)補(bǔ)全

代碼質(zhì)量:日志記錄:非staticfinal的日志對(duì)象

代碼質(zhì)量:日志記錄:使用系統(tǒng)輸出流

代碼質(zhì)量:冗余的null檢查

代碼質(zhì)量:冗余的初始化

代碼質(zhì)量:使用==或!=比較字符串

代碼質(zhì)量:使用equals()來(lái)判斷字符串是否為空

代碼質(zhì)量:使用單個(gè)字符字符串獲取索引位置

代碼質(zhì)量:使用已過(guò)時(shí)的屬性或標(biāo)簽

代碼質(zhì)量:未使用的值

代碼質(zhì)量:未使用的字段

代碼質(zhì)量:無(wú)用的分號(hào)

代碼質(zhì)量:系統(tǒng)信息泄露:Debug日志程序

代碼質(zhì)量:系統(tǒng)信息泄露:標(biāo)準(zhǔn)錯(cuò)誤流

代碼質(zhì)量:系統(tǒng)信息泄露:過(guò)于寬泛的Debug日志記錄

代碼質(zhì)量:系統(tǒng)信息泄露:內(nèi)部

代碼質(zhì)量:循環(huán)中拼接字符串

代碼質(zhì)量:遺留的調(diào)試代碼

代碼質(zhì)量:隱藏的表單字段

代碼質(zhì)量:硬編碼URL地址

代碼質(zhì)量:硬編碼文件分隔符

代碼質(zhì)量:注釋中的銀行卡號(hào)

代碼質(zhì)量:注釋中的郵箱

代碼注入:JavaScript劫持:易受攻擊的框架

代碼注入:JSON注入

代碼注入:有風(fēng)險(xiǎn)的SQL查詢:Hibernate

跨站腳本:跨站請(qǐng)求偽造

密碼管理:不安全的哈希算法

密碼管理:不安全的哈希算法

密碼管理:不安全的隨機(jī)數(shù)

密碼管理:明文密碼

密碼管理:硬編碼加密密鑰

密碼管理:注釋中的密碼

配置管理:構(gòu)建配置錯(cuò)誤:Maven倉(cāng)庫(kù)外部依賴

輸入驗(yàn)證:操縱設(shè)置

輸入驗(yàn)證:拒絕服務(wù):StringBuilder

輸入驗(yàn)證:拒絕服務(wù):解析Double類型數(shù)據(jù)

輸入驗(yàn)證:數(shù)據(jù)跨越信任邊界

輸入驗(yàn)證:文件上傳

輸入驗(yàn)證:有風(fēng)險(xiǎn)的資源使用

異常處理:泛化的捕獲異常

異常處理:泛化的拋出異常

異常處理:空的catch代碼塊

異常處理:空的catch代碼塊

資源管理:有風(fēng)險(xiǎn)的數(shù)據(jù)庫(kù)訪問(wèn)控制

基于參考文檔進(jìn)行的補(bǔ)充

參考文檔:

JAVA Web應(yīng)用常見(jiàn)漏洞與修復(fù)建議_輸入驗(yàn)證:直接綁定敏感字段-CSDN博客文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-794450.html

到了這里,關(guān)于Java代碼漏洞檢測(cè)-常見(jiàn)漏洞與修復(fù)建議的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Java 超高頻常見(jiàn)字符操作【建議收藏】

    前些天發(fā)現(xiàn)了一個(gè)巨牛的人工智能學(xué)習(xí)網(wǎng)站,通俗易懂,風(fēng)趣幽默,忍不住分享一下給大家?!緦毑厝肟凇?。 為了鞏固所學(xué)的知識(shí),作者嘗試著開(kāi)始發(fā)布一些學(xué)習(xí)筆記類的博客,方便日后回顧。當(dāng)然,如果能幫到一些萌新進(jìn)行新技術(shù)的學(xué)習(xí)那也是極好的。作者菜菜一枚,文章

    2024年02月08日
    瀏覽(17)
  • 【網(wǎng)安AIGC專題10.19】論文6:Java漏洞自動(dòng)修復(fù)+數(shù)據(jù)集 VJBench+大語(yǔ)言模型、APR技術(shù)+代碼轉(zhuǎn)換方法+LLM和DL-APR模型的挑戰(zhàn)與機(jī)會(huì)

    【網(wǎng)安AIGC專題10.19】論文6:Java漏洞自動(dòng)修復(fù)+數(shù)據(jù)集 VJBench+大語(yǔ)言模型、APR技術(shù)+代碼轉(zhuǎn)換方法+LLM和DL-APR模型的挑戰(zhàn)與機(jī)會(huì)

    本文為 鄒德清教授的《網(wǎng)絡(luò)安全專題》課堂筆記系列 的文章,本次專題主題為大模型。 ISSTA 2023 How Effective Are Neural Networks for Fixing Security Vulnerabilities 評(píng)測(cè)現(xiàn)有的大模型和基于深度學(xué)習(xí)的自動(dòng)補(bǔ)丁修復(fù)模型對(duì) Java漏洞修復(fù) 能力的工作 論文很長(zhǎng)很系統(tǒng),學(xué)姐讀的很細(xì)節(jié)很深入

    2024年02月08日
    瀏覽(98)
  • Java配置47-Spring Eureka 未授權(quán)訪問(wèn)漏洞修復(fù)

    Java配置47-Spring Eureka 未授權(quán)訪問(wèn)漏洞修復(fù)

    項(xiàng)目組使用的 Spring Boot 比較老,是 1.5.4.RELEASE 。最近被檢測(cè)出 Spring Eureka 未授權(quán)訪問(wèn)漏洞。 現(xiàn)狀是瀏覽器直接訪問(wèn) Eureka Server 可以直接進(jìn)去,看到已經(jīng)注冊(cè)的服務(wù)信息。 2.1 Eureka Server 添加安全組件 Eureka Server 添加 pom 依賴: 2.2 Eureka Server 添加參數(shù) 2.3 重啟 Eureka Server 重啟

    2024年02月05日
    瀏覽(27)
  • Linux Polkit本地權(quán)限提升漏洞(CVE-2021-4034)的修復(fù)方式建議

    Linux Polkit本地權(quán)限提升漏洞(CVE-2021-4034)的修復(fù)方式建議

    近日,網(wǎng)絡(luò)上出現(xiàn) Linux 下 Polkit 工具集的本地權(quán)限提升漏洞,任何非特權(quán)本地用戶可通過(guò)此漏洞獲取root權(quán)限。目前該漏洞PoC已公開(kāi)。 漏洞描述 Polkit 是用于在類 Unix 操作系統(tǒng)中控制系統(tǒng)范圍特權(quán)的組件。它為非特權(quán)進(jìn)程提供了與特權(quán)進(jìn)程進(jìn)行通信的有組織的方式。 CVE-2021-4

    2024年02月10日
    瀏覽(36)
  • 常見(jiàn)漏洞修復(fù)方案

    【漏洞描述】 由于服務(wù)器中間件配置不當(dāng),客戶端可以直接訪問(wèn)站點(diǎn)文件目錄。如目錄中恰好存在敏感文件(如配置文件、備份文件、數(shù)據(jù)庫(kù)文件等),可被直接下載,導(dǎo)致嚴(yán)重的敏感信息泄露。 【漏洞危害】 黑客可獲得服務(wù)器上的文件目錄結(jié)構(gòu),從而下載敏感文件,為后

    2024年02月09日
    瀏覽(16)
  • [Java安全]—weblogic常見(jiàn)漏洞

    [Java安全]—weblogic常見(jiàn)漏洞

    本來(lái)想跟一些T3反序列化的,奈何本地環(huán)境怎么都起不起來(lái)先復(fù)現(xiàn)一下常見(jiàn)漏洞吧。。。 Weblogic是美國(guó)Oracle公司出品的一個(gè)應(yīng)用服務(wù)器(application server),確切的說(shuō)是一個(gè)基于Java EE架構(gòu)的中間件,是用于開(kāi)發(fā)、集成、部署和管理大型分布式Web應(yīng)用、網(wǎng)絡(luò)應(yīng)用和 數(shù)據(jù)庫(kù)應(yīng)用的Jav

    2024年02月06日
    瀏覽(19)
  • SonarQube掃描常見(jiàn)Bug、漏洞修復(fù)整理(持續(xù)更新中)

    SonarQube掃描常見(jiàn)Bug、漏洞修復(fù)整理(持續(xù)更新中)

    這種提示是指可能存在空指針異常,需要增加空值檢測(cè)。 說(shuō)明:未做非空校驗(yàn),可能產(chǎn)生空指針 解決方案:加上非空校驗(yàn) 解決方式:先判斷或者先實(shí)例化,再訪問(wèn)里面的屬性或者成員。 說(shuō)明:int數(shù)運(yùn)算最終再把結(jié)果轉(zhuǎn)為long將有可能產(chǎn)生溢出 說(shuō)明:防止內(nèi)存泄露溢出,Thr

    2024年02月15日
    瀏覽(22)
  • 【網(wǎng)安】處理項(xiàng)目中的一些常見(jiàn)漏洞bug(java相關(guān))

    【網(wǎng)安】處理項(xiàng)目中的一些常見(jiàn)漏洞bug(java相關(guān))

    [福利:[ 網(wǎng)絡(luò)安全重磅福利:入門進(jìn)階全套282G學(xué)習(xí)資源包免費(fèi)分享 !]](網(wǎng)絡(luò)安全重磅福利:入門進(jìn)階全套282G學(xué)習(xí)資源包免費(fèi)分享! ) 1.寫(xiě)在前面 很多時(shí)候,一些項(xiàng)目,或許都會(huì)有一定的系統(tǒng)安全要求。一般常見(jiàn)于政府項(xiàng)目比較多?。?! 項(xiàng)目做完后,都需要做一些安全的掃

    2024年02月13日
    瀏覽(11)
  • 漏洞修復(fù)-檢測(cè)到目標(biāo)URL存在http host頭攻擊漏洞

    漏洞修復(fù)-檢測(cè)到目標(biāo)URL存在http host頭攻擊漏洞

    這個(gè)漏洞通常表示目標(biāo)URL會(huì)被截取,攻擊者可以通過(guò)修改請(qǐng)求頭中的”host”屬性,導(dǎo)致最后導(dǎo)向的目標(biāo)主機(jī)被篡改。漏洞說(shuō)明如下: ModHeader它可以用來(lái)偽造HTTP請(qǐng)求頭,包含覆蓋Chrome瀏覽器請(qǐng)求頭的默認(rèn)值??稍贑hrome拓展程序中搜索安裝。 訪問(wèn)網(wǎng)站,頁(yè)面正常 2.通過(guò)ModHeade

    2024年02月06日
    瀏覽(20)
  • 【教程】一些服務(wù)器常見(jiàn)漏洞的修復(fù)方法,親測(cè)超詳細(xì)

    【教程】一些服務(wù)器常見(jiàn)漏洞的修復(fù)方法,親測(cè)超詳細(xì)

    目錄 漏洞名稱解釋 Apache漏洞——卸載Apache2(可能不適用于大家) CVE-2020-15778——禁用SCP CVE-2020-15778、CVE-2016-2183、CVE-2021-41617、CVE-2014-0160、CVE-2020-12062、CVE-2021-28041、CVE-2016-6515——升級(jí)openssl和openssh 安裝編譯環(huán)境所需的工具 然后編譯升級(jí)openssl 之后編譯升級(jí)openssh CVE-2018-1905

    2024年02月08日
    瀏覽(48)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包