You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin Exposed:如何创建预准备语句或规避SQL注入?

安全处理Kotlin Exposed查询中的用户参数,防范SQL注入

嘿,刚好对Kotlin Exposed的参数安全这块熟得很,来给你捋清楚!

首先要给你吃个定心丸:Exposed的DSL查询默认就是用预准备语句处理参数的,完全不需要你手动去构建预准备语句框架——它底层会自动把你传入的参数作为绑定变量,而不是直接拼进SQL字符串里,从根源上避免了SQL注入风险。

你的现有代码其实已经是安全的

看你这段代码:

private fun accountInfo(msg: AccountInfoMsg) { 
    transaction { 
        val accountInfo = UserAccount.wrapRow(
            Account.innerJoin(Account_Banned)
                .select { 
                    Account.email.eq(msg.login.toLowerCase()) and (Account.id eq Account_Banned.accountId) 
                }.single()
        ) 
    } 
}

这里你用Account.email.eq(msg.login.toLowerCase())传递用户输入的参数,Exposed会自动把msg.login.toLowerCase()的值作为预准备语句的占位符参数,生成的SQL类似这样(底层逻辑):

SELECT ... FROM Account INNER JOIN Account_Banned ON ... WHERE Account.email = ? AND Account.id = Account_Banned.accountId

然后把msg.login.toLowerCase()的值绑定到?这个占位符上,完全不会有SQL注入的问题。

需要避免的危险操作

唯一会引入SQL注入的情况,是你手动拼接字符串到查询语句中,比如错误地使用SqlExpressionBuilder.raw直接拼参数:

// 危险!不要这么做!
select { raw("Account.email = '${msg.login.toLowerCase()}'") }

这种写法会把用户输入直接拼进SQL,才会被注入攻击利用。只要你坚持用Exposed提供的DSL方法(比如eq、like、inList等)来传递参数,就绝对安全。

额外的优化建议

  1. 处理single()的异常:single()会在查询结果为空或超过一条时抛出异常,建议用singleOrNull()更稳妥,然后做空值判断:
val accountRow = Account.innerJoin(Account_Banned)
    .select { 
        Account.email.eq(msg.login.toLowerCase()) and (Account.id eq Account_Banned.accountId) 
    }.singleOrNull()

accountRow?.let { row ->
    val accountInfo = UserAccount.wrapRow(row)
    // 处理账号信息
} ?: run {
    // 处理未找到记录的情况
}
  1. 提前校验输入:虽然Exposed已经防注入,但对用户输入做业务校验(比如检查邮箱格式)还是很有必要的,能减少无效查询和异常情况。

内容的提问来源于stack exchange,提问作者nllsdfx

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 11:09:09