111年高考三級程式設計

二、資料庫是企業組織或政府部門中用以保存大量資料的機制。下圖為資料表的結構,請回答以下各小題。(每小題10分,共20分)

            pic01.png

     ()請以 SQL 列出某一個人的年度薪資總額,必須顯示 id, first_name, last_name 及總額。

    ()現在的資料查詢服務常見於網頁系統,而 SQL Injection 是最常見的資料庫攻擊方式。請問下列查詢語句是否會有被攻擊的疑慮?若有的話該如何改善?程式碼可以使用 PHP ASP.NET

        SELECT first_name, last_name FROM employee WHERE id = 'A001'

答:

()

employee資料表:

employee_id

first_name

last_name

e001

e002

e003

salary_slip資料表:

salary_slip_id

year

month

amount

employee_id

s001

2021

1

20000

e001

s002

2021

2

20000

e001

s003

2021

3

20000

e001

s004

2021

4

20000

e001

s005

2021

5

20000

e001

s006

2021

1

20000

e002

s007

2021

2

30000

e002

s008

2021

3

30000

e002

s009

2021

4

30000

e002

s010

2021

1

40000

e003

s011

2021

2

40000

e003

s012

2021

3

40000

e003

Select E.employee_id, E.first_name, E.last_name, Sum(amount) As 總額

From employee As E, salary_slip As S

Where E.employee_id = S.employee_id

Group By E.employee_id, E.first_name, E.last_name

執行結果:

employee_id

first_name

last_name

總額

e001

100000

e002

110000

e003

120000

()

1.程式碼:

  test.html

<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>

<form action="hello.php" method="post">

員工ID<input type="text" name="id"><br>

<input type="submit" value=" 送出">

</form>

  執行結果:

  pic02.png

  hello.php

<?php

    // 接收員工ID

    $id = $_REQUEST['id'];

    echo "<br> 輸入員工ID".$id ;

    echo "</br>";

    $host = 'localhost';

    $dbuser = 'root';

    $dbpassword = '12345678';

    $dbname = 'test1';

    $link = mysqli_connect($host, $dbuser, $dbpassword, $dbname);

    if($link){

        mysqli_query($link, 'SET NAMES uff8');

        echo "正確連接資料庫";

    }

    else {

        echo "不正確連接資料庫</br>" . mysqli_connect_error( );

    }

    // 設置一個空陣列來放資料

    $datas = array( );

    // sql 語法存在變數中

    $sql = "SELECT * FROM `employee` WHERE `employee_id` = '".$id."'";

    echo "<br>SQL語法為".$sql;

    echo "</br>";

    // mysqli_query 方法執行 (sql 語法) 將結果存在變數中

    $result = mysqli_query($link, $sql);

    // 如果有資料

    if ($result) {

        // mysqli_num_rows 方法可以回傳我們結果總共有幾筆資料

        if (mysqli_num_rows($result) > 0) {

            // 取得大於0代表有資料

            // while 迴圈會根據資料數量,決定跑的次數

            // mysqli_fetch_assoc 方法可取得一筆值

            while ($row = mysqli_fetch_assoc($result)) {

                                        // 每跑一次迴圈就抓一筆值,最後放進 data 陣列中

                                        $datas[ ] = $row;

            }

        }

        // 釋放資料庫查到的記憶體

        mysqli_free_result($result);

    }

    else {

        echo "{$sql} 語法執行失敗,錯誤訊息: " . mysqli_error($link);

    }

    // 處理完後印出資料

    if(!empty($result)){

        // 如果結果不為空,就利用 print_r 方法印出資料

        print_r($datas);

          }

          else {

        // 為空表示沒資料

        echo "查無資料";

          }

?>

  執行結果:

  pic03.png

  輸入員工:ID' or '1 = 1

  正確連接資料庫

  SQL語法為SELECT * FROM `employee` WHERE `employee_id` = '' or '1 = 1'

  Array ( [0] => Array ( [employee_id] => e001 [first_name] => [last_name] => ) [1] => Array ( [employee_id] => e002 [first_name] => [last_name] => ) )

  補充說明:

  輸入員工ID' OR ''='' # (O)

  輸入員工ID' OR 1=1 # (O)

  輸入員工ID' OR '1=1'# (O)

  輸入員工ID' OR '1=1 (O)

  原先SQL語法

  SELECT * FROM `employee` WHERE `employee_id` = 'e0033' or 1 = 1;

  將「'e0033' or 1 = 1」替換成 or 1=1,如下:

  SELECT * FROM `employee` WHERE `employee_id` = 'or 1 = 1'; (X)

  將「'e0033' or 1 = 1」替換成 'or '1=1,如下:

  SELECT * FROM `employee` WHERE `employee_id` = ''or '1 = 1'; (O)

2.被攻擊的疑慮:

  在員工 ID 上輸入「ID' or '1 = 1」,可以查詢 employee 資料表的所有內容。

3.改善方式:

  (1)透過不同DB的帳號給予不同的權限:

  網路上的 Web 系統,會另外開一個 DB 帳號,權限只能讀與寫。

  (2)可疑的關鍵字全部都過濾掉:

  例如輸入 --1 = 1、註解符號、單引號、雙引號、<script> HTML 標籤。

  (3)SQL指令透過Stored Procedure來執行:

  一般的惡意參數會失效,例如:

  Select * From Table Where id = ‘user’ And passwd = ‘ab123’

    可以將 id passwd 的值修改為 Stored Procedure 的輸入參數,做法如下:

  Create Proc sp_SprocName2 @MyInput1 varchar(20), @MyInput2 varchar(20)

  As

  Select * From Table

  Where id = @MyInput1 And passwd = @MyInput2

  Go

  sp_SprocName2 接收到輸入值後,便將它存放在 @MyInput1 @MyInput2 變數中,變數使用 @ 符號開頭,如果使用 @@ 符號開頭的則為全域變數,執行如下:

  Exec sp_SprocName2 ‘user’, ‘ab123’

  ※參考資料

  1.http://yes.nctu.edu.tw/sql/StoredProcedure/StoredProcedure.htm

  2.https://blog.xuite.net/linriva/blog/41344348-%5B%E9%A0%90%E5%AD%98%E7%A8%8B%E5%BA%8F%5D+%E6%9C%89%E8%BC%B8%E5%85%A5%E5%8F%83%E6%95%B8%E7%9A%84Stored+Procedure

  (4)使用已修正過 SQL 資料隱碼問題資料庫連接元件連接資料庫,例如  ASP.NET SqlDataSource 物件

  (5)在組合 SQL 字串時,先針對所傳入參數作字元取代

  (6)透過程式語言中特殊的功能,讓使用者輸入的特殊字串被加上反斜線以去除其功能

參考資料:https://ithelp.ithome.com.tw/articles/10254637

arrow
arrow
    文章標籤
    程式設計
    全站熱搜

    jacksaleok 發表在 痞客邦 留言(0) 人氣()