安裝sonar并配置
docker安裝sonarqube,sonarQube靜態代碼掃描 - Joson6350 - 博客園 (cnblogs.com)
對webgoat進行sonar掃描
掃描結果?
bugs?
Change this condition so that it does not always evaluate to "false"
意思是這里的else if語句不會執行,因為ipAddressKnow為true,所以if 和else if的條件結果是一樣的。
?Use try-with-resources or close this "PreparedStatement" in a "finally" clause.
提示資源沒有關閉,需要在finally中進行資源關閉,但是把資源關閉放到finally中由提示這樣寫不規范有異味。所以它推薦的寫法是將創建資源流的代碼放在try()中,這樣系統會自動的關閉資源,不需要我們寫.close()方法
try-with-resources
Java 異常處理 | 菜鳥教程 (runoob.com)
JDK7 之后,Java 新增的?try-with-resource?語法糖來打開資源,并且可以在語句執行完畢后確保每個資源都被自動關閉 。
try-with-resources 是一種異常處理機制,它可以簡化資源管理代碼的編寫。
JDK7 之前所有被打開的系統資源,比如流、文件或者 Socket 連接等,都需要被開發者手動關閉,否則將會造成資源泄露。
try (resource declaration) {// 使用的資源 } catch (ExceptionType e1) {// 異常塊 }
以上的語法中 try 用于聲明和實例化資源,catch 用于處理關閉資源時可能引發的所有異常。
注意:try-with-resources 語句關閉所有實現 AutoCloseable 接口的資源。
參考:Java 異常處理 | 菜鳥教程 (runoob.com)
【轉】Sonar掃描bug修復 - 登風360 - 博客園 (cnblogs.com)
合規方案 在try語句進行實例定義,以防失敗。
private void readTheFile(String fileName) throws IOException {Path path = Paths.get(fileName);try (BufferedReader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {reader.readLine();// ...}// ..try (Stream<String> input = Files.lines("input.txt")) {input.forEach(System.out::println);}
}private void doSomething() {OutputStream stream = null;try {stream = new FileOutputStream("myfile.txt");for (String property : propertyList) {// ...}} catch (Exception e) {// ...} finally {stream.close();}
}
修復
try (var connection = dataSource.getConnection()) {try(PreparedStatement statement =connection.prepareStatement("select password from challenge_users where userid = '"+ username_login+ "' and password = '"+ password_login+ "'")) {ResultSet resultSet = statement.executeQuery();if (resultSet.next()) {return success(this).feedback("challenge.solved").feedbackArgs(flags.getFlag(5)).build();} else {return failed(this).feedback("challenge.close").build();}}}
?
?"Random" objects should be reused
問題:在類的多個方法中使用了Random random = new Random();不應該在方法內創建random實例,而應該把random實例創建為類的屬性,可以在多個地方調用,而且建議用?SecureRandom is preferred to Random。
解決:隨機數實例定義為一個屬性,然后在下面的方法里面生成隨機值
private Random rand = SecureRandom.getInstanceStrong(); // SecureRandom is preferred to Randompublic void doSomethingCommon() {int rValue = this.rand.nextInt();//...
?Use the "equals" method if value comparison was intended.
這個誤報了,因為這里!=是用來判斷不為null,跟值比較用的是equals方法
合規的方案也是這樣寫的。
String firstName = getFirstName();
String lastName = getLastName();if (firstName != null && firstName.equals(lastName)) { ... };
?Do something with the "boolean" value returned by "createNewFile"
意思是這個方法可能失敗,但是并沒有失敗處理。
Compliant Solution
public void doSomething(File file, Lock lock) {if (!lock.tryLock()) {// lock failed; take appropriate action}if (!file.delete()) {// file delete failed; take appropriate action}
}
?Null pointers should not be dereferenced
代碼中存在空指針解引用的問題。空指針解引用指的是當一個對象為空(null)時,嘗試訪問它的方法或屬性。
為了修復這個問題,你需要確保在訪問對象的方法或屬性之前,先進行空指針檢查
A "Map<WebGoatUser, Comments>" cannot contain a "String" in a "WebGoatUser" type.
?
vulnerability
Don't use the default "PasswordEncoder" relying on plain-text.
不要用純文本或者快速hash算法存儲password?,應該使用安全的算法產生hash。原因
1、預防暴力破解攻擊
2、預防撞庫攻擊
3、密碼應該加salt來降低彩虹表攻擊的風險。
?
The JWT signature (JWS) should be verified before using this token?
JWT應該使用強加密算法簽名和驗證
1、不要使用none算法簽名或驗證token的有效性
2、不要在沒有驗證簽名之前試用token。
這里就是在沒有驗證之前,就對token進行解析,如果攻擊者將算法設置為none后加密,也可以通過。
Disable access to external entities in XML parsing?
禁止在XML解析中訪問外部實體?
XML解析可能導致XXE攻擊
Security Hotspots?
Security-sensitive code that requires manual review to assess whether or not a vulnerability exists.安全敏感代碼需要人工審查來判斷是否存在漏洞。
可以看到檢測出好幾類問題,包括認證,CSSRF,SQL注入,DOS,弱加密,不安全配置和其他。
authentication 認證
'PASSWORD' detected in this expression, review this potentially hard-coded credential.
問題:這里把密碼硬編碼在文件中。
由于很容易從應用程序源代碼或二進制文件中提取字符串,因此不應對憑據進行硬編碼。尤其如此 適用于分布式或開源應用程序。
建議方案
1、憑據存放在配置文件中
2、憑據存放在數據庫中
3、如果密碼通過源代碼泄露,則修改密碼。
CSRF 跨站點請求偽造
Make sure allowing safe and unsafe HTTP methods is safe here.
問題:對于同一個url,同時使用了get和post方法
?
HTTP 方法在用于執行只讀操作(如檢索信息)時是安全的。相反,不安全的 HTTP 方法用于 更改應用程序的狀態,例如在 Web 應用程序上更新用戶的配置文件。
常見的安全 HTTP 方法有 GET、HEAD 或 OPTIONS。
常見的不安全 HTTP 方法有 POST、PUT 和 DELETE。
允許安全和不安全的 HTTP 方法對 Web 應用程序執行特定操作可能會影響其安全性,例如 CSRF 大多數情況下,保護僅保護由不安全的 HTTP 方法執行的操作。
敏感代碼示例
@RequestMapping("/delete_user") // Sensitive: by default all HTTP methods are allowed
public String delete1(String username) {
// state of the application will be changed here
}@RequestMapping(path = "/delete_user", method = {RequestMethod.GET, RequestMethod.POST}) // Sensitive: both safe and unsafe methods are allowed
String delete2(@RequestParam("id") String id) {
// state of the application will be changed here
}
推薦的安全編碼實踐
對于應用程序的所有路由/控制器,應顯式定義授權的 HTTP 方法,并且僅應定義安全的 HTTP 方法 用于執行只讀操作。
合規解決方案
@RequestMapping("/delete_user", method = RequestMethod.POST) // Compliant
public String delete1(String username) {
// state of the application will be changed here
}@RequestMapping(path = "/delete_user", method = RequestMethod.POST) // Compliant
String delete2(@RequestParam("id") String id) {
// state of the application will be changed here
}
有問題代碼
這里沒指定請求方法
?Make sure disabling Spring Security's CSRF protection is safe here.
當攻擊者可以強制 Web 應用程序的受信任用戶執行敏感操作時,就會發生跨站點請求偽造 (CSRF) 攻擊 他不打算執行的操作,例如更新他的個人資料或發送消息,更一般地說,任何可以改變狀態的行為。 應用。
攻擊者可以誘騙用戶/受害者單擊與特權操作相對應的鏈接,或訪問嵌入 隱藏的 Web 請求,并且由于 Web 瀏覽器自動包含 cookie,因此可以對操作進行身份驗證和敏感操作。
是否有風險?
問問自己是否
- Web 應用程序使用 Cookie 對用戶進行身份驗證。
- Web 應用程序中存在敏感操作,可以在對用戶進行身份驗證時執行這些操作。
- 例如,可以通過執行HTTP POST或HTTP DELETE請求來修改Web應用程序的狀態/資源。
如果您對這些問題中的任何一個回答是肯定的,則存在風險。
敏感代碼示例
默認情況下,Spring Security?提供了一個 防止 CSRF 攻擊,可以禁用:
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.csrf().disable(); // Sensitive: csrf protection is entirely disabled// orhttp.csrf().ignoringAntMatchers("/route/"); // Sensitive: csrf protection is disabled for specific routes}
}
推薦的安全編碼實踐
- 強烈建議對 CSRF 攻擊進行防護:
- 默認情況下,為所有不安全的 HTTP 激活 方法。
- 例如,使用不可猜測的 CSRF 令牌實現
- 當然,所有敏感操作都不應該使用安全的HTTP方法執行,例如設計為 僅用于信息檢索。
GET
合規解決方案
Spring SecurityCSRF 保護是 默認啟用,請勿禁用:
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {// http.csrf().disable(); // Compliant}
}
SQL注入
Make sure using a dynamically formatted SQL query is safe here.
格式化的 SQL 查詢可能難以維護和調試,并且將不受信任的值連接到 查詢?
問問自己是否
- 查詢的某些部分來自不受信任的值(如用戶輸入)。
- 查詢在代碼的其他部分重復/重復。
- 應用程序必須支持不同類型的關系數據庫。
如果您對這些問題中的任何一個回答是肯定的,則存在風險。
敏感代碼示例
public User getUser(Connection con, String user) throws SQLException {Statement stmt1 = null;Statement stmt2 = null;PreparedStatement pstmt;try {stmt1 = con.createStatement();ResultSet rs1 = stmt1.executeQuery("GETDATE()"); // No issue; hardcoded querystmt2 = con.createStatement();ResultSet rs2 = stmt2.executeQuery("select FNAME, LNAME, SSN " +"from USERS where UNAME=" + user); // Sensitivepstmt = con.prepareStatement("select FNAME, LNAME, SSN " +"from USERS where UNAME=" + user); // SensitiveResultSet rs3 = pstmt.executeQuery();//...
}public User getUserHibernate(org.hibernate.Session session, String data) {org.hibernate.Query query = session.createQuery("FROM students where fname = " + data); // Sensitive// ...
}
推薦的安全編碼實踐
- 使用參數化查詢、預準備語句或存儲 過程并將變量綁定到 SQL 查詢參數。
- 如果需要一個抽象層來訪問數據,請考慮使用 ORM 框架。
合規解決方案
public User getUser(Connection con, String user) throws SQLException {Statement stmt1 = null;PreparedStatement pstmt = null;String query = "select FNAME, LNAME, SSN " +"from USERS where UNAME=?"try {stmt1 = con.createStatement();ResultSet rs1 = stmt1.executeQuery("GETDATE()");pstmt = con.prepareStatement(query);pstmt.setString(1, user); // Good; PreparedStatements escape their inputs.ResultSet rs2 = pstmt.executeQuery();//...}
}public User getUserHibernate(org.hibernate.Session session, String data) {org.hibernate.Query query = session.createQuery("FROM students where fname = ?");query = query.setParameter(0,data); // Good; Parameter binding escapes all inputorg.hibernate.Query query2 = session.createQuery("FROM students where fname = " + data); // Sensitive// ...
Denial of Service(DOS) 拒絕服務攻擊
Make sure the regex used here, which is vulnerable to polynomial runtime due to backtracking, cannot lead to denial of service.?
需要審查是否由于使用了正則導致DOS
問問自己是否
- 輸入由用戶控制。
- 輸入大小不限于少量字符。
- 沒有超時來限制正則表達式評估時間。
如果您對這些問題中的任何一個回答是肯定的,則存在風險。
?Weak Cryptography 弱加密
Make sure this weak hash algorithm is not used in a sensitive context here.
請確保此處的敏感上下文中未使用此弱哈希算法。
passwordEncoder()
方法返回一個NoOpPasswordEncoder
實例,這是一個實現了PasswordEncoder
接口但并沒有實際操作的類,它通常用于開發過程中,在不處理密碼的情況下進行測試或開發。
這段代碼的具體含義是:創建一個不執行任何操作的密碼編碼器實例,以供Spring容器管理。這種實例通常在開發或測試階段使用,而在生產環境中,你可能需要使用更安全的密碼編碼器來保護你的用戶密碼。
?
危險:
?MD2、
MD4、
MD5、
MD6、
HAVAL-128、
HMAC-MD5、
DSA、
SHA-1、
RIPEMD、
RIPEMD-128、
RIPEMD-160、
HMACRIPEMD160、
SHA-1、
collisions
如圖顯示的這些加密算法不安全,不建議使用,因為可能由于不同的輸入產生same hash
?
問問自己是否
哈希值用于安全上下文,例如:
- 用戶密碼存儲。
- 生成安全令牌(用于在網站上注冊時確認電子郵件、重置密碼等)。
- 計算一些消息完整性。
如果您對這些問題中的任何一個回答是肯定的,則存在風險。
敏感代碼示例
MessageDigest md1 = MessageDigest.getInstance("SHA"); // Sensitive: SHA is not a standard name, for most security providers it's an alias of SHA-1
MessageDigest md2 = MessageDigest.getInstance("SHA1"); // Sensitive
推薦的安全編碼實踐
建議使用更安全的替代方案,例如 、 ,對于密碼哈希,它甚至 最好使用計算速度不太“快”的算法,例如 、 ,或者因為它會變慢。SHA-256?
SHA-512?
SHA-3?
bcrypt?
scrypt?
argon2?
pbkdf2
合規解決方案
MessageDigest md1 = MessageDigest.getInstance("SHA-512"); // Compliant
Make sure that using this pseudorandom number generator is safe here.
確保在這里使用偽隨機數生成器是安全的
?
問題:這里用了Random類生成隨機數,這個類被認為是偽隨機生成器,不推薦用這個類,推薦用 secureRandom類
使用偽隨機數生成器 (PRNG) 是安全敏感的。例如,它過去曾導致以下漏洞:
- CVE-2013-6386 漏洞CVE-<>-<>
- CVE-2006-3419 漏洞CVE-<>-<>
- CVE-2008-4102 漏洞CVE-<>-<>
當軟件在需要不可預測性的上下文中生成可預測值時,攻擊者可能會猜測下一個值 將生成,并使用此猜測來冒充其他用戶或訪問敏感信息。
由于該類依賴于偽隨機數生成器,因此此類和相關方法不應用于安全關鍵型應用程序或保護敏感數據。在這種情況下,應使用依賴于加密強隨機數生成器 (RNG)
問問自己是否
- 使用生成值的代碼要求它是不可預測的。所有加密機制都是這種情況,或者當一個秘密值時,例如 作為密碼,經過哈希處理。
- 您使用的函數生成一個可以預測的值(偽隨機)。
- 生成的值被多次使用。
- 攻擊者可以訪問生成的值。
如果您對這些問題中的任何一個回答是肯定的,則存在風險。
敏感代碼示例
Random random = new Random(); // Sensitive use of Random byte bytes[] = new byte[20]; random.nextBytes(bytes); // Check if bytes is used for hashing, encryption, etc...
推薦的安全編碼實踐
- 使用加密性強隨機數生成器 (RNG),如“java.security.SecureRandom”來代替此 PRNG。
- 生成的隨機值僅使用一次。
- 不應公開生成的隨機值。如果必須存儲它,請確保數據庫或文件是安全的。
合規解決方案
SecureRandom random = new SecureRandom(); // Compliant for security-sensitive use cases byte bytes[] = new byte[20]; random.nextBytes(bytes);
SecureRandom
類和Random
類都是Java中用于生成隨機數的類,但它們之間有一些重要的區別。
Random
類生成的是偽隨機數,這意味著它基于一個種子值生成數字,如果知道種子值,就可以預測生成的隨機數序列。這對于一些簡單的隨機數生成需求來說是足夠的,但對于需要高度安全性的應用,如密碼生成或加密,這種可預測性就不夠了。
SecureRandom
類是專門為需要高度安全性的隨機數生成需求設計的。它生成的是真正的隨機數,來源于系統提供的隨機性源,如操作系統的熵池(entropy pool)。這意味著即使知道當前的隨機數生成位置,也無法預測下一個生成的隨機數。這種真正的隨機性對于密碼學和加密學非常重要,因為它們需要無法預測的隨機數來保證安全性。總的來說,
SecureRandom
類比Random
類生成的數更隨機,因為它提供了真正的隨機性,而不是偽隨機性。這對于需要高度安全性的應用來說是至關重要的。
Insecure configuration不安全配置
Make sure this debug feature is deactivated before delivering the code in production.
問題:這里用了printStackTrace方法來調用堆棧。?
問問自己是否
- 啟用應用程序調試功能的代碼或配置部署在生產服務器上。
- 默認情況下,應用程序在激活調試功能的情況下運行。
如果您對這些問題中的任何一個回答是肯定的,則存在風險。
敏感代碼示例
Throwable.printStackTrace(...)
將 Throwable 及其堆棧跟蹤打印到(默認情況下),這并不容易 可解析,并可能暴露敏感信息:System.Err
try {/* ... */
} catch(Exception e) {e.printStackTrace(); // Sensitive
}
SpringFramework 的 EnableWebSecurity?注解,用于啟用調試支持:debug
true
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;@Configuration
@EnableWebSecurity(debug = true) // Sensitive
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {// ...
}
推薦的安全編碼實踐
不要在生產服務器上啟用調試功能。
合規解決方案
應使用記錄器(而不是 )來打印投擲物:printStackTrace
try {/* ... */
} catch(Exception e) {LOGGER.log("context", e); // Compliant
}
SpringFramework 的 EnableWebSecurity?注解,用于禁用調試支持:debug
false
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;@Configuration
@EnableWebSecurity(debug = false) // Compliant
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {// ...
}
其他
Make sure publicly writable directories are used safely here.
確保在此處安全地使用可公開寫入的目錄。
問題:這里用了?createTempDirectory方法創建文件,可能導致文件被創建至臨時文件夾
操作系統具有全局目錄,任何用戶都具有寫入訪問權限。這些文件夾主要用作臨時存儲區域,就像在基于 Linux 的系統中一樣。操作這些文件夾中的文件的應用程序會暴露在文件名的爭用條件下:惡意 用戶可以嘗試在應用程序之前創建具有可預測名稱的文件。成功的攻擊可導致其他文件被訪問, 已修改、損壞或刪除。如果應用程序使用提升的權限運行,則此風險甚至更高。/tmp
過去,它導致了以下漏洞:
- CVE-2012-2451 漏洞CVE-<>-<>
- CVE-2015-1838 漏洞CVE-<>-<>
每當此規則檢測到指向可公開寫入目錄的硬編碼路徑時,都會引發問題,例如(請參閱下面的示例)。它 還檢測對指向可公開寫入目錄的環境變量的訪問,例如 和 ./tmp
TMP
TMPDIR
/tmp
/var/tmp
/usr/tmp
/dev/shm
/dev/mqueue
/run/lock
/var/run/lock
/Library/Caches
/Users/Shared
/private/tmp
/private/var/tmp
\Windows\Temp
\Temp
\TMP
?問問自己是否
- 從可公開寫入的文件夾中讀取文件或將文件寫入該文件夾
- 應用程序將具有可預測名稱的文件創建到可公開寫入的文件夾中
如果您對這些問題中的任何一個回答是肯定的,則存在風險。
敏感代碼示例
new File("/tmp/myfile.txt"); // Sensitive
Paths.get("/tmp/myfile.txt"); // Sensitivejava.io.File.createTempFile("prefix", "suffix"); // Sensitive, will be in the default temporary-file directory.
java.nio.file.Files.createTempDirectory("prefix"); // Sensitive, will be in the default temporary-file directory.
Map<String, String> env = System.getenv();
env.get("TMP"); // Sensitive
推薦的安全編碼實踐
- 使用具有嚴格控制權限的專用子文件夾
- 使用設計安全的 API 創建臨時文件。此類 API 將確保:
- 生成的文件名是不可預測的
- 該文件只能由創建用戶 ID 讀取和寫入
- 文件描述符不由子進程繼承
- 文件將在關閉后立即銷毀
合規解決方案
new File("/myDirectory/myfile.txt");File.createTempFile("prefix", "suffix", new File("/mySecureDirectory"));FileAttribute<Set<PosixFilePermission>> attr = PosixFilePermissions.asFileAttribute(PosixFilePermissions.fromString("w+"));
Files.createTempFile("prefix", "suffix", attr); // Compliant, created with explicit attributes.
Make sure that expanding this archive file is safe here.
當應用程序在不控制擴展數據大小的情況下擴展不受信任的存檔文件時,就會發生成功的 Zip Bomb 攻擊,這可能會 導致拒絕服務。Zip 炸彈通常是幾千字節壓縮數據的惡意存檔文件,但變成了千兆字節的 未壓縮的數據。為了達到這種極端的壓縮率,攻擊者將 壓縮不相關的數據(例如:一長串重復字節)。?
問問自己是否
要擴展的存檔不受信任,并且:
- 沒有對存檔中的條目數進行驗證。
- 沒有對未壓縮數據的總大小進行驗證。
- 沒有驗證壓縮和未壓縮存檔條目之間的比率。
如果您對這些問題中的任何一個回答是肯定的,則存在風險。
敏感代碼示例
File f = new File("ZipBomb.zip");
ZipFile zipFile = new ZipFile(f);
Enumeration<? extends ZipEntry> entries = zipFile.entries(); // Sensitivewhile(entries.hasMoreElements()) {ZipEntry ze = entries.nextElement();File out = new File("./output_onlyfortesting.txt");Files.copy(zipFile.getInputStream(ze), out.toPath(), StandardCopyOption.REPLACE_EXISTING);
}
推薦的安全編碼實踐
- 定義和控制壓縮數據與未壓縮數據之間的比例,一般來說,大多數合法檔案的數據壓縮比例是 1 到 3。
- 定義和控制未壓縮數據的最大總大小的閾值。
- 計算從存檔中提取的文件條目數,如果其數量大于預定義的閾值,則中止提取,在 特別是,不建議以遞歸方式擴展存檔(存檔的條目也可以是存檔)。
合規解決方案
不要依賴?getsize?來檢索 未壓縮的條目,因為此方法返回存檔標頭中定義的內容,攻擊者可以偽造這些內容,而不是計算實際 解壓時的條目尺寸