[PHP] 常見網路攻擊及防範方法


Posted by Nicolakacha on 2020-09-11

本篇主要會介紹常見的網路攻擊,像是 XSS、明文密碼竊取、SQL Injection 以及 CSRF 等,並以 PHP 示範防範的方法:

XSS attack

Problem

如果在畫面上呈現的內容是使用者可以控制的,使用者就可以輸入能被解析的 <script> 或 HTML 標籤來改變網站內容。例如在input 欄位裡面輸入 <script>alert('hack')</script>

Solution

利用 PHP 內建的 htmlspecialchars 來跳脫字元

htmlspecialchars($str, ENT_QUOTES);

Plain text password

Problem

明文密碼儲存在資料庫容易被偷走,就算使用加密也可以被駭客解析

Solution

把密碼存成 Hash雜湊,利用 PHP 內建的 hash 雜湊方法在資料庫儲存密碼,雜湊和上述所說的加密的差別在於,雜湊是不可還原的。

  • 使用 password_hash() 將密碼存成雜湊

      $password = password_hash($_POST['password'], PASSWORD_DEFAULT);
    
  • 利用 password_verify() 核對密碼

      $row = $result->fetch_assoc();
        if (password_verify($password, $row['password'])) {
          $_SESSION['username'] = $username;
          header('Location: index.php');
        } else {
          header('Location: login.php?errorCode=2');
        }
    
  • 加鹽

    在儲存密碼時,使用雜湊不使用加密,是因為雜湊是不可逆的,無法逆向還原,而加密是可以解密的,只要加密的密鑰被掌握(為了驗證使用者登入,這個密鑰很有可能就存在 Server 上),就能夠輕鬆的還原出原來的密碼,此外,一旦有任何人類(可能是某個開發人員)知道這個密鑰,也就有可能被拿去做不法使用的風險。

    使用雜湊演算法時,雖無法逆向還原,但不同的輸入也有可能生成相同的雜湊碼。也因為這個特性,一些簡單的雜湊方法,還是有可能被有心人士利用。所以如 MD5 等一些簡單的雜湊演算法是不夠安全的,像是 md5hashing 之類的網站上就提供超過 60 種雜湊演算法的破解服務。

    為了加強雜湊的安全性,可以利用加鹽方法(Salting),在執行雜湊運算前先加入額外的字串,這樣雜湊碼即使被破解了,也無法得到真實的密碼,但更進一步地,如果駭客還是成功暴力破解了加鹽的字串,一旦成功破解第一組密碼,其他密碼也都暴露了,所以我們需要隨機生成的 Salt 來讓雜湊更安全。如 PHP 提供的 password_hash 方法可以隨機生成處理 Salt,所以即使是開發人員也不會知道每次的 Salt 是什麼,至此我們的密碼儲存又更安全了。

SQL injection

Problem

如果網頁上的 input 是有把值存在資料庫的動作時,駭客就可利用字串拼接的方式來改變原來的 SQL 意思,來改變內容,甚至進一步撈取資料。

  • 隨便亂新增內容

      INSERT INTO comments (nickname, content) values ('%s', '%s')
      ↓
      //nickname: a, content: '), ('admin', 'hi'
      ↓
      INSERT INTO comments (nickname, content) values ('a, content: '), ('admin', 'hi')
    
  • 撈取密碼

      INSERT INTO comments (nickname, content) values ('%s', '%s')
      ↓
      // '), ('admin', (SELECT password FROM users WHERE id=40))#
    
      INSERT INTO comments (nickname, content) values ('%s', '), ('admin', (SELECT password FROM users WHERE id=40))#
      )
    

Solution

  • Prepared statement

      /*
      $sql = sprintf(
          "select * from users where username='%s' and password='%s'",
          $username,
          $password
        );
        $result = $conn->query($sql);
      */
    
      $sql = "INSERT INTO nicolakacha_comments(nickname, content, client_ip) VALUES(?, ?, ?)";
      $stmt = $conn->prepare($sql);
      $stmt->bind_param('sss', $nickname, $content);
      $result = $stmt->execute();
    
      //拿 result 回來
      $result = $stmt->get_result();
    

CSRF

Problem

Cross-site request forgery (CSRF) 是利用各種偽裝的方法偽造一個對目標網站合法的 request 在某個網站 action 內(可能點了一個連結,一張圖片等),因為使用者的瀏覽器自帶有其目標網站驗證身分用的 cookie,所以一旦這個釣魚 action 被觸發,就可以成功讓使用者在不知情的情況下發出 request 給目標網站。

Solution

  • 檢查 Referer

    利用 request header 內的 referer 欄位檢查是不是來自合法的 domain,若不是則 reject。

    潛在問題:

    • 瀏覽器可能不會帶 referer
    • 使用者可能關閉自動帶 referer 的功能
    • 判定不是合法的程式碼必須要保證沒有 bug
  • 圖形驗證碼、簡訊驗證

    每次都要驗證會很麻煩,但會降低使用者體驗

  • CSRF Token

    在 form 裡面隨機產生一個 CSRF token,並將其存在 server 端的 session 裡,按下 submit 的時候就可比對兩者是否一致,若不一致則 reject。

    潛在問題:

    • 若 server 支援 cross origin 的 request,攻擊者可能會在他的頁面發起 request 來拿到這個 CSRF token
  • Double Submit Cookie 設置 CSRF Token

    因為攻擊者的沒辦法讀寫目標網站的 cookie,而且也不能設置目標網站的 cookie,我們可以使用 Double Submit Cookie 的 CSRF Token,存一個 token 在 Client 端的 cookie 裡,每次 Client 發出 Request 時,就比 form 裡面的 POST 是否也帶有這個 token,就知道是不是真的使用者發出的 Request了。

    潛在問題:
    https://security.stackexchange.com/questions/59470/double-submit-cookies-vulnerabilities

參考資料:讓我們來談談 CSRF


#PHP #程式導師計畫







Related Posts

MTR04_0724

MTR04_0724

Go起手式之三

Go起手式之三

[Week4] JS 實作串接 API(二)

[Week4] JS 實作串接 API(二)


Comments