代码质量管理-安全问题
自动化持续代码质量监测工具SonarQube,有关安全问题相关代码示例。
1、Use a logger to log this exception.
错误代码:
try {
saveGeographicInfo(geographicInfo, gisConfig);
} catch (Exception e) {
e.printStackTrace();
//Use a logger to log this exception.
}
Reason:
- 不应调用Throwable.printStackTrace(…)
- printStackTrace(…)将抛出及其堆栈跟踪打印到某个流。默认情况下,该stream System.Err可能会无意中公开敏感信息。
应该使用记录器来打印一次性文件,因为它们有许多优点:
- 用户可以轻松地检索日志。
- 日志消息的格式是统一的,允许用户轻松浏览日志。
- 如果使用printStackTrace时没有参数,即堆栈跟踪打印到默认流时,此规则会引发问题。
Solution:
错误案例:
//Noncompliant Code Example
try {
/* ... */
} catch(Exception e) {
LOGGER.log("context", e);
}
try {
/* ... */
} catch(Exception e) {
e.printStackTrace(); // Noncompliant
}
推荐案例:
//Compliant Solution
try {
/* ... */
} catch(Exception e) {
LOGGER.log("context", e);
}
2、Add password protection to this database
错误代码:
try {
/* 建立连接 */
conn = DriverManager.getConnection(URL, username, password);
//Add password protection to this database。
}
Reason:
- 数据库应始终受密码保护,但使用密码为空的数据库连接清楚地表明数据库未受保护。
用空密码标记数据库连接。
Solution:
错误案例:
//Noncompliant Code Example
Connection conn = DriverManager.getConnection("jdbc:derby:memory:myDB;create=true", "AppLogin", "");
Connection conn2 = DriverManager.getConnection("jdbc:derby:memory:myDB;create=true?user=user&password=");
推荐案例:
//Compliant Solution
DriverManager.getConnection("jdbc:derby:memory:myDB;create=true?user=user&password=password");
DriverManager.getConnection("jdbc:mysql://address=(host=myhost1)(port=1111)(key1=value1)(user=sandy)(password=secret),address=(host=myhost2)(port=2222)(key2=value2)(user=sandy)(password=secret)/db");
DriverManager.getConnection("jdbc:mysql://sandy:secret@[myhost1:1111,myhost2:2222]/db");
String url = "jdbc:postgresql://localhost/test";
Properties props = new Properties();
props.setProperty("user", "fred");
props.setProperty("password", "secret");
DriverManager.getConnection(url, props);
3、Make this “public static map” field final
错误代码:
public static Map<String, String> map;
Reason:
没有充分的理由在不声明字段“final”的情况下声明字段“public”和“static”。大多数情况下,这是一个在多个对象之间共享状态的错误。但是使用这种方法,任何对象都可以对共享状态执行它想要的任何操作,例如将其设置为空。
Solution:
错误案例:
//Noncompliant Code Example
public class Greeter {
public static Foo foo = new Foo();
...
}
推荐案例:
//Compliant Solution
public class Greeter {
public static final Foo FOO = new Foo();
...
}
Make map a static final constant or non-public and provide accessors if needed.
公共类变量字段不尊重封装原则,有三个主要缺点:
- 无法添加其他行为,如验证。
- 内部表示是公开的,以后不能更改。
- 成员值可能会在代码中的任何地方发生变化,并且可能不符合程序员的假设。
通过使用私有属性和访问器方法(set和get),可以防止未经授权的修改。
Solution:
错误案例:
//Noncompliant Code Example
public class MyClass {
public static final int SOME_CONSTANT = 0; // Compliant - constants are not checked
public String firstName; // Noncompliant
}
推荐案例:
//Compliant Solution
public class MyClass {
public static final int SOME_CONSTANT = 0; // Compliant - constants are not checked
private String firstName; // Compliant
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
}
例外情况:
因为它们不可修改,所以此规则忽略公共final字段。
4、‘PASSWORD’ detected in this expression, review this potentially hard-coded credential.
错误代码:
private static final String DBPASSWORD = "xxxxxx";// 数据库密码
Reason:
- 由于从已编译的应用程序中提取字符串很容易,因此不应硬编码凭据。这样做,它们几乎肯定会落入攻击者手中。这对于分布式应用程序尤其如此。
凭据应存储在代码之外的受强保护的加密配置文件或数据库中。
建议使用其他凭据字(如“oauthToken”、“secret”、。。。
Solution:
错误案例:
//Noncompliant Code Example
Connection conn = null;
try {
conn = DriverManager.getConnection("jdbc:mysql://localhost/test?" +
"user=steve&password=blue"); // Noncompliant
String uname = "steve";
String password = "blue";
conn = DriverManager.getConnection("jdbc:mysql://localhost/test?" +
"user=" + uname + "&password=" + password); // Noncompliant
java.net.PasswordAuthentication pa = new java.net.PasswordAuthentication("userName", "1234".toCharArray()); // Noncompliant
推荐案例:
//Compliant Solution
Connection conn = null;
try {
String uname = getEncryptedUser();
String password = getEncryptedPass();
conn = DriverManager.getConnection("jdbc:mysql://localhost/test?" +
"user=" + uname + "&password=" + password);
4.1 Remove this hard-coded password.
错误代码:
try {
Class.forName(DBDRIVER);// 注册驱动
conn = DriverManager.getConnection(DBURL,DBUSER, DBPASSWORD);// 获得连接对象
解决方案同4。