代码质量管理-安全问题

1、Use a logger to log this exception.2、Add password protection to this database3、Make this “public static map” field finalMake map a static final constant or non-public and provide accessors if needed.4、’PASSWORD’ detected in this expression, review this potentially hard-coded credential.4.1 Remove this hard-coded password.

自动化持续代码质量监测工具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。