docker安装sonarqube,sonarQube静态代码扫描 - Joson6350 - 博客园 (cnblogs.com)
扫描结果
意思是这里的else if语句不会执行,因为ipAddressKnow为true,所以if 和else if的条件结果是一样的。
提示资源没有关闭,需要在finally中进行资源关闭,但是把资源关闭放到finally中由提示这样写不规范有异味。所以它推荐的写法是将创建资源流的代码放在try()中,这样系统会自动的关闭资源,不需要我们写.close()方法
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 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 random = new Random();不应该在方法内创建random实例,而应该把random实例创建为类的属性,可以在多个地方调用,而且建议用 SecureRandom is preferred to Random。
解决:随机数实例定义为一个属性,然后在下面的方法里面生成随机值
private Random rand = SecureRandom.getInstanceStrong(); // SecureRandom is preferred to Random
public void doSomethingCommon() {
int rValue = this.rand.nextInt();
//...
这个误报了,因为这里!=是用来判断不为null,跟值比较用的是equals方法
合规的方案也是这样写的。
String firstName = getFirstName();
String lastName = getLastName();
if (firstName != null && firstName.equals(lastName)) { ... };
意思是这个方法可能失败,但是并没有失败处理。
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)时,尝试访问它的方法或属性。
为了修复这个问题,你需要确保在访问对象的方法或属性之前,先进行空指针检查
不要用纯文本或者快速hash算法存储password ,应该使用安全的算法产生hash。原因
1、预防暴力破解攻击
2、预防撞库攻击
3、密码应该加salt来降低彩虹表攻击的风险。
JWT应该使用强加密算法签名和验证
1、不要使用none算法签名或验证token的有效性
2、不要在没有验证签名之前试用token。
这里就是在没有验证之前,就对token进行解析,如果攻击者将算法设置为none后加密,也可以通过。
禁止在XML解析中访问外部实体
XML解析可能导致XXE攻击
Security-sensitive code that requires manual review to assess whether or not a vulnerability exists.安全敏感代码需要人工审查来判断是否存在漏洞。
可以看到检测出好几类问题,包括认证,CSSRF,SQL注入,DOS,弱加密,不安全配置和其他。
问题:这里把密码硬编码在文件中。
由于很容易从应用程序源代码或二进制文件中提取字符串,因此不应对凭据进行硬编码。尤其如此 适用于分布式或开源应用程序。
建议方案
1、凭据存放在配置文件中
2、凭据存放在数据库中
3、如果密码通过源代码泄露,则修改密码。
问题:对于同一个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
}
有问题代码
这里没指定请求方法
当攻击者可以强制 Web 应用程序的受信任用户执行敏感操作时,就会发生跨站点请求伪造 (CSRF) 攻击 他不打算执行的操作,例如更新他的个人资料或发送消息,更一般地说,任何可以改变状态的行为。 应用。
攻击者可以诱骗用户/受害者单击与特权操作相对应的链接,或访问嵌入 隐藏的 Web 请求,并且由于 Web 浏览器自动包含 cookie,因此可以对操作进行身份验证和敏感操作。
是否有风险?
问问自己是否
如果您对这些问题中的任何一个回答是肯定的,则存在风险。
敏感代码示例
默认情况下,Spring Security 提供了一个 防止 CSRF 攻击,可以禁用:
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable(); // Sensitive: csrf protection is entirely disabled
// or
http.csrf().ignoringAntMatchers("/route/"); // Sensitive: csrf protection is disabled for specific routes
}
}
推荐的安全编码实践
GET
合规解决方案
Spring SecurityCSRF 保护是 默认启用,请勿禁用:
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// http.csrf().disable(); // Compliant
}
}
格式化的 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 query
stmt2 = con.createStatement();
ResultSet rs2 = stmt2.executeQuery("select FNAME, LNAME, SSN " +
"from USERS where UNAME=" + user); // Sensitive
pstmt = con.prepareStatement("select FNAME, LNAME, SSN " +
"from USERS where UNAME=" + user); // Sensitive
ResultSet rs3 = pstmt.executeQuery();
//...
}
public User getUserHibernate(org.hibernate.Session session, String data) {
org.hibernate.Query query = session.createQuery(
"FROM students where fname = " + data); // Sensitive
// ...
}
推荐的安全编码实践
合规解决方案
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 input
org.hibernate.Query query2 = session.createQuery("FROM students where fname = " + data); // Sensitive
// ...
需要审查是否由于使用了正则导致DOS
问问自己是否
如果您对这些问题中的任何一个回答是肯定的,则存在风险。
请确保此处的敏感上下文中未使用此弱哈希算法。
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
确保在这里使用伪随机数生成器是安全的
问题:这里用了Random类生成随机数,这个类被认为是伪随机生成器,不推荐用这个类,推荐用 secureRandom类
使用伪随机数生成器 (PRNG) 是安全敏感的。例如,它过去曾导致以下漏洞:
当软件在需要不可预测性的上下文中生成可预测值时,攻击者可能会猜测下一个值 将生成,并使用此猜测来冒充其他用户或访问敏感信息。
由于该类依赖于伪随机数生成器,因此此类和相关方法不应用于安全关键型应用程序或保护敏感数据。在这种情况下,应使用依赖于加密强随机数生成器 (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...
推荐的安全编码实践
合规解决方案
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
类生成的数更随机,因为它提供了真正的随机性,而不是伪随机性。这对于需要高度安全性的应用来说是至关重要的。
问题:这里用了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 {
// ...
}
确保在此处安全地使用可公开写入的目录。
问题:这里用了 createTempDirectory方法创建文件,可能导致文件被创建至临时文件夹
操作系统具有全局目录,任何用户都具有写入访问权限。这些文件夹主要用作临时存储区域,就像在基于 Linux 的系统中一样。操作这些文件夹中的文件的应用程序会暴露在文件名的争用条件下:恶意 用户可以尝试在应用程序之前创建具有可预测名称的文件。成功的攻击可导致其他文件被访问, 已修改、损坏或删除。如果应用程序使用提升的权限运行,则此风险甚至更高。/tmp
过去,它导致了以下漏洞:
每当此规则检测到指向可公开写入目录的硬编码路径时,都会引发问题,例如(请参阅下面的示例)。它 还检测对指向可公开写入目录的环境变量的访问,例如 和 ./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"); // Sensitive
java.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 env = System.getenv();
env.get("TMP"); // Sensitive
推荐的安全编码实践
合规解决方案
new File("/myDirectory/myfile.txt");
File.createTempFile("prefix", "suffix", new File("/mySecureDirectory"));
FileAttribute> attr = PosixFilePermissions.asFileAttribute(PosixFilePermissions.fromString("w+"));
Files.createTempFile("prefix", "suffix", attr); // Compliant, created with explicit attributes.
当应用程序在不控制扩展数据大小的情况下扩展不受信任的存档文件时,就会发生成功的 Zip Bomb 攻击,这可能会 导致拒绝服务。Zip 炸弹通常是几千字节压缩数据的恶意存档文件,但变成了千兆字节的 未压缩的数据。为了达到这种极端的压缩率,攻击者将 压缩不相关的数据(例如:一长串重复字节)。
问问自己是否
要扩展的存档不受信任,并且:
如果您对这些问题中的任何一个回答是肯定的,则存在风险。
敏感代码示例
File f = new File("ZipBomb.zip");
ZipFile zipFile = new ZipFile(f);
Enumeration extends ZipEntry> entries = zipFile.entries(); // Sensitive
while(entries.hasMoreElements()) {
ZipEntry ze = entries.nextElement();
File out = new File("./output_onlyfortesting.txt");
Files.copy(zipFile.getInputStream(ze), out.toPath(), StandardCopyOption.REPLACE_EXISTING);
}
推荐的安全编码实践
合规解决方案
不要依赖 getsize 来检索 未压缩的条目,因为此方法返回存档标头中定义的内容,攻击者可以伪造这些内容,而不是计算实际 解压时的条目尺寸