1. 程式人生 > >mybatis字符串轉義問題

mybatis字符串轉義問題

轉義 string類 輸入 log 參數傳遞 sta 報錯 strong string

問題描述

@Select("select * from account order by #{orderBy} #{orderRule} limit #{start},#{offset}")
public List<Account> getAccountList(@Param("orderBy") String orderBy, @Param("orderRule") String orderRule,
    @Param("start) int start, @Param("offset") int offset);

如上代碼所示,在執行查詢操作時,為了能夠與前端聯動進行排序,直接在SQL參數中傳遞排序字段和排序規則。
但是,在調試時偶然發現,當傳遞的“orderBy”值為不存在的字段時,竟然不會報錯!!!
經過進一步調試發現,實際上並不會按照預期的排序規則返回數據列表!!!

原因追蹤

設置log4j的日誌級別為DEBUG後發現,最終執行的SQL語句是一個預編譯操作,mybatis輸出日誌如下:

==>  Preparing: select * from account order by ? ? limit ?, ? 
==> Parameters: loginName(String), DESC(String), 0(Integer), 50(Integer)

很顯然,傳遞的參數loginName和DESC是作為字符串處理的。
也就是說,很有可能mybatis對String類型的參數會進行轉換。舉個例子:傳遞的String參數為loginName,最終在SQL語句執行時為:‘loginName‘。
再進一步驗證,如果在SQL語句中傳遞的排序字段不是字段名loginName,而是‘loginName‘時,是不會按照排序規則返回數據的,並且也不會報錯!
追溯mybatis官方文檔發現:默認情況下,使用#{}格式的語法會導致mybatis對字符串進行修改或轉義!!!
技術分享圖片


詳見:http://www.mybatis.org/mybatis-3/zh/sqlmap-xml.html#select

解決問題

將參數傳遞的語法格式#{}修改為${},即:

@Select("select * from account order by ${orderBy} ${orderRule} limit #{start},#{offset}")
public List<Account> getAccountList(@Param("orderBy") String orderBy, @Param("orderRule") String orderRule,
    @Param
("start) int start, @Param("offset") int offset);

觀察mybatis日誌輸出:

==>  Preparing: select * from account order by login_name DESC limit ?, ? 
==> Parameters: 0(Integer), 50(Integer)

此時,對於使用${}格式引用的參數,mybatis直接在SQL語句中插入一個不改變的字符串,而不再作為一個預編譯參數處理。
註意:
以這種方式接受從用戶輸出的內容並提供給語句中不變的字符串是不安全的,會導致潛在的SQL註入攻擊,因此要麽不允許用戶輸入這些字段,要麽自行轉義並檢驗。

總結

如果只是想直接在SQL語句中插入一個不改變的字符串,比如,像ORDER BY,可以使用${}引用參數:ORDER BY ${columnName},這裏mybatis不會修改或轉義字符串。

mybatis字符串轉義問題