每個語言都有自己的資料庫框架或庫,無論是哪種語言,哪種庫,它們在資料庫防註入方面使用的技術原理無外乎下麵介紹的幾種方法。 一、特殊字元轉義處理 Mysql特殊字元指在mysql中具有特殊含義的字元,除了 和`_`是mysql特有的外,其他的和我們在C語句中接觸的特殊字元一樣。 |特殊字元|轉義字元| ...
每個語言都有自己的資料庫框架或庫,無論是哪種語言,哪種庫,它們在資料庫防註入方面使用的技術原理無外乎下麵介紹的幾種方法。
一、特殊字元轉義處理
Mysql特殊字元指在mysql中具有特殊含義的字元,除了%
和_
是mysql特有的外,其他的和我們在C語句中接觸的特殊字元一樣。
特殊字元 | 轉義字元 | 特殊意義 |
---|---|---|
\0 |
\\0 |
字元串結束符NUL |
' |
\' |
單引號 |
" |
\" |
雙引號 |
\b |
\\b |
退格 |
\n |
\\n |
換行 |
\r |
\\r |
回車 |
\Z |
\\Z |
Control+Z |
\ |
\\ |
反斜杠 |
% |
\% |
百分號,模糊查詢中匹配任意個任意字元 |
_ |
\_ |
下劃線,模糊查詢中匹配單個任意字元 |
mysql C API提供了mysql_real_escape_string
函數對轉義字元進行處理,但根據實際經驗,在使用該API時會產生諸多問題。
因此自己實現了一個類似的函數:
std::string MysqlEscapeString(const std::string &strSql) {
size_t iSrcSize = strSql.size();
std::string strDest;
for (size_t i = 0; i < iSrcSize; i++) {
char ch = strSql[i];
switch (ch)
{
case '\0':
strDest.append("\\0");
break;
case '\n':
strDest.append("\\n");
break;
case '\r':
strDest.append("\\r");
break;
case '\'':
strDest.append("\\'");
break;
case '"':
strDest.append("\\\"");
break;
case '\\':
strDest.append("\\\\");
break;
case '%':
strDest.append("\\%");
break;
case '_':
strDest.append("\\_");
break;
default:
strDest.append(1, ch);
break;
}
}
return strDest;
}
對於%
和_
這2個只在模糊查詢條件中有特殊含義,而在普通字元串中沒有其他含義的字元,需要根據字元使用在SQL語句中的具體位置來決定是否需要處理。如我們要查詢memberName包含t_st的用戶信息:
select * from member where memberName like '%t_st%;
如果不對_
進行轉義處理則會查詢出:
test
tast
tbst
t_st
二、Prepared SQL Statement(預處理語句)
SET @sql = "SELECT * FROM member WHERE memberName like ?";
SET @param = '%t_st%';
PREPARE stmt FROM @sql;
EXECUTE stmt using @param;
DEALLOCATE PREPARE stmt;
使用這種方法需要註意以下2點:
1) ?
占位符不能用在字元串中,上面例子如果寫成下麵這樣是錯誤的。
SET @sql = "SELECT * FROM member WHERE memberName like '%?%'";
SET @param = 't_st';
PREPARE stmt FROM @sql;
EXECUTE stmt using @param;
DEALLOCATE PREPARE stmt;
2) EXECUTE stmt USING @param;
中使用的@param變數,是會話級別的變數。該變數的作用域至整個連接,連接斷開之後該變數才會釋放。重覆使用相同變數時要留意了。