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是很好的替代方案。
标签:
java
本文转载自: https://blog.csdn.net/2301_76354366/article/details/128815903
版权归原作者 半自定义大剑仙 所有, 如有侵权,请联系我们删除。
版权归原作者 半自定义大剑仙 所有, 如有侵权,请联系我们删除。