赞
踩
就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。具体来说,它是利用现有应用程序,将(恶意)的SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句。
1.判断是否存在注入,注入是字符型还是数字型
2.猜解SQL查询语句中的字段数
3.确定回显位置
4.获取当前数据库
5.获取数据库中的表
6.获取表中的字段名
7.得到数据
- <?php
-
- if( isset( $_REQUEST[ 'Submit' ] ) ) {
- // Get input
- $id = $_REQUEST[ 'id' ];
-
- switch ($_DVWA['SQLI_DB']) {
- case MYSQL:
- // Check database
- $query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
- $result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
-
- // Get results
- while( $row = mysqli_fetch_assoc( $result ) ) {
- // Get values
- $first = $row["first_name"];
- $last = $row["last_name"];
-
- // Feedback for end user
- $html .= "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
- }
-
- mysqli_close($GLOBALS["___mysqli_ston"]);
- break;
- case SQLITE:
- global $sqlite_db_connection;
-
- #$sqlite_db_connection = new SQLite3($_DVWA['SQLITE_DB']);
- #$sqlite_db_connection->enableExceptions(true);
-
- $query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
- #print $query;
- try {
- $results = $sqlite_db_connection->query($query);
- } catch (Exception $e) {
- echo 'Caught exception: ' . $e->getMessage();
- exit();
- }
-
- if ($results) {
- while ($row = $results->fetchArray()) {
- // Get values
- $first = $row["first_name"];
- $last = $row["last_name"];
-
- // Feedback for end user
- $html .= "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
- }
- } else {
- echo "Error in fetch ".$sqlite_db->lastErrorMsg();
- }
- break;
- }
- }
-
- ?>
没有对用户输入进行任何过滤或转义,直接注入即可
- <?php
-
- if( isset( $_POST[ 'Submit' ] ) ) {
- // Get input
- $id = $_POST[ 'id' ];
-
- $id = mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $id);
-
- switch ($_DVWA['SQLI_DB']) {
- case MYSQL:
- $query = "SELECT first_name, last_name FROM users WHERE user_id = $id;";
- $result = mysqli_query($GLOBALS["___mysqli_ston"], $query) or die( '<pre>' . mysqli_error($GLOBALS["___mysqli_ston"]) . '</pre>' );
-
- // Get results
- while( $row = mysqli_fetch_assoc( $result ) ) {
- // Display values
- $first = $row["first_name"];
- $last = $row["last_name"];
-
- // Feedback for end user
- $html .= "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
- }
- break;
- case SQLITE:
- global $sqlite_db_connection;
-
- $query = "SELECT first_name, last_name FROM users WHERE user_id = $id;";
- #print $query;
- try {
- $results = $sqlite_db_connection->query($query);
- } catch (Exception $e) {
- echo 'Caught exception: ' . $e->getMessage();
- exit();
- }
-
- if ($results) {
- while ($row = $results->fetchArray()) {
- // Get values
- $first = $row["first_name"];
- $last = $row["last_name"];
-
- // Feedback for end user
- $html .= "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
- }
- } else {
- echo "Error in fetch ".$sqlite_db->lastErrorMsg();
- }
- break;
- }
- }
-
- // This is used later on in the index.php page
- // Setting it here so we can close the database connection in here like in the rest of the source scripts
- $query = "SELECT COUNT(*) FROM users;";
- $result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
- $number_of_rows = mysqli_fetch_row( $result )[0];
-
- mysqli_close($GLOBALS["___mysqli_ston"]);
- ?>
mysqli_real_escape_string()
mysqli_real_escape_string()
函数用于对用户输入的id进行转义,以防止恶意SQL代码被插入到SQL查询语句中。通过使用这个函数,特殊字符(如单引号)将被转义,从而使输入的数据变得安全,并且不会破坏SQL查询语句的结构。涉及的字符是 NUL(ASCII 0)、\n、\r、\、'、" 和 Control-Z
- <?php
-
- if( isset( $_SESSION [ 'id' ] ) ) {
- // Get input
- $id = $_SESSION[ 'id' ];
-
- switch ($_DVWA['SQLI_DB']) {
- case MYSQL:
- // Check database
- $query = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";
- $result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>Something went wrong.</pre>' );
-
- // Get results
- while( $row = mysqli_fetch_assoc( $result ) ) {
- // Get values
- $first = $row["first_name"];
- $last = $row["last_name"];
-
- // Feedback for end user
- $html .= "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
- }
-
- ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
- break;
- case SQLITE:
- global $sqlite_db_connection;
-
- $query = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";
- #print $query;
- try {
- $results = $sqlite_db_connection->query($query);
- } catch (Exception $e) {
- echo 'Caught exception: ' . $e->getMessage();
- exit();
- }
-
- if ($results) {
- while ($row = $results->fetchArray()) {
- // Get values
- $first = $row["first_name"];
- $last = $row["last_name"];
-
- // Feedback for end user
- $html .= "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
- }
- } else {
- echo "Error in fetch ".$sqlite_db->lastErrorMsg();
- }
- break;
- }
- }
-
- ?>
在上面的代码中,虽然没有直接调用
mysqli_real_escape_string()
函数对$_SESSION['id']
进行转义处理,但是通过将$_SESSION['id']
直接插入到SQL查询语句中,可以利用PHP会自动转义会话变量的特性来防止SQL注入。SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;
这个LIMIT 1;会在sql注入中被注释符号注释掉,相当于没用
- <?php
-
- if( isset( $_GET[ 'Submit' ] ) ) {
- // Check Anti-CSRF token
- checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
-
- // Get input
- $id = $_GET[ 'id' ];
-
- // Was a number entered?
- if(is_numeric( $id )) {
- $id = intval ($id);
- switch ($_DVWA['SQLI_DB']) {
- case MYSQL:
- // Check the database
- $data = $db->prepare( 'SELECT first_name, last_name FROM users WHERE user_id = (:id) LIMIT 1;' );
- $data->bindParam( ':id', $id, PDO::PARAM_INT );
- $data->execute();
- $row = $data->fetch();
-
- // Make sure only 1 result is returned
- if( $data->rowCount() == 1 ) {
- // Get values
- $first = $row[ 'first_name' ];
- $last = $row[ 'last_name' ];
-
- // Feedback for end user
- $html .= "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
- }
- break;
- case SQLITE:
- global $sqlite_db_connection;
-
- $stmt = $sqlite_db_connection->prepare('SELECT first_name, last_name FROM users WHERE user_id = :id LIMIT 1;' );
- $stmt->bindValue(':id',$id,SQLITE3_INTEGER);
- $result = $stmt->execute();
- $result->finalize();
- if ($result !== false) {
- // There is no way to get the number of rows returned
- // This checks the number of columns (not rows) just
- // as a precaution, but it won't stop someone dumping
- // multiple rows and viewing them one at a time.
-
- $num_columns = $result->numColumns();
- if ($num_columns == 2) {
- $row = $result->fetchArray();
-
- // Get values
- $first = $row[ 'first_name' ];
- $last = $row[ 'last_name' ];
-
- // Feedback for end user
- $html .= "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
- }
- }
-
- break;
- }
- }
- }
-
- // Generate Anti-CSRF token
- generateSessionToken();
-
- ?>
加了token检查
代码使用
is_numeric()
函数来检查id是否为数字类型。使用
intval()
函数将id转换为整数类型,以确保输入的id是一个有效的整数值。代码使用了PDO(PHP Data Objects)扩展来执行预处理语句,通过绑定参数和执行查询来防止SQL注入。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。