java代码审计和安全漏洞修复
本文目录
- java代码审计和安全漏洞修复
- 开源:奇安信代码卫士
- 官网使用
- gitee服务使用
- 非开源:思客云找八哥
- 错误类型以及修改方法
- 1.硬编码
- 2. 路径操作
- 3. 路径操作 - Zip文件条目覆盖
- 4. SQL注入
- 5. SQL注入 - Hibernate
- 6. XML外部实体注入,有风险的XML外部实体解析
- 7. 空加密密钥
- 8. 系统信息泄露
- 9. 私密违反:私密信息序列化
- 其他参考链接
开源:奇安信代码卫士
官网使用
-
选择源码并上传
-
检测
-
查看漏洞
-
详情
gitee服务使用
在项目的【服务】项下,选择【奇安信代码卫士】
【创建分析】
新建分析,选择【检测分支】,支持扫描的语言:php、java/jsp、python、c/c++,java 版本最高支持 1.8,点击【提交】
查看扫描结果
https://codescan.qianxin.com/#/login
https://blog.csdn.net/SHELLCODE_8BIT/article/details/129281099
https://blog.csdn.net/qq_36434219/article/details/127659944
非开源:思客云找八哥
- 详情
错误类型以及修改方法
1.硬编码
- 漏洞
public void hardcodedCredentials(String name, String password) {
if(name.equals("admin") && password.equals("admin")) {
// Do something
}
}
修复思路:密码等敏感数据不要直接从代码中读取,可以使用配置文件或数据库存储的方式来存储系统所需的数据,录入数据时,还可以在对敏感数据做加密处理之后再进行数据的录入
- 修复方法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
}
}
- 修复方法2
public void hardcodedCredentials(String name, String password) {
if (name.equals(System.getenv("ADMIN_NAME")) && password.equals(System.getenv("ADMIN_PASSWORD"))) {
}
}
2. 路径操作
- File漏洞
public void pathManipulation(HttpServletRequest request, String rootPath) throws FileNotFoundException {
String filename = request.getParameter("filename");
String fullFileName = rootPath + filename;
File downFile = new File(fullFileName);
}
思路:对输入文件进行验证,使用安全的读取文件的方法
- 修复方法
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漏洞
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));
}
- 修复方法
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封装类漏洞
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);
- 修复方法
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. 路径操作 - Zip文件条目覆盖
- 漏洞
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
}
思路:判断压缩文件路径
- 修复方法
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注入
- 漏洞
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();
}
思路:用户的输入不能直接嵌套在SQL语句中,使用参数设置
- 修复方法
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注入 - Hibernate
- 漏洞
@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
}
- 修复方法
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外部实体注入,有风险的XML外部实体解析
- 漏洞
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;
}
思路:XXE 注入的主要入口点是 DTD。防止 XXE 漏洞的最简单方法是禁用应用程序的 DTD,禁用 DTD 可能并不适用于所有场景,也可以使用输入验证来防止恶意注入
- 修复方法
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. 空加密密钥
- 漏洞
public void nullEncryptionKey(String key) throws Exception {
if(key == null) key = "";
}
- 修复方法
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. 系统信息泄露
- 漏洞
public String systemInformationLeak( String json) {
PrintWriter w = null;
w.write(json);
try {
// Do something
} catch (Exception e) {
e.printStackTrace();
return e.getMessage();
}
return null;
}
- 修复方法
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. 私密违反:私密信息序列化
- 漏洞
public class UserTest implements Serializable {
private String username;
private String pwd;
private String password;
}
- 修复⽅式1,采⽤hash加密
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);
}
}
- 修复⽅式1,直接删除Serializable
public class User {
private String username;
private transient String pwd;
private String passwordHash;
}
其他参考链接
https://blog.csdn.net/a3562323/article/details/105389651