3秒でわかる
文字として扱いたい記号を、構文上の意味を失わせた形に置き換える処理。XSS や SQL インジェクションを防ぐ土台になります。
もう少し詳しく
どういうものか
その文脈で特別な意味を持つ文字を、意味を持たない別の表記に置き換える処理。HTML なら < を < に、& を & に変える。文字列リテラルの中の改行を \n と書くのも、正規表現でドットを \. と書くのも、同じ発想になる。
重要なのは、置き換え方が文脈ごとに違うこと。HTML、URL、SQL、シェル、正規表現は、それぞれ特別扱いする文字も置換の形式も異なる。「エスケープ済み」という状態は文脈と切り離しては存在しない。
なぜ必要か
利用者が入力した文字列を、そのままページに埋め込むと何が起きるか。名前の欄に と入れられた場合、ブラウザはそれをテキストではなくタグとして解釈し、スクリプトを実行する。これが XSS で、セッションの盗み取りにつながる。データを命令として読ませないための境界がエスケープになる。
具体例
// HTML に埋め込むときの最小の対応表
const escapeHtml = (s) =>
String(s)
.replace(/&/g, "&") // & を最初に置くのが要点
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
// 実際には自前で書かず、textContent を使うほうが安全
el.textContent = userInput; // タグとして解釈されないSQL の場合、文字列を自分でエスケープするのではなく、プレースホルダに任せるのが正解になる。
// 危険 文字列連結
db.query(`SELECT * FROM users WHERE name = '${name}'`);
// 安全 値は必ず別枠で渡す
db.query("SELECT * FROM users WHERE name = ?", [name]);つまずきやすいところ
置換の順番を間違えると壊れる。< を < にしたあとで & を & に変えると、< になって画面に < と表示される。& を最初に処理する。
二重エスケープも起きやすい。テンプレートエンジンが自動でエスケープする環境で、さらに手動でエスケープすると & になる。どの層が責任を持つかを決めておく。
文脈の取り違えも典型的な穴になる。HTML 用にエスケープした文字列を、そのまま href 属性の位置や の中に置いても防御にならない。属性値なら URL エンコード、JavaScript の文字列なら JSON エンコードというように、埋め込む先に合わせる必要がある。
覚え方
「データを命令として読ませない」ための処理。どこに置くかで、必要な変換が変わる。
