iT邦幫忙

2026 iThome 鐵人賽

DAY 12
0
佛心分享-SideProject30

就決定是你了!打造寶可夢持有追蹤系統 (React x Express)系列 第 12

DAY 12:新增持有紀錄 (參數化查詢防止 SQL Injection)

  • 分享至 

  • xImage
  •  

今日目標說明

今天我們要在 src/routes/holdings.ts 加上一組 POST API,讓朋友可以把自己新抓到的寶可夢存進資料庫裡。在這篇實作中,我們將探討後端工程師絕對不能犯的低級錯誤:SQL Injection (資料隱碼攻擊)

【架構決策對比】字串串接 vs Parameterized Queries (參數化查詢)

當前端把新增的資料 (例如寶可夢 ID、備註文字) 傳給後端時,我們要怎麼寫 SQL?

寫法 程式碼範例 危險程度與原理
❌ 錯誤寫法 (字串串接) sql = "INSERT ... VALUES ('" + req.body.notes + "')" 極度致命! 如果駭客在 notes 欄位輸入 '); DROP TABLE system_users; --,這段惡意字串會直接變成 SQL 指令被執行,您的帳號表會瞬間灰飛煙滅!
✅ 正確寫法 (參數化查詢) sql = "INSERT ... VALUES (?)", args: [req.body.notes] 絕對安全。 資料庫引擎會把傳入的 ? 嚴格當作「純文字資料」看待,即便裡面包含 SQL 關鍵字,也只會變成一段名叫 "DROP TABLE..." 的搞笑備註而已,完全不會被當成指令執行。

核心程式碼片段

我們使用了 libsql 提供的 args 陣列來實作完美的參數化查詢:

router.post('/', async (req, res) => {
  const { pokemon_id, player_id, gender, is_shiny, is_lucky, notes } = req.body;

  try {
    // 使用 ? 作為佔位符,把變數放在 args 陣列中
    // turso (libsql) 會自動幫我們做好防護
    await db.execute({
      sql: `
        INSERT INTO user_pokemon_holdings 
        (pokemon_id, player_id, gender, is_shiny, is_lucky, notes) 
        VALUES (?, ?, ?, ?, ?, ?)
      `,
      args: [
        pokemon_id, 
        player_id, 
        gender ?? null, // 處理 undefined 以免 libsql 報錯
        is_shiny ? 1 : 0, 
        is_lucky ? 1 : 0, 
        notes ?? null
      ]
    });
    
    res.status(201).json({ message: '新增寶可夢成功!' });
  } catch (error) {
    console.error(error);
    res.status(500).json({ error: '新增失敗' });
  }
});

(備註小踩坑:libsql 的 args 不接受 undefined,如果是選填欄位,記得給個預設的 null 喔!)

實際畫面截圖

驗證被擋下

  1. 驗證被擋下:在 Postman 不帶 Token 發送 POST,截圖被擋下 (401) 的畫面。

驗證通過並新增成功

  1. 驗證通過並新增成功:在 Headers 帶上 Bearer Token 後,附上 JSON Body (包含 player_id, pokemon_id, gender 等) 發送,並截圖回傳 201 Created 成功訊息的畫面。

小結

我們成功實作了新增功能,而且不怕任何駭客的破壞!基本的 CRUD (增刪改查) 其實不難,但真正的挑戰在明天:我們要讓使用者上傳寶可夢的自訂圖示 (圖片檔案)!


上一篇
DAY 11:取得持有列表 (SQL JOIN 實戰與效能考量)
系列文
就決定是你了!打造寶可夢持有追蹤系統 (React x Express)12
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言