最近项目遇到一次整型溢出攻击
有一个功能, 玩家购买 num 个物品. 每个物品花费 14 货币. 客户端限制玩家只能购买 1-9999 个该物品.
但是某玩家通过技术手段, 获得了客户端的运行权限. 于是发送协议购买该物品 306783379 个
于是服务器收到请求进行以下处理
调用扣除货币数量 cost
val num = message.getInt("num") // 获得客户端发送来的 306783379
val cost = num * produc.price // 这里没有校验物品的数量就直接计算总价了. 所以总价是 306783379 * 14
调用发放物品数量 num
这一眼看起来没什么问题, 但是扣除时发现只扣除了他 10 货币. 猛然发现 num 是 int 型的, 所以 int 306783379 乘以 14 后溢出了, 结果是 10
再查发现代码里非常多地方有这种直接是 num * price 的, 于是想以最小的改动来封禁这个 bug.
最开始的想法是写一个函数, 参数是相乘的 2 个数, 如果越界就抛异常. a * b 改为 Util.safeMultiple(a, b) 但发现这么改代码看起来有点蛋疼. 后来决定使用隐式转换
定义个 IntChecker , 和 implicit 类 SafeInt,
做个测试:
package thomaswong025.example1
/**
* Created by Administrator on 2018/1/9/009.
*/
object IntChecker {
implicit class SafeInt(val a: Int) {
def`safe * ` (b: Int) = {
val r = BigDecimal(a) * b
if (r.isValidInt) r.toInt
else throw new RuntimeException(s " $a * $b out of int range")
}
}
}
找到其他需要使用安全乘法的地方 把乘号改成 `safe*`, 记得在顶部import 包路径.IntChecker._即可
package thomaswong025.example1
import thomaswong025.example1.IntChecker._
object Test {
def main(args: Array[String]) {
val a = 306783379
val b = 14
println(a * b) //输出10
println(a `safe*` b) //抛异常
}
}
如果需要安全加减等操作,也可以直接自己在SafeInt类里加上
注意: 改成 `safe*` 后, 函数优先级比原来的 * 降低了, 跟其他函数调用的优先级一样. 所以 如果代码里有 a * b / c 变成 a `safe*` b / c 之后, 一定要记得加括号 (a `safe*` b) / c
来源: http://www.bubuko.com/infodetail-2461201.html