国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

用javaPreparedStatement就不用擔心sql注入了嗎?

2019-11-14 15:38:19
字體:
來源:轉載
供稿:網友

     先感慨下,好久沒寫博客了,一是工作太忙,二是身體不太給力,好在終于查清病因了,趁著今天閑下來,迫不及待與讀者交流,最后忠告一句:身體是活著的本錢!

     言歸正傳,對java有了解的同學基本上都體驗過JDBC,基本都了解PReparedStatement,PreparedStatement相比Statement基本解決了SQL注入問題,而且效率也有一定提升。

     關于PreparedStatement和Statement其他細節我們不討論,只關心注入問題。無論讀者是老鳥還是菜鳥,都需要問一下自己,PreparedStatement真的百分百防注入嗎?

     接下來我們研究一下PreparedStatement如何防止注入,本文以MySQL數據庫為例。

     為了避免篇幅過長,我這里只貼代碼片段,希望讀者能有一定的基礎。

1 String sql = "select * from goods where min_name = ?";  // 含有參數2 PreparedStatement st = conn.prepareStatement(sql);3 st.setString(1, "兒童"); // 參數賦值4 System.out.println(st.toString()); //com.mysql.jdbc.JDBC4PreparedStatement@d704f0: select * from goods where min_name = '兒童'

     這段代碼屬于JDBC常識了,就是簡單的根據參數查詢,看不出什么端倪,但假如有人使壞,想注入一下呢?

1 String sql = "select * from goods where min_name = ?";  // 含有參數2 PreparedStatement st = conn.prepareStatement(sql);3 st.setString(1, "兒童'"); // 參數賦值4 System.out.println(st.toString()); //com.mysql.jdbc.JDBC4PreparedStatement@d704f0: select * from goods where min_name = '兒童/''

     簡單的在參數后邊加一個單引號,就可以快速判斷是否可以進行SQL注入,這個百試百靈,如果有漏洞的話,一般會報錯。

     之所以PreparedStatement能防止注入,是因為它把單引號轉義了,變成了/',這樣一來,就無法截斷SQL語句,進而無法拼接SQL語句,基本上沒有辦法注入了。

     所以,如果不用PreparedStatement,又想防止注入,最簡單粗暴的辦法就是過濾單引號,過濾之后,單純從SQL的角度,無法進行任何注入。

     其實,剛剛我們提到的是String參數類型的注入,大多數注入,還是發生在數值類型上,幸運的是PreparedStatement為我們提供了st.setInt(1, 999);這種數值參數賦值API,基本就避免了注入,因為如果用戶輸入的不是數值類型,類型轉換的時候就報錯了。

     好,現在讀者已經了解PreparedStatement會對參數做轉義,接下來再看個例子。

1 String sql = "select * from goods where min_name = ?";  // 含有參數2 PreparedStatement st = conn.prepareStatement(sql);3 st.setString(1, "兒童%"); // 參數賦值4 System.out.println(st.toString()); //com.mysql.jdbc.JDBC4PreparedStatement@8543aa: select * from goods where min_name = '兒童%'

     我們嘗試輸入了一個百分號,發現PreparedStatement竟然沒有轉義,百分號恰好是like查詢的通配符。

     正常情況下,like查詢是這么寫的:

1 String sql = "select * from goods where min_name like ?";  // 含有參數2 st = conn.prepareStatement(sql);3 st.setString(1, "兒童" + "%"); // 參數賦值4 System.out.println(st.toString()); //com.mysql.jdbc.JDBC4PreparedStatement@8543aa: select * from goods where min_name like '兒童%'

     查詢min_name字段以"兒童"開頭的所有記錄,其中"兒童"二字是用戶輸入的查詢條件,百分號是我們自己加的,怎么可能讓用戶輸入百分號嘛!等等!如果用戶非常聰明,偏要輸入百分號呢?

String sql = "select * from goods where min_name like ?";  // 含有參數st = conn.prepareStatement(sql);st.setString(1, "%兒童%" + "%"); // 參數賦值System.out.println(st.toString()); //com.mysql.jdbc.JDBC4PreparedStatement@8543aa: select * from goods where min_name like '%兒童%%'

     聰明的用戶直接輸入了"%兒童%",整個查詢的意思就變了,變成包含查詢。實際上不用這么麻煩,用戶什么都不輸入,或者只輸入一個%,都可以改變原意。

     雖然此種SQL注入危害不大,但這種查詢會耗盡系統資源,從而演化成拒絕服務攻擊。

     那如何防范呢?筆者能想到的方案如下:

        

          ·直接拼接SQL語句,然后自己實現所有的轉義操作。這種方法比較麻煩,而且很可能沒有PreparedStatement做的好,造成其他更大的漏洞,不推薦。

          ·直接簡單暴力的過濾掉%。筆者覺得這方案不錯,如果沒有嚴格的限制,隨便用戶怎么輸入,既然有限制了,就干脆嚴格一些,干脆不讓用戶搜索%,推薦。

        

     目前做搜索,只要不是太差的公司,一般都有自己的搜索引擎(例如著名的java開源搜索引擎solr),很少有在數據庫中直接like的,筆者并不是想在like上鉆牛角尖,而是提醒讀者善于思考,每天都在寫著重復的代碼,卻從來沒有停下腳步細細品味。

     有讀者可能會問,為什么我們不能手動轉義一下用戶輸入的%,其他的再交給PreparedStatement轉義?這個留作思考題,動手試一下就知道為什么了。

     注意,JDBC只是java定義的規范,可以理解成接口,每種數據庫必須有自己的實現,實現之后一般叫做數據庫驅動,本文所涉及的PreparedStatement,是由MySQL實現的,并不是JDK實現的默認行為,也就是說,不同的數據庫表現不同,不能一概而論。

 


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 莲花县| 宁都县| 乌鲁木齐市| 邵阳市| 尼玛县| 海伦市| 保康县| 泸定县| 曲靖市| 黄梅县| 柘荣县| 大安市| 靖安县| 阿图什市| 平果县| 博爱县| 津市市| 内丘县| 赞皇县| 登封市| 甘德县| 静海县| 额尔古纳市| 龙门县| 韩城市| 小金县| 永清县| 鄂托克旗| 额尔古纳市| 纳雍县| 龙里县| 龙泉市| 宣化县| 潜江市| 阿巴嘎旗| 巫山县| 永德县| 得荣县| 亳州市| 墨竹工卡县| 合肥市|