JAVA开发中涉及的基础安全问题和解决方法初探
字数 575 2025-08-26 22:11:51

JAVA开发中涉及的基础安全问题和解决方法

SQL注入

漏洞原理

SQL注入是由于未对用户输入进行过滤,直接将用户输入拼接到SQL语句中执行,导致攻击者可以构造恶意SQL语句执行非授权操作。

漏洞示例代码

public String jdbc_sqli_vul(@RequestParam("username") String username) {
    StringBuilder result = new StringBuilder();
    try {
        Connection con = DriverManager.getConnection(url, user, password);
        Statement statement = con.createStatement();
        String sql = "select * from users where username = '" + username + "'"; // 直接拼接用户输入
        ResultSet rs = statement.executeQuery(sql);
        // ...
    } catch (Exception e) {
        logger.error(e.toString());
    }
    return result.toString();
}

安全解决方案

使用预处理语句(PreparedStatement)和参数化查询:

String sql = "select * from users where username = ?";
PreparedStatement st = con.prepareStatement(sql);
st.setString(1, username); // 安全地设置参数
ResultSet rs = st.executeQuery();

错误使用案例

即使使用了PreparedStatement,如果仍然拼接SQL字符串,依然存在风险:

String sql = "select * from users where username = '" + username + "'";
PreparedStatement st = con.prepareStatement(sql); // 错误用法,仍然存在SQL注入

XSS(跨站脚本攻击)

漏洞类型

  1. 反射型XSS:恶意脚本来自当前HTTP请求
  2. 存储型XSS:恶意脚本被存储到服务器(如数据库)中

漏洞示例代码

// 反射型XSS
public static String reflect(String xss) {
    return xss; // 直接返回用户输入
}

// 存储型XSS(存储到cookie)
public String store(String xss, HttpServletResponse response) {
    Cookie cookie = new Cookie("xss", xss);
    response.addCookie(cookie);
    return "Set param into cookie";
}

// 从cookie中读取并展示XSS
public String show(@CookieValue("xss") String xss) {
    return xss;
}

安全解决方案

  1. 转义特殊字符:
public static String encode(String origin) {
    origin = StringUtils.replace(origin, "&", "&");
    origin = StringUtils.replace(origin, "<", "&lt;");
    origin = StringUtils.replace(origin, ">", "&gt;");
    origin = StringUtils.replace(origin, "\"", "&quot;");
    origin = StringUtils.replace(origin, "'", "&#x27;");
    origin = StringUtils.replace(origin, "/", "&#x2F;");
    return origin;
}
  1. 输入验证:
public static String safe(String xss) {
    if (code(xss)=="false"){
        System.out.println("参数不合法");
    }
}
private static String code(String origin){
    if (origin.contains(""+'&')||origin.contains(""+'<')||origin.contains(""+'>')||origin.contains(""+'&')||origin.contains(""+'"')){
        return "false";
    }
    return "true";
}

文件上传漏洞

漏洞示例代码

public String singleFileUpload(@RequestParam("file") MultipartFile file,
                               RedirectAttributes redirectAttributes) {
    try {
        byte[] bytes = file.getBytes();
        Path path = Paths.get(UPLOADED_FOLDER + file.getOriginalFilename());
        Files.write(path, bytes); // 直接保存上传的文件,无任何过滤
    } catch (IOException e) {
        logger.error(e.toString());
    }
    return "redirect:/file/status";
}

安全解决方案

  1. 文件后缀名白名单校验
  2. MIME类型黑名单校验
  3. 文件内容校验
public String uploadPicture(@RequestParam("file") MultipartFile multifile) throws Exception {
    // 1. 校验文件后缀名
    String fileName = multifile.getOriginalFilename();
    String Suffix = fileName.substring(fileName.lastIndexOf("."));
    String[] picSuffixList = {".jpg", ".png", ".jpeg", ".gif", ".bmp", ".ico"};
    boolean suffixFlag = false;
    for (String white_suffix : picSuffixList) {
        if (Suffix.toLowerCase().equals(white_suffix)) {
            suffixFlag = true;
            break;
        }
    }
    if (!suffixFlag) {
        logger.error("[-] Suffix error: " + Suffix);
        return "Upload failed. Illeagl picture.";
    }

    // 2. 校验MIME类型
    String mimeType = multifile.getContentType();
    String[] mimeTypeBlackList = {"text/html", "text/javascript", "application/javascript"};
    for (String blackMimeType : mimeTypeBlackList) {
        if (SecurityUtil.replaceSpecialStr(mimeType).toLowerCase().contains(blackMimeType)) {
            logger.error("[-] Mime type error: " + mimeType);
            return "Upload failed. Illeagl picture.";
        }
    }

    // 3. 校验文件内容
    File excelFile = convert(multifile);
    boolean isImageFlag = isImage(excelFile);
    if (!isImageFlag) {
        logger.error("[-] File is not Image");
        return "Upload failed. Illeagl picture.";
    }

    // 安全保存文件
    byte[] bytes = multifile.getBytes();
    Path path = Paths.get(UPLOADED_FOLDER + multifile.getOriginalFilename());
    Files.write(path, bytes);
    return String.format("You successfully uploaded '%s'", path);
}

XXE(XML外部实体注入)

漏洞示例代码

public String DocumentBuilderVuln01(HttpServletRequest request) {
    String body = WebUtils.getRequestBody(request);
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    DocumentBuilder db = dbf.newDocumentBuilder();
    StringReader sr = new StringReader(body);
    InputSource is = new InputSource(sr);
    Document document = db.parse(is);  // 解析XML,未禁用外部实体
    // ...
}

安全解决方案

禁用DOCTYPE声明和外部实体:

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
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);
DocumentBuilder db = dbf.newDocumentBuilder();

路径遍历漏洞

漏洞示例代码

public String getImage(String filepath) throws IOException {
    File f = new File(filepath);
    if (f.exists() && !f.isDirectory()) {
        byte[] data = Files.readAllBytes(Paths.get(filepath));
        return new String(Base64.encodeBase64(data)); // 直接读取文件,无路径过滤
    }
    return "File doesn't exist or is not a file.";
}

安全解决方案

对路径参数进行过滤:

public static String pathFilter(String filepath) {
    String temp = filepath;
    // 处理URL编码
    while (temp.indexOf('%') != -1) {
        try {
            temp = URLDecoder.decode(temp, "utf-8");
        } catch (Exception e) {
            return null;
        }
    }
    // 禁止相对路径和绝对路径
    if (temp.contains("..") || temp.charAt(0) == '/') {
        return null;
    }
    return filepath;
}

public String getImageSec(String filepath) throws IOException {
    if (SecurityUtil.pathFilter(filepath) == null) {
        return "Bad boy. Illegal file path.";
    }
    return getImgBase64(filepath);
}

总结

  1. SQL注入:使用预处理语句和参数化查询
  2. XSS:对输出进行HTML编码或验证输入
  3. 文件上传:校验文件后缀、MIME类型和文件内容
  4. XXE:禁用外部实体和DOCTYPE声明
  5. 路径遍历:过滤路径中的特殊字符和相对路径

安全开发应该遵循"不信任任何输入"的原则,对所有用户输入进行严格的验证和过滤。

JAVA开发中涉及的基础安全问题和解决方法 SQL注入 漏洞原理 SQL注入是由于未对用户输入进行过滤,直接将用户输入拼接到SQL语句中执行,导致攻击者可以构造恶意SQL语句执行非授权操作。 漏洞示例代码 安全解决方案 使用预处理语句(PreparedStatement)和参数化查询: 错误使用案例 即使使用了PreparedStatement,如果仍然拼接SQL字符串,依然存在风险: XSS(跨站脚本攻击) 漏洞类型 反射型XSS :恶意脚本来自当前HTTP请求 存储型XSS :恶意脚本被存储到服务器(如数据库)中 漏洞示例代码 安全解决方案 转义特殊字符: 输入验证: 文件上传漏洞 漏洞示例代码 安全解决方案 文件后缀名白名单校验 MIME类型黑名单校验 文件内容校验 XXE(XML外部实体注入) 漏洞示例代码 安全解决方案 禁用DOCTYPE声明和外部实体: 路径遍历漏洞 漏洞示例代码 安全解决方案 对路径参数进行过滤: 总结 SQL注入 :使用预处理语句和参数化查询 XSS :对输出进行HTML编码或验证输入 文件上传 :校验文件后缀、MIME类型和文件内容 XXE :禁用外部实体和DOCTYPE声明 路径遍历 :过滤路径中的特殊字符和相对路径 安全开发应该遵循"不信任任何输入"的原则,对所有用户输入进行严格的验证和过滤。