整理些平时不好的coding习惯导致的bug📝
1、包装类型导致的NPE
处理项目的一个bug,看日志是发生了空指针,相关代码如下:
@Data
public class Dto {
private Integer offset;
private Integer limit;
}
if (dto.getLimit() < 0 || dto.getLimit() > 100) {
throw new RuntimeException("参数非法");
}
这里对外API文档写的offset和limit有默认值0和20,但实际代码里并未赋值,这里用的是int的包装类,不传时,默认值为null,而下面 < 0 的比较,会触发自动拆箱,调用Integer对象的intValue()方法,因此,空指针
2、xxApiWrapper命名
发现一个类命名的单词,wrapper,用它结尾命名一个封装📦类,很不错
/**
* 封装调用xx系统的API
*/
public class ServiceApiWrapper {
}
3、@see注释
有时候,一些字段是枚举类型,但Dto类中我们更想用String,此时,可以@see 跟一个全类名,方便点击跳转到对应的类上:
/**
* @see com.llg.common.SourceTypeEnum
*/
private String sourceType;
4、MySQL模糊匹配特殊字符bug
用户反馈有个模糊查询,输入_
下划线,返回的有带-
中划线的结果,debug到对应位置的代码:
criteria.andCondition("upper(group_id) like upper('%" + searchKey + "%')");
这里很明显是用户输入的下划线被当成通配符了,作用是匹配单个字符,对于这种情况,要考虑两个点:
- SQL注入
- 特殊字符
字符 | 类型 | 含义 |
---|---|---|
% | 通配符 | 匹配任意数量字符(包括0个) |
_ | 通配符 | 匹配单个字符 |
\ | 转义符 | 取消后续字符的特殊含义 |
永远不要直接拼接用户输入到你的SQL中,对于特殊字符,用这个工具类处理一下,加转义符,取消后面字符的特殊含义:
public class SqlUtil {
// https://dev.mysql.com/doc/refman/5.7/en/string-comparison-functions.html#operator_like
public static String escapeLikeValue(String value) {
if (value == null) {
return null;
}
return value
.replace("\\", "\\\\")
.replace("%", "\\%")
.replace("_", "\\_");
}
}
对于SQL注入,其实最好的就是预处理,SQL模板化,让SQL和传入的值分开,但这里项目用了tk mybatis框架,考虑加个正则表达式拦一下,能解决一部分,但并不是最优解:
private static final Pattern RISK_SQL = Pattern.compile("[\\s#/*'\"]");
if (RISK_SQL.matcher(searchKey).find()) {
throw new RuntimeException("输入非法");
}
但这么改其实漏洞🕳️也不少,比如union 或者结束; 搭配Drop table等等:
SELECT * FROM users WHERE id = 1 UNION SELECT password FROM users
'); DROP TABLE x; --
总之,这种拼接SQL的,要特别注意SQL注入导致数据泄漏或者数据被删的问题。