java.lang.security.audit.md5-used-as-password.md5-used-as-password

profile photo of returntocorpreturntocorp
Author
unknown
Download Count*

It looks like MD5 is used as a password hash. MD5 is not considered a secure password hash because it can be cracked by an attacker in a short amount of time. Use a suitable password hashing function such as PBKDF2 or bcrypt. You can use javax.crypto.SecretKeyFactory with SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1") or, if using Spring, org.springframework.security.crypto.bcrypt.

Run Locally

Run in CI

Defintion

rules:
  - id: md5-used-as-password
    languages:
      - java
    severity: WARNING
    message: It looks like MD5 is used as a password hash. MD5 is not considered a
      secure password hash because it can be cracked by an attacker in a short
      amount of time. Use a suitable password hashing function such as PBKDF2 or
      bcrypt. You can use `javax.crypto.SecretKeyFactory` with
      `SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1")` or, if using Spring,
      `org.springframework.security.crypto.bcrypt`.
    metadata:
      category: security
      technology:
        - java
        - md5
      references:
        - https://tools.ietf.org/id/draft-lvelvindron-tls-md5-sha1-deprecate-01.html
        - https://github.com/returntocorp/semgrep-rules/issues/1609
        - https://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#SecretKeyFactory
        - https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/crypto/bcrypt/BCryptPasswordEncoder.html
      owasp:
        - A03:2017 - Sensitive Data Exposure
        - A02:2021 - Cryptographic Failures
      cwe:
        - "CWE-327: Use of a Broken or Risky Cryptographic Algorithm"
      subcategory:
        - vuln
      likelihood: HIGH
      impact: MEDIUM
      confidence: MEDIUM
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
    mode: taint
    pattern-sources:
      - patterns:
          - pattern-inside: |
              $TYPE $MD = MessageDigest.getInstance("MD5");
              ...
          - pattern: $MD.digest(...);
    pattern-sinks:
      - patterns:
          - pattern: $MODEL.$METHOD(...);
          - metavariable-regex:
              metavariable: $METHOD
              regex: (?i)(.*password.*)

Examples

md5-used-as-password.java

package website.controller;

import website.RandomUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.hibernate.service.spi.ServiceException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import java.security.MessageDigest;

import java.util.List;
import java.util.Optional;

@RestController
@RequestMapping("/user")
public class UserController extends BaseController {

    private final UserService service;

    @Autowired
    public UserController(UserService service) {
        this.service = service;
    }

    @RequestMapping(value = "addUser", method = RequestMethod.POST)
    public Result addUser(@RequestBody UserModel user) {
        UserModel userModel = service.findUserByEmail(user.getEmail());
        if (userModel != null) {
            return new Result<>(CodeConst.USER_REPEAT.getResultCode(), CodeConst.USER_REPEAT.getMessage());
        }

        String salt = RandomUtil.createSalt();
        MessageDigest md = MessageDigest.getInstance("MD5");
        md.update(user.getPassword());

        // ruleid: md5-used-as-password
        user.setPassword(md.digest(), salt);

        user.setValidateCode(Md5Util.encode(user.getEmail(), ""));
        user.setSalt(salt);
        service.addUser(user);
        return new Result<>(user);
    }

    @RequestMapping(value = "addUserOk", method = RequestMethod.POST)
    public Result addUserOk(@RequestBody UserModel user) {
        UserModel userModel = service.findUserByEmail(user.getEmail());
        if (userModel != null) {
            return new Result<>(CodeConst.USER_REPEAT.getResultCode(), CodeConst.USER_REPEAT.getMessage());
        }

        String salt = RandomUtil.createSalt();
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        md.update(user.getPassword());

        // ok: md5-used-as-password
        user.setPassword(md.digest(), salt);

        user.setValidateCode(Md5Util.encode(user.getEmail(), ""));
        user.setSalt(salt);
        service.addUser(user);
        return new Result<>(user);
    }
}