簡單聊一聊SQL注入及防止SQL注入
SQL注入
SQL注入是通過操作輸入來修改事先定義好的SQL語句,對用戶輸入的字符串進(jìn)行過濾,轉(zhuǎn)義,限制或處理不嚴(yán)謹(jǐn),導(dǎo)致用戶可以通過輸入精心構(gòu)造的字符串去非法獲取到數(shù)據(jù)庫中的數(shù)據(jù),以達(dá)到執(zhí)行代碼對服務(wù)器進(jìn)行攻擊的方法。
現(xiàn)有一個數(shù)據(jù)庫test中的表user,可以通過賬號name,密碼pass登錄,查看id

登錄代碼
package JDBCtest;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;
/*
* 用戶登錄
*/
public class Demo4 {
public static void main(String[] args) throws Exception {
// 1.加載驅(qū)動
Class.forName("com.mysql.jdbc.Driver");
// 2.創(chuàng)建連接
String url = "jdbc:mysql:///test";
String username = "root";
String password = "1234";
Connection connection = DriverManager.getConnection(url, username, password);
// 接收用戶名密碼
Scanner sc = new Scanner(System.in);
String name = sc.next();
String pass = sc.next();// 3.sql語句
String sql = "Select * from user where name='" + name + "' and pass ='" + pass + "'";
// System.out.println(sql);
// 4.獲取sql對象statement
Statement statement = connection.createStatement();
// 5.執(zhí)行sql語句
ResultSet rs = statement.executeQuery(sql);
// 6.登錄
if (rs.next()) {
System.out.println("登錄成功");
} else {
System.out.println("登錄失敗");
}
// 7.釋放資源
statement.close();
connection.close();
}
}通過表中賬號密碼登錄成功


由于賬號或密碼錯誤登錄失敗


以上可以正確登錄成功或失敗
注意!
如果此時我這樣輸入 【lihua 'or'1'='1】,也成功登錄了,但是數(shù)據(jù)庫沒根本沒有這條數(shù)據(jù)

這是為什么呢?讓我們從代碼里找問題!
String sql = "Select * from user where name='" + name + "' and pass ='" + pass + "'";
為了調(diào)用數(shù)據(jù)庫,使用字符串拼接SQL語句
讓我們打印一下輸入 【lihua 'or'1'='1】的sql語句一探究竟

select語句中的where條件可以看做兩組并列(注意and在前先執(zhí)行,or后執(zhí)行)

由于'1'='1'為TRUE,所以以上語句等價于
肯定會登錄成功!
同理輸入【'or'1'='1'# xxx】也能登陸成功

這是由于#在SQL中是注釋符號,以上語句等價于
,于是就和上述情況一樣了。
附防止sql注入的一些建議
1. 代碼層防止sql注入攻擊的最佳方案就是sql預(yù)編譯
public List<Course> orderList(String studentId){
String sql = "select id,course_id,student_id,status from course where student_id = ?";
return jdbcTemplate.query(sql,new Object[]{studentId},new BeanPropertyRowMapper(Course.class));
}
這樣我們傳進(jìn)來的參數(shù) 4 or 1 = 1就會被當(dāng)作是一個student_id,所以就不會出現(xiàn)sql注入了。
2. 確認(rèn)每種數(shù)據(jù)的類型,比如是數(shù)字,數(shù)據(jù)庫則必須使用int類型來存儲
3. 規(guī)定數(shù)據(jù)長度,能在一定程度上防止sql注入
4. 嚴(yán)格限制數(shù)據(jù)庫權(quán)限,能最大程度減少sql注入的危害
5. 避免直接響應(yīng)一些sql異常信息,sql發(fā)生異常后,自定義異常進(jìn)行響應(yīng)
6. 過濾參數(shù)中含有的一些數(shù)據(jù)庫關(guān)鍵詞
@Component
public class SqlInjectionFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req=(HttpServletRequest)servletRequest;
HttpServletRequest res=(HttpServletRequest)servletResponse;
//獲得所有請求參數(shù)名
Enumeration params = req.getParameterNames();
String sql = "";
while (params.hasMoreElements()) {
// 得到參數(shù)名
String name = params.nextElement().toString();
// 得到參數(shù)對應(yīng)值
String[] value = req.getParameterValues(name);
for (int i = 0; i < value.length; i++) {
sql = sql + value[i];
}
}
if (sqlValidate(sql)) {
throw new IOException("您發(fā)送請求中的參數(shù)中含有非法字符");
} else {
chain.doFilter(servletRequest,servletResponse);
}
}
/**
* 關(guān)鍵詞校驗
* @param str
* @return
*/
protected static boolean sqlValidate(String str) {
// 統(tǒng)一轉(zhuǎn)為小寫
str = str.toLowerCase();
// 過濾掉的sql關(guān)鍵字,可以手動添加
String badStr = "'|and|exec|execute|insert|select|delete|update|count|drop|*|%|chr|mid|master|truncate|" +
"char|declare|sitename|net user|xp_cmdshell|;|or|-|+|,|like'|and|exec|execute|insert|create|drop|" +
"table|from|grant|use|group_concat|column_name|" +
"information_schema.columns|table_schema|union|where|select|delete|update|order|by|count|*|" +
"chr|mid|master|truncate|char|declare|or|;|-|--|+|,|like|//|/|%|#";
String[] badStrs = badStr.split("\\|");
for (int i = 0; i < badStrs.length; i++) {
if (str.indexOf(badStrs[i]) >= 0) {
return true;
}
}
return false;
}
}總結(jié)
到此這篇關(guān)于SQL注入及防止SQL注入的文章就介紹到這了,更多相關(guān)防止SQL注入內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解Navicat Premium 15 無限試用腳本的方法
這篇文章主要介紹了Navicat Premium 15 無限試用腳本的方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2020-11-11
SunlightDB 2017新型區(qū)塊鏈數(shù)據(jù)庫
這篇文章主要為大家詳細(xì)介紹了SunlightDB 2017新型區(qū)塊鏈數(shù)據(jù)庫的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-01-01
SQL利用Function創(chuàng)建長整形的唯一ID示例代碼
這篇文章主要給大家介紹了關(guān)于SQL利用Function創(chuàng)建長整形的唯一ID的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-07-07
ACCESS轉(zhuǎn)SQLSERVER數(shù)據(jù)庫的注意事項
Access承重量太低,當(dāng)你考慮升級到SQL Server時,并不只是個連接字符串需要改變,需要改變的還有很多2007-01-01
時序數(shù)據(jù)庫TDengine寫入查詢的問題分析
最近TDengine很火,本人也一直很早就有關(guān)注,其官方給出的測試性能結(jié)果很喜人,所以一開源,本人就進(jìn)行了相關(guān)調(diào)研,最終發(fā)現(xiàn)還是存在著一定的問題,期待后續(xù)的完善吧2022-03-03

