0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

「削除ボタン?GETリクエストで `/delete?id=5` に飛ばせばいいですよね」←それ、Googleのクローラーが全データ消します

0
Posted at

「リンクを踏んだだけ」でデータが消える設計

新人が管理画面の「ユーザー削除」機能を実装しました。

<a href="/admin/delete?id=5">このユーザーを削除</a>
@app.get("/admin/delete")
def delete_user(id: int):
    db.delete_user(id)
    return RedirectResponse("/admin/users")

<a> タグでリンクを作り、GETリクエストで削除APIを叩く。画面から削除ボタンを押せばユーザーが消える。一見、正常に動きます。
しかしこの設計には、3つの致命的な問題が潜んでいます。

問題1:ブラウザのプリフェッチが削除を発動する

モダンブラウザには、ページ内のリンクを先読み(プリフェッチ)してページ表示を高速化する機能があります。つまり、ユーザーが管理画面を開いただけで、ブラウザが勝手に /admin/delete?id=5 にGETリクエストを飛ばし、ユーザーが何も押していないのにデータが消える可能性があります。

問題2:検索エンジンのクローラーが全削除する

もし管理画面にBasic認証すらかかっていなかった場合、Googleのクローラー(Googlebot)がリンクを辿って /admin/delete?id=1/admin/delete?id=2/admin/delete?id=3…と順番にアクセスし、全ユーザーが自動削除されるという悪夢が起こりえます。(実際にこの事故は過去に複数のサービスで報告されています)

問題3:CSRF攻撃に対して完全に無防備

攻撃者が悪意のあるサイトにこう書くだけで、管理者がそのサイトを踏んだ瞬間にデータが消されます。

<!-- 攻撃者のサイト -->
<img src="https://target.com/admin/delete?id=5" />
<!-- ブラウザは画像を取得しようとGETリクエストを送る → 削除が発動 -->

HTTPメソッドの正しい使い分け

┌──────────┬───────────────────────────────┐
│ メソッド   │ 用途                           │
├──────────┼───────────────────────────────┤
│ GET      │ データの取得(副作用なし)        │
│ POST     │ データの作成                     │
│ PUT/PATCH│ データの更新                     │
│ DELETE   │ データの削除                     │
└──────────┴───────────────────────────────┘
【鉄則】
GETリクエストは「冪等(何回叩いても結果が同じ)」であり、
サーバーの状態を変更してはいけない。

正しい実装

<!-- フォームでPOSTリクエストを送る -->
<form method="POST" action="/admin/delete">
  <input type="hidden" name="id" value="5" />
  <input type="hidden" name="csrf_token" value="{{ csrf_token }}" />
  <button type="submit" onclick="return confirm('本当に削除しますか?')">
    削除
  </button>
</form>
@app.post("/admin/delete")  # GETではなくPOST
def delete_user(id: int, csrf_token: str = Form(...)):
    verify_csrf_token(csrf_token)  # CSRF対策
    db.delete_user(id)
    return RedirectResponse("/admin/users")

GETで状態を変更するコードをレビューで見つけたら、いくら動いていても即修正を依頼すべきです。これは「ベストプラクティス」ではなく「HTTP仕様違反」であり、予測不能な事故を引き起こす時限爆弾です。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?