Java code audit and security vulnerability repair

Java code audit and security vulnerability repair

Open Source: Qi Anxin Code Guard

Official website use

  • Select source code and upload

  • detection

  • View Vulnerabilities

  • details

gitee service use

Under the [Service] item of the project, select [Qianxin Code Guard]

【Create Analysis】

Create a new analysis, select [Detect Branch], support scanning languages: php, java/jsp, python, c/c++, java version supports up to 1.8, click [Submit]

view scan results

https://codescan.qianxin.com/#/login
https://blog.csdn.net/SHELLCODE_8BIT/article/details/129281099
https://blog.csdn.net/qq_36434219/article/details/127659944

Non-open source: Sikeyun looking for starlings

  • details

Types of errors and how to fix them

1. Hardcoded

  • loophole
    public void hardcodedCredentials(String name, String password) {
        if(name.equals("admin") && password.equals("admin")) {
            // Do something
        }
    }

Repair ideas: Do not read sensitive data such as passwords directly from the code. You can use configuration files or database storage to store the data required by the system. When entering data, you can also encrypt the sensitive data before entering the data.

  • Repair method 1
import org.springframework.beans.factory.annotation.Value;

    @Value("${admin.username}")
    private String adminUsername;

    @Value("${admin.password}")
    private String adminPassword;

    public void checkCredentials(String name, String password) {
        if(name.equals(adminUsername) && password.equals(adminPassword)) {
            // Do something
        }
    }
  • Repair method 2
    public void hardcodedCredentials(String name, String password) {
        if (name.equals(System.getenv("ADMIN_NAME")) && password.equals(System.getenv("ADMIN_PASSWORD"))) {
        }
    }

2. Path operations

  • File Vulnerabilities
    public void pathManipulation(HttpServletRequest request, String rootPath) throws FileNotFoundException {
        String filename = request.getParameter("filename");
        String fullFileName = rootPath + filename;
        File downFile = new File(fullFileName);
    }

Idea: Verify the input file and use a safe way to read the file

  • Repair method
import org.apache.commons.io.FileUtils;

    public void pathManipulation(HttpServletRequest request, String rootPath) throws FileNotFoundException {
        String filename = request.getParameter("filename");

        Pattern pattern = Pattern.compile("[\\s\\\\/:\\*\\?\\\"<>\\|]");
        Matcher matcher = pattern.matcher(filename);
        filename = matcher.replaceAll("");

        File downFile = FileUtils.getFile(filename, "dddd");
        if (!downFile.exists()) {
            throw new FileNotFoundException("File not found: " + filename);
        } else {
            // Do something with downFile
        }
    }
  • Stream Vulnerabilities
    public void pathManipulation2(HttpServletRequest request, String rootPath) throws FileNotFoundException {
        String filename = request.getParameter("filename");
        String fullFileName = rootPath + filename;
        InputStream is = new BufferedInputStream(new FileInputStream(fullFileName));
        OutputStream os = new BufferedOutputStream(new FileOutputStream(fullFileName));
    }
  • Repair method
    public void pathManipulation2(HttpServletRequest request, HttpServletResponse response, String rootPath) throws IOException {
        String filename = request.getParameter("filename");
        String fullFileName = rootPath + filename;

        Pattern pattern = Pattern.compile("[\\s\\\\/:\\*\\?\\\"<>\\|]");
        Matcher matcher = pattern.matcher(filename);
        filename = matcher.replaceAll("");

        File f = FileUtils.getFile(filename);

        if(f != null){
            InputStream is = new BufferedInputStream(new FileInputStream(f));
            OutputStream os = new BufferedOutputStream(response.getOutputStream());
            OutputStream os2 = new BufferedOutputStream(new FileOutputStream(f));
        }
    }
  • File encapsulation class vulnerability
import java.io.File;
public class FileUtil extends File {

    static String fileFullPath;

    public FileUtil(String pathname) {
        super(pathname);
        fileFullPath = pathname;
    }

    //其他操作

}

// 使用
FileUtil fileUtil = new FileUtil(fullFileName);
  • Repair method
FileUtil fileUtil2 = (FileUtil) FileUtils.getFile(filename);

https://www.cnblogs.com/jayus/p/11423769.html
https://blog.csdn.net/m0_71745754/article/details/128675164
https://blog.csdn.net/qq_33204709/article/details/127968923
https://blog.csdn.net/qq_41085151/article/details/113525348
https://blog.csdn.net/qq_29384639/article/details/82705421

3. Path manipulation - Zip file entry override

  • loophole
    public void zipEntryOverwrite(ZipEntry entry, String dstFileName) throws Exception {
        File outFile = new File(dstFileName, entry.getName());
        OutputStream outputStream = new FileOutputStream(outFile);
        // Write data to outputStream
    }

Idea: Determine the compressed file path

  • Repair method
    public void zipEntryOverwrite(ZipEntry entry, String dstFileName) throws IOException {
        String entryName = Paths.get(entry.getName()).normalize().toString();
        // Reject entries that try to escape the target directory
        if (entryName.startsWith("..")) {
            throw new IOException("Bad zip entry: " + entry.getName());
        }
        // 创建一个新的文件路径
        String newFilePath = Paths.get(dstFileName, entryName).toString();
        // 创建新文件并获取输出流
        File outFile = new File(newFilePath);
        OutputStream outputStream = new FileOutputStream(outFile);
        // Write data to outputStream
    }

https://www.cnblogs.com/jinqi520/p/9391596.html

4. SQL injection

  • loophole
    public void sqlInjection(String orderId,Connection conn) throws Exception {
        String sql = "From User u on where 1=1";
        if(!orderId.equals("")){
            sql = sql + " and u.id = "+ orderId;
        }
        if(!orderId.equals("")){
            sql = sql + " and u.id like '%"+ orderId + "%'";
        }
        PreparedStatement stmt = conn.prepareStatement(sql);
        ResultSet rs = stmt.executeQuery();
    }

Idea: The user's input cannot be directly nested in the SQL statement, use parameter settings

  • Repair method
    public void sqlInjection(String orderId, Connection conn) throws Exception {
        String sql;
        PreparedStatement stmt;
        ResultSet rs;
        if (!orderId.isEmpty()) {
            sql = "SELECT * FROM User u WHERE u.id = ? ORDER BY id DESC";
            stmt = conn.prepareStatement(sql);
            stmt.setString(1, orderId);
        } else {
            sql = "SELECT * FROM User u ORDER BY id DESC";
            stmt = conn.prepareStatement(sql);
        }
        rs = stmt.executeQuery();
    }
    public void safeSQLExecution(Connection conn, List<String> ids) throws Exception {
        String sql = "SELECT * FROM some_table WHERE id = ?";  // '?' 是一个参数占位符
        PreparedStatement stmt = conn.prepareStatement(sql);
        for (String id : ids) {
            stmt.setString(1, id);  // 使用用户输入替代参数占位符
            ResultSet rs = stmt.executeQuery();
            // 处理结果集...
        }
    }

5. SQL Injection - Hibernate

  • loophole
    @PersistenceContext
    private EntityManager entityManager;

    public void sqlInjectionHibernate(String orderId) {
        String sql = "From User u on where 1=1";
        if(!orderId.equals("")){
            sql = sql + " and u.id = "+ orderId;
        }
        sql = sql + " order by id desc";
        Session session = entityManager.unwrap(Session.class);
        Query query = session.createQuery(sql);
        // Execute the query
    }
  • Repair method
    public void sqlInjectionHibernate(String orderId, Session session) throws Exception {
        String hql = "FROM UserEntity u WHERE 1=1";
        if (!orderId.equals("")) {
            hql = hql + " AND u.id = :orderId";
        }
        hql = hql + " ORDER BY id DESC";

        Query query = session.createQuery(hql);
        if (!orderId.equals("")) {
            // Set the parameter
            query.setParameter("orderId", Integer.parseInt(orderId));
        }
        List<UserEntity> users = query.list();
        // Process the users
    }
    public void sqlInjectionL(List<String> orderIds, Session session) throws Exception {
        String sql = "delete from UserEntity u where u.id in ("+ orderIds +")";
        Query query = session.createQuery(sql);
        query.setParameterList("orderIds", orderIds);
        // Process the result set
    }

6. XML external entity injection, risky XML external entity parsing

  • loophole
    public void xxeInjection(String xmlFilePath) throws Exception {
        // Process the document
        String baseDir = System.getProperty("user.dir");
        File file = new File(baseDir);
        String configFile = file.getParent()+"\\conf\\server.xml";
        XmlUtil xmlut = new XmlUtil();
        String port = getMyPort(configFile);

    }

    public String getMyPort(String xmlFilePath) throws ParserConfigurationException, IOException, SAXException {
        String port = "";
        Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(xmlFilePath);
        Element root = document.getDocumentElement();
        NodeList list = root.getElementsByTagName("service");
        Node ServiceNode = list.item(0);
        list = ServiceNode.getChildNodes();
        // ...
        return port;
    }

Idea: The main entry point for XXE injection is the DTD. The easiest way to prevent XXE vulnerabilities is to disable the DTD of the application, disabling the DTD may not be suitable for all scenarios, you can also use input validation to prevent malicious injection

  • Repair method
    public String getMyPort(String xmlFilePath) throws ParserConfigurationException, IOException, SAXException {
        String port = "";
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

        //REDHAT
        //https://www.blackhat.com/docs/us-15/materials/us-15-Wang-FileCry-The-New-Age-Of-XXE-java-wp.pdf
        dbf.setAttribute(XMLConstants.FEATURE_SECURE_PROCESSING, true);
        dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD,"");
        dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA,"");

        //OWASP
        //https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html
        dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
        dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
        dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
        // Disable external DTDs as well
        dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
        // and these as well, per Timothy Morgan's 2014 paper:"XML Schema, DTD, and Entity Attacks"
        dbf.setXIncludeAware(false);
        dbf.setExpandEntityReferences(false);

        DocumentBuilder db = dbf.newDocumentBuilder();
        Document document = db.parse(xmlFilePath);

        Element root = document.getDocumentElement();
        NodeList list = root.getElementsByTagName("service");
        Node ServiceNode = list.item(0);
        list = ServiceNode.getChildNodes();

        // 获取真正的port,省略
        return port;
    }

https://www.codenong.com/56777287/
https://www.jianshu.com/p/9b4e1bce8da2

7. Empty encryption key

  • loophole
    public void nullEncryptionKey(String key) throws Exception {
        if(key == null) key = "";
    }
  • Repair method
    public void nullEncryptionKey(byte[] input) throws Exception {
        byte[] key = null;
        // An actual encryption key should be used here
        key = "Some real key".getBytes();
        if (key == null || key.length != 16) {
            throw new IllegalArgumentException("Key is invalid");
        }
    }

8. System Information Leakage

  • loophole
    public String systemInformationLeak( String json) {
        PrintWriter w = null;
        w.write(json);

        try {
            // Do something
        } catch (Exception e) {
            e.printStackTrace();
            return e.getMessage();
        }
        return null;
    }
  • Repair method
    public String systemInformationLeak() {
        try {
            // Do something
        } catch (Exception e) {
            Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, e);
            return "An error occurred. Please try again later.";
        }
        return null;
    }

9. Privacy Violation: Serialization of Private Information

  • loophole
public class UserTest implements Serializable {
    private String username;
    private String pwd;
    private String password;
}
  • Repair method 1, using hash encryption
public class UserTest implements Serializable {

    private String username;
    private String pwd;
    private String password;
    public String getPassword() {
        return passwordHash;
    }

    public void setPassword(String password) {
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        this.passwordHash = passwordEncoder.encode(password);
    }
}
  • Repair method 1, delete Serializable directly
public class User {
    private String username;
    private transient String pwd;
    private String passwordHash;
}

Other reference links

https://blog.csdn.net/a3562323/article/details/105389651

Guess you like

Origin blog.csdn.net/qq_23858785/article/details/131253599