Access Control: Database(訪問控制:數據庫)
Build Misconfiguration: External Maven Dependency Repository(構建錯誤配置:外部 Maven 依賴庫(環境、配置))
Code Correctness: Byte Array to String Conversion(代碼正確性:字節數組到字符串的轉換)
Code Correctness: Double-Checked Locking(代碼正確性:雙重檢查鎖定)
Cross-Site Scripting: Persistent(跨站點腳本:持久性)
Dead Code: Expression is Always true(死代碼:表達式始終為真)
Dead Code: Unused Field(死代碼:未使用的字段)
Dead Code: Unused Method(死代碼:未使用的方法)
Denial of Service(拒絕服務)
Denial of Service: Parse Double(拒絕服務:雙重解析)
Insecure Randomness(不安全隨機性)
J2EE Bad Practices: Leftover Debug Code(J2EE錯誤實踐:遺留測試代碼)
J2EE Bad Practices: Sockets(J2EE錯誤實踐:套接字)
Key Management: Hardcoded Encryption Key(密鑰管理:硬編碼加密密鑰)
Missing Check against Null(缺少對 NULL 的檢查)
Obsolete(淘汰的)
Often Misused: Authentication(經常被誤用的:身份驗證)
Password Management: Empty Password in Configuration File(密碼管理:配置文件中的密碼為空)
Password Management: Password in Comment(密碼管理:注釋中的密碼)
Poor Error Handling: Empty Catch Block(錯誤處理不佳:捕獲塊為空)
Poor Error Handling: Overly Broad Catch(錯誤處理不佳:捕獲范圍過廣)
Poor Error Handling: Overly Broad Throws(錯誤處理不佳:拋出范圍過廣)
Poor Error Handling: Throw Inside Finally(錯誤處理不佳:最終拋出內部)
Poor Logging Practice: Use of a System Output Stream(糟糕的日志記錄實踐:使用系統輸出流)
Poor Style: Non-final Public Static Field(糟糕的樣式:非最終公共靜態字段)
Poor Style: Redundant Initialization(糟糕的風格:冗余初始化)
Poor Style: Value Never Read(糟糕的風格:值永遠不會被閱讀)
Portability Flaw: Locale Dependent Comparison(可移植性缺陷:與區域設置相關的比較)
SQL Injection: MyBatis Mapper(SQL注入:Mybatis映射器)
System Information Leak(系統信息泄露)
System Information Leak: Internal(系統信息泄露: 內部)
Unchecked Return Value(未檢查返回值)
Unreleased Resource: Streams(沒有釋放流資源)
Weak Cryptographic Hash(弱加密散列)
Access Control: Database(訪問控制:數據庫)
這個是數據越權問題
發生這個問題的原因:
1.數據從一個不可信賴的數據源進入程序。
2.這個數據用來指定SQL查詢中主鍵的值。
示例:
------
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();
------
上述問題:
開發者沒有考慮到所有可能出現的id值。雖然接口生成了一個當前用戶的標識符清單,但是攻擊者可以繞過這個接口,從而獲取所需的任何清單。
代碼示例中在查詢數據庫時沒有執行檢查用戶是否有權限進行查詢。
解決方案:
與其靠表面層來限制用戶輸入的值,還不如在應用程序和數據庫層上進行 access control。在任何情況下都不允許用戶在沒有取得相應權限的情況下獲取或修改數據庫中的記錄。每個涉及數據庫的查詢都必須遵守這個原則,這可以通過把當前被授權的用戶名作為查詢語句的一部分來實現。
示例:
------
userName = ctx.getAuthenticatedUserName();
id = Integer.decode(request.getParameter("invoiceID"));
String query =
"SELECT * FROM invoices WHERE id = ? AND user = ?";
PreparedStatement stmt = conn.prepareStatement(query);
stmt.setInt(1, id);
stmt.setString(2, userName);
ResultSet results = stmt.execute();
------
總結:
要防止數據越權的漏洞問題,需要做到以下兩點:
1.對需要查詢的數據,給sql語句加上數據權限的限定條件,限定數據所屬角色。
2.對於這個加上的數據權限的限定條件,最好是從后台獲取,而不是通過前台傳入。(如獲取登錄用戶的用戶角色,直接從后台通過工具類獲取,而不是從前台傳過來)。
tips:
還有一個一勞永逸的方法,直接將dao層打成一個jar包,這樣掃描工具就掃描不出來了。(實測可用)
Build Misconfiguration: External Maven Dependency Repository
構建錯誤配置:外部 Maven 依賴庫(環境、配置)
示例:
------
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
...
------
問題:
這一 Maven 編譯腳本依賴於外部數據源,這會導致攻擊者能夠將惡意代碼插入最終產品中,或者控制編譯計算機。
解決方案:
1.
------
<project>
...
------
2.
使用自己創建或者公司創建的安全依賴來源。
Code Correctness: Byte Array to String Conversion
代碼正確性:字節數組到字符串的轉換
示例:
------
public static String encodeBase64(byte[] binaryData) {
byte[] newbt = Base64.encodeBase64(binaryData);
return new String(newbt);
}
------
問題:
將字節數組轉換成字符串可能會導致數據丟失。
解決方案:
return new String(newbt, "UTF-8");
Code Correctness: Double-Checked Locking
代碼正確性:雙重檢查鎖定
示例:
------
if (appConfService == null) {
synchronized (AppConfService.class) {
if (appConfService == null) {
appConfService = new AppConfService();
}
}
------
問題:
多此一舉,雙重檢查鎖定是一種不正確的習慣用法。
解決方案:
刪掉多余的一層。
Cross-Site Scripting: Persistent
跨站點腳本:持久性
示例:
------
//輸出浿
InputStream str = conn.getInputStream();
OutputStream out = response.getOutputStream();
int len = 0;
byte[] by = new byte[1024 * 10];
while ((len = str.read(by)) > 0) {
out.write(by, 0, len);
}
out.close();
str.close();
------
問題:
向瀏覽器發送未經驗證的數據可能導致瀏覽器執行惡意代碼。
解決方案:
進行數據校驗。
Dead Code: Expression is Always true
死代碼:表達式始終為真
示例:
------
BigDecimal threshold = null;
Double thresholdValue = threshold == null ? 0 : threshold.doubleValue();
------
問題:
重視代碼質量與代碼邏輯。
這個問題在進行循環、判斷等情況下經常出現。
解決方案:
重新修改判斷邏輯。
Dead Code: Unused Field
死代碼:未使用的字段
示例:
------
@Autowired
private EquipStatisticsDao equipStatisticsDao;
@Autowired
private OrgDao orgDao;
------
問題:
定義的字段,在代碼中沒有使用到。
解決方案:
在每天寫完代碼,進行提交的時候,先檢查一遍,把IDEA上灰色沒有用到的代碼進行刪除或者注釋。
Dead Code: Unused Method
死代碼:未使用的方法
問題:
定義的方法,在代碼中沒有使用到。
解決方案:
代碼中沒有用到的方法進行刪除或者注釋。
Denial of Service
拒絕服務
攻擊者可以通過向應用程序發送大量請求來拒絕向合法用戶提供服務。
示例:
------
問題一:
int usrSleepTime = Integer.parseInt(usrInput);
Thread.sleep(usrSleepTime);
問題二:
InputStream zipInput = zipFile.getInputStream(zipEntry);
Reader zipReader = new InputStreamReader(zipInput);
BufferedReader br = new BufferedReader(zipReader);
String line = br.readLine();
------
問題:
泛洪攻擊通常可以在網絡層消除,更嚴重的問題是允許攻擊者使用少量請求過載應用程序的漏洞,此類漏洞允許攻擊者指定其請求將消耗的系統資源數量或使用時間。
問題一:允許用戶指定線程睡眠的時間量,通過指定一個大的數字,攻擊者可以無限期地捆綁線程。通過少量請求,攻擊者可能會耗盡應用程序的線程池。
問題二:代碼從zip文件中讀取字符串,因為它使用readLine()方法,所以它將讀取無限量的輸入。攻擊者可能會利用此代碼造成攻擊,OutOfMemoryException或消耗大量內存,使程序花費更多執行垃圾收集或在后續操作中耗盡內存的時間。
解決方案:
驗證用戶輸入,以確保它不會導致不適當的資源利用率。
問題一:允許用戶指定線程睡眠的時間量但前提是該值在合理范圍內。
------
int usrSleepTime = Integer.parseInt(usrInput);
if (usrSleepTime >= SLEEP_MIN &&
usrSleepTime <= SLEEP_MAX) {
Thread.sleep(usrSleepTime);
} else {
throw new Exception("Invalid sleep duration");
}
------
問題二:從zip文件中讀取一個字符串,與示例2中的一樣,但最大值為它將讀取的長度為最大字符數。
------
InputStream zipInput = zipFile.getInputStream(zipEntry);
Reader zipReader = new InputStreamReader(zipInput);
BufferedReader br = new BufferedReader(zipReader);
StringBuffer sb = new StringBuffer();
int intC;
while ((intC = br.read()) != -1) {
char c = (char) intC;
if (c == '\n') {
break;
}
if (sb.length() >= MAX_STR_LEN) {
throw new Exception("input too long");
}
sb.append(c);
}
String line = sb.toString();
------
Denial of Service: Parse Double
拒絕服務:雙重解析
程序調用一個方法,該方法解析 double 並可能導致線程掛起。
示例:
------
pressureList.add(Double.valueOf(map.get("pressure").toString()));
------
問題:
java.lang.Double.parseDouble()和相關方法的實現中存在一個漏洞,在解析范圍內的任何數字時,該漏洞會導致線程掛起[2^(-1022) - 2^(-1075) :2^(-1022) - 2^(-1076)]。此缺陷可用於執行拒絕服務(DoS)攻擊。
解決方案:
升級JDK。(1.7 不存在服務掛起)
Insecure Randomness
不安全隨機性
標准偽隨機數生成器無法抵抗加密攻擊。
示例:
------
String GenerateReceiptURL(String baseUrl) {
Random ranGen = new Random();
ranGen.setSeed((new Date()).getTime());
return (baseUrl + ranGen.nextInt(400000000) + ".html");
}
------
問題:
當能夠產生可預測值的函數被用作安全敏感上下文中的隨機性源時,就會出現不安全的隨機性錯誤。計算機是確定性機器,因此無法產生真正的隨機性。
PRNG有兩種類型:統計和加密。
統計PRNG提供有用的統計特性,但其輸出具有高度可預測性,並形成易於復制的數字流,不適合在安全性依賴於生成的不可預測值的情況下使用。
加密PRNG通過生成更難預測的輸出來解決此問題。對於加密安全的值,攻擊者必須不可能或極不可能區分生成的隨機值和真正的隨機值。
一般來說,如果PRNG算法沒有被宣傳為加密安全的,那么它可能是一種統計PRNG,不應在安全敏感的環境中使用,在這種環境中使用它可能導致嚴重的漏洞,例如容易猜測的臨時密碼、可預測的加密密鑰、會話劫持和DNS欺騙。
解決方案:
使用加密的PRNG生成隨機數。
SecureRandom random1 = new SecureRandom();
J2EE Bad Practices: Leftover Debug Code
J2EE錯誤實踐:遺留測試代碼
調試代碼可以在已部署的web應用程序中創建意外的入口點。
示例:
------
public static void main(String[] args) {
System.out.println("獲取拼音首字母:" + getFirstLetter("北京"));
}
------
問題:
這些測試代碼不打算隨應用程序一起發布或部署。當這類調試代碼意外地留在應用程序中時,應用程序將對非預期的交互模式開放,這些后門入口點會產生安全風險,因為它們在設計或測試期間未被考慮,並且超出了應用程序的預期操作條件。最常見示例是web應用程序中出現的main()方法。
解決方案:
在部署應用程序的生產版本之前刪除調試代碼。無論是否可以明確表示直接的安全威脅,在開發的早期階段之后,不太可能有合法的理由讓此類代碼保留在應用程序中。
J2EE Bad Practices: Sockets
J2EE錯誤實踐:套接字
示例:
------
/**
* 校驗ip、端口是否ping通
*
* @param host
* @param port
* @return
*/
public static boolean isHostConnectable(String host, int port) {
Socket socket = new Socket();
try {
socket.connect(new InetSocketAddress(host, port));
} catch (IOException e) {
e.printStackTrace();
return false;
} finally {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return true;
}
------
問題:
J2EE標准只允許在沒有更高級別的協議可用時,將套接字用於與遺留系統通信。編寫自己的通信協議需要解決棘手的安全問題,包括:-協議版本之間的帶內與帶外信令兼容性-通道安全-錯誤處理-網絡約束(防火牆)-會話管理,無需安全專家的嚴格審查,自定義通信協議很可能會遇到安全問題。
解決方案:
使用更高級的通信協議進行通信,方法沒用到的話就注釋掉。
Key Management: Hardcoded Encryption Key
密鑰管理:硬編碼加密密鑰
硬編碼加密密鑰可能會以一種不易補救的方式危害安全性。
示例:
------
私有靜態最終字符串加密密鑰=“lakdsljklkjlksdfkl”;
byte[]keyBytes=encryptionKey.getBytes();
SecretKeySpec key=新的SecretKeySpec(keyBytes,“AES”);
Cipher encryptCipher=Cipher.getInstance(“AES”);
encryptCipher.init(Cipher.ENCRYPT_模式,密鑰);
------
問題:
硬編碼加密密鑰從來不是一個好主意,因為它允許項目的所有開發人員查看加密密鑰,並且使修復問題變得極其困難。代碼投入生產后,需要一個軟件補丁來更改加密密鑰。如果受加密密鑰保護的帳戶受損,系統所有者必須在安全性和可用性之間進行選擇。
解決方案:
加密密鑰不應硬編碼,應在外部源中進行模糊處理和管理。
Missing Check against Null
缺少對 NULL 的檢查
示例:
------
問題一:
String itemName = request.getParameter(ITEM_NAME);
if (itemName.compareTo(IMPORTANT_ITEM)) {
...
}
...
問題二:
System.clearProperty("os.name");
String os = System.getProperty("os.name");
if (os.equalsIgnoreCase("Windows 95") )
System.out.println("Not supported");
------
問題:
代碼中容易發現的兩個可疑假設是“此函數調用永遠不會失敗”和“此函數調用失敗並不重要”。考慮空值的存在,要先進行判斷。
解決方案:
對可能存在空值的情況下,先進行非空校驗。
Obsolete
淘汰的
使用不推薦使用或過時的函數
示例:
------
public static String stringEncode(String str) {
return java.net.URLEncoder.encode(str);
}
------
問題:
使用已過期的方法 encode()。如果程序使用不推薦的或如果函數過時,則會增加附近潛伏安全問題的可能性。
解決方案:
使用更新過的類與方法,減少潛在的安全風險。
Often Misused: Authentication
經常被誤用的:身份驗證
攻擊者可能偽造DNS條目。不要依賴DNS名稱來實現安全性。
示例:
------
String ip = request.getRemoteAddr();
InetAddress addr = InetAddress.getByName(ip);
if (addr.getCanonicalHostName().endsWith("trustme.com")) {
trusted = true;
}
------
問題:
這種驗證方式不安全,容易受到DNS的攻擊。
解決方案:
在許多情況下,包括物理令牌在內的多因素身份驗證提供了最大的安全性價格合理。(使用Token)
Password Management: Empty Password in Configuration File
密碼管理:配置文件中的密碼為空
示例:
------
spring.redis.password=
------
問題:
使用空字符串作為密碼是不安全的。
解決方案:
提供足夠難猜的密碼保護所有賬戶和系統資源。
Password Management: Password in Comment
密碼管理:注釋中的密碼
示例:
------
// Default username for database connection is "scott"
// Default password for database connection is "tiger"
------
問題:
在系統或系統代碼中的任何位置以純文本形式存儲密碼或密碼詳細信息可能會以不易補救的方式危害系統安全性。
解決方案:
注釋掉的密碼代碼,刪除。
Poor Error Handling: Empty Catch Block
錯誤處理不佳:捕獲塊為空
示例:
------
try {
doExchange();
}
catch (RareException e) {
// this can never happen
}
------
問題:
忽略異常會導致程序忽略意外的狀態和條件。
解決方案:
在捕獲異常的代碼塊中填寫可能出現的異常,養成好習慣。
Poor Error Handling: Overly Broad Catch
錯誤處理不佳:捕獲范圍過廣
示例:
public static String adding(String a, String b) {
try {
return String.valueOf(Double.valueOf(a).doubleValue() + Double.valueOf(b).doubleValue());
} catch (Exception e) {
return a;
}
}
問題:
捕獲一個過於廣泛的異常本質上違背了Java的類型化異常,因為例外可能會掩蓋那些值得特別對待或不應該被抓住的例外節目中的要點。
節目中的要點。
解決方案:
不要捕獲廣泛的異常類,例如exception、Throwable、Error或RuntimeException除了在程序或線程的最高層。分層次拋出可能出現的異常(如IOException、InvocationTargetException、SQLException 等)
Poor Error Handling: Overly Broad Throws
錯誤處理不佳:拋出范圍過廣
示例:
------
public void doExchange()
throws Exception {
...
}
------
問題:
拋出異常的級別過高,使得調用方更難做好錯誤處理和恢復工作。
解決方案:
public void doExchange()
throws IOException, InvocationTargetException,
SQLException {
...
}
拋出異常進行降級,更好進行處理。
Poor Error Handling: Throw Inside Finally
錯誤處理不佳:最終拋出內部
示例:
------
public void processTransaction(Connection conn) throws FileNotFoundException
{
FileInputStream fis = null;
Statement stmt = null;
try {
stmt = conn.createStatement();
fis = new FileInputStream("badFile.txt");
...
}
catch (FileNotFoundException fe) {
log("File not found.");
}
catch (SQLException se) {
//handle error
}
finally {
if (fis == null) {
throw new FileNotFoundException();
}
if (stmt != null) {
try {
stmt.close();
}
catch (SQLException e) {
log(e);
}
}
}
}
------
問題:
在finally塊中使用throw語句會中斷try-catch finally的邏輯進程。
解決方案:
不要在 finally 中進行拋出,直接 try-catch 捕獲處理。
Poor Logging Practice: Use of a System Output Stream
糟糕的日志記錄實踐:使用系統輸出流
示例:
------
public class MyClass
public static void main(String[] args) {
System.out.println("hello world");
}
}
------
問題:
使用System.out或System.err而不是專用的日志記錄工具會使監控程序的行為變得困難。
解決方案:
import org.apache.log4j.Logger;
import org.apache.log4j.BasicConfigurator;
public class MyClass {
private final static Logger logger = Logger.getLogger(MyClass.class);
public static void main(String[] args) {
BasicConfigurator.configure();
logger.info("hello world");
}
}
使用日志來記錄程序的運行狀況,養成良好的習慣。
Poor Style: Non-final Public Static Field
糟糕的樣式:非最終公共靜態字段
示例:
------
public class MyClass
{
public static int ERROR_CODE = 100;
//...
}
------
問題:
通常情況下,您不希望提供外部類直接訪問對象的成員字段,因為公共字段可以由任何外部類更改。良好的面向對象設計使用封裝來防止實現細節(如成員字段)暴露給其他類。
解決方案:
public class MyClass
{
public static final int ERROR_CODE = 123;
//...
}
如果要將字段作為常量值公開,則應則應將該字段聲明為public static final,否則將該字段聲明為私有。
Poor Style: Redundant Initialization
糟糕的風格:冗余初始化
示例:
------
int r = getNum();
r = getNewNum(buf);
------
問題:
不使用此變量的初始值。初始化后,變量被分配另一個值或超出范圍。上面的代碼摘錄分配給變量r,然后覆蓋,沒有使用它的價值。
解決方案:
刪除不必要的分配,以使代碼更易於理解與維護。
Poor Style: Value Never Read
糟糕的風格:值永遠不會被閱讀
示例:
------
r = getName();
r = getNewBuffer(buf);
------
問題:
變量的值已賦值,但從未使用過,這使它成為一個死區。
解決方案:
刪除不必要的分配,以使代碼更易於理解和維護。
Portability Flaw: Locale Dependent Comparison
可移植性缺陷:與區域設置相關的比較
示例:
------
/**
* 判斷當前操作系統是否為windows
*
* @return
*/
public static boolean isWindows() {
return System.getProperty("os.name").toLowerCase().startsWith("win");
}
------
問題:
限定范圍,不易移植。
解決方案:
import java.util.Locale;
...
public String tagProcessor(String tag){
if (tag.toUpperCase(Locale.ENGLISH).equals("SCRIPT")){
return null;
}
//does not contain SCRIPT tag, keep processing input
...
}
SQL Injection: MyBatis Mapper
SQL注入:Mybatis映射器
問題:
與數據庫權限問題類似。
解決方案:
把dao層打成jar包。
System Information Leak
系統信息泄露
示例:
------
try {
...
} catch (Exception e) {
e.printStackTrace();
}
------
問題:
透露系統數據或調試信息有助於敵方了解系統並形成一個進攻計划。
解決方案:
1.IIS上發布站點時關閉Debug 遠程調試模式。
2.定義錯誤頁面規范錯誤提示信息。
3.自定義客戶端異常信息類,消化內部異常信息,記錄日志,過濾處理后拋給客戶端允許可到的異常信息。
System Information Leak: Internal
系統信息泄露: 內部
示例:
------
System.out.println("字符串編碼轉換異常:" + ex.getMessage());
------
問題:
同上。
解決方案:
同上。
Unchecked Return Value
未檢查返回值
示例:
------
File file = new File(fileName);
//文件夾不存在則自動創廿
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
os = new FileOutputStream(file);
------
問題:
返回值沒有校驗。
解決方案:
校驗返回值。
Unreleased Resource: Streams
沒有釋放流資源
示例:
------
private void processFile(String fName) throws FileNotFoundException,
IOException {
FileInputStream fis = new FileInputStream(fName);
int sz;
byte[] byteArray = new byte[BLOCK_SIZE];
while ((sz = fis.read(byteArray)) != -1) {
processBytes(byteArray, sz);
}
}
------
問題:
流使用完畢之后沒有關閉,會消耗內存資源。
解決方案:
關閉流資源。(通常在 finally 中進行關閉)
Weak Cryptographic Hash
弱加密散列
示例:
------
try {
md5 = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
// System.out.println("Error: " + e);
------
問題:
MD2、MD4、MD5、RIPEMD-160和SHA-1是常用的加密哈希算法,用於驗證消息和其他數據的完整性。然而,最近的密碼分析研究表明這些算法存在根本缺陷,因此不應再在安全關鍵系統中使用它們上下文。
解決方案:
停止使用MD2、MD4、MD5、RIPEMD-160和SHA-1進行安全關鍵數據庫中的數據驗證
上下文。目前,SHA-224、SHA-256、SHA-384、SHA-512和SHA-3是很好的替代方案。