# SQL Injection ## 概述 使用者透過介面輸入非法的字串,導致 __SQL__ 被重新組合成非預期的 __SQL__,達到不被允許的目的。 ## 情境 查詢訂單 ### code ``` java public Order find(String id,Long userId){ String sql = "select * from order where id ='"+id+"' and user_id = "+userId; ResultSet resultSet = connection.createStatement().executeQuery(sql); } ``` ### 正常輸入 id = "xxxx0001"; ```sql select * from `order` where id = 'xxxx0001' and user_id = 1; ``` ### 不正常輸入 id = "' or 0=0 -- "; ```sql select * from `order` where id = '' or 0=0 -- ' and user_id = 1; ``` ## 原理 利用字串拼接組合 __SQL__ 的程式碼,在字串值中,使用 __'__ 特殊符號結束字串並注入新的指令。 ## 解決方法 ### 錯誤 * 將特殊符號取代 * 譬如將 __'__ 取代為 __"__,則文字 __I'am__ 就會變成 __I"am__ ,汙染使用者原始輸入的資料。 [剛好看到血淋淋的例子](https://ithelp.ithome.com.tw/articles/10189201) * 遇到特殊符號返回錯誤 * 等於告訴人家,我不懂 __SQL Injection__。 ### 正確 * 使用 __PreparedStatement__ 但是實作原理與下方一樣,利用 __StringUtils.escapeBytes__ 讓特殊符號失效。 ``` java public Order find(String id,Long userId){ String sql = "select * from `order` where id =? and user_id = ?"; PreparedStatement ps = connection.prepareStatement(sql); ps.setString(1,id); ps.setLong(2,userId); // (id,userId) } ``` 實際上,在沒有設定 __cachePrepStmts__ 跟 __useServerPrepStmts__ 時,__SQL__ 會在本地組裝好,才發送給 __DB__ ```sql select * from `order` where id = 'xxxx0001' and user_id = 1; ``` * 使 __'__ 符號失效 ```java String id = "' or 0=0 -- "; id = id.replaceAll("'","''"); // 變為 "'' or 0=0 -- " // 使用跳脫字元 id = id.replaceAll("'","\\'"); // 變為 "\' or 0=0 -- " ``` __'__ 則會被判定為純字串 ```sql select * from `order` where id = ''' or 0=0 -- ' and user_id = 1; select * from `order` where id = '\' or 0=0 -- ' and user_id = 1; select '\' or 0=0 -- ' ; select ''' or 0=0 -- ' ; ``` __出處__ 參考 mysql-connector-j [StringUtils.escapeBytes](https://github.com/mysql/mysql-connector-j/blob/805f872a57875f311cb82487efcfb070411a3fa0/src/main/core-api/java/com/mysql/cj/util/StringUtils.java#L1822) ## 總結 * 官方源碼有教利用 __\\__ 跳脫字元,讓特殊符號失效。 * 替換時機點,應在執行 __SQL__ 前,否則可能因為流程混亂,導致資料被汙染。 * __PreparedStatement__ 職責不是處理 __SQL Injection__,另有大用。 * https://freedocs.mi.hdm-stuttgart.de/sectPreparedStatements.html
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up