Files
build-web-application-with-…/ja/04.3.md
2014-12-14 23:27:42 +08:00

4.2 KiB
Raw Blame History

4.3 クロスサイトスクリプティングの予防

現在のホームページは大量の動的なコンテンツを含み、ユーザのエクスペリエンスを高めています。以前に比べてとても複雑になっています。いわゆる動的なコンテンツとは、ユーザの環境と要求により、Webアプリケーションが目的の内容を出力できることを指します。動的なホームページは"クロスサイトスクリプティング"(Cross Site Scripting、セキュリティ専門家が一般的にXSSと省略するもの)と呼ばれる攻撃を受けることがあります。

攻撃者は通常セキュリティホールのあるプログラム中にJavaScript、VBScript、ActiveXまたはFlashを挿入することでユーザを騙します。一旦攻撃が成功するとユーザアカウント情報が盗まれ、ユーザの設定を改ざんされてしまったり、cookieを盗みまたは汚染して悪意ある広告を埋め込んだりされます。

XSSに対する最も効果的な予防は以下の二種類を組み合わせることですすべての入力データを検証し、攻撃の検査をすることこれに関しては前の節でいくつかご紹介しました。もうひとつは出力されるデータに対し適切な処理を行うことによって、すでに挿入されてしまったいかなるスクリプトに対してもブラウザで実行されないようにすることです。

Goではどのようにこの効果的な防御を行なっているのでしょうかGoのhtml/templateの中では以下のいくつかの関数によってエスケープすることができます。

  • func HTMLEscape(w io.Writer, b []byte) //bに対してエスケープを行い、wに出力する。
  • func HTMLEscapeString(s string) string //sに対してエスケープを行い、結果の文字列を返す。
  • func HTMLEscaper(args ...interface{}) string //複数の引数を同時にエスケープします。結果となる文字列を返します。

4.1節の例を見てみましょう。

fmt.Println("username:", template.HTMLEscapeString(r.Form.Get("username"))) //サーバ側に出力されます。
fmt.Println("password:", template.HTMLEscapeString(r.Form.Get("password")))
template.HTMLEscape(w, []byte(r.Form.Get("username"))) //クライアントに出力されます。

もし入力されたusernameが<script>alert()</script>だった場合、ブラウザ上では以下のように表示されます:

図4.3 Javascriptフィルターによる出力

Goのhtml/templateパッケージはデフォルトでhtmlタグをフィルターします。しかし時にはこの<script>alert()</script>を正常な情報として出力したい場合があるかもしれません。そのような場合はどのように処理するべきでしょうかこの場合はtext/templateをご利用ください。下の例をご覧ください

import "text/template"
...
t, err := template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`)
err = t.ExecuteTemplate(out, "T", "<script>alert('you have been pwned')</script>")

出力

Hello, <script>alert('you have been pwned')</script>!

またはtemplate.HTML型を使用すると

import "html/template"
...
t, err := template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`)
err = t.ExecuteTemplate(out, "T", template.HTML("<script>alert('you have been pwned')</script>"))

出力

Hello, <script>alert('you have been pwned')</script>!

template.HTMLに変換した後も、変数の内容はエスケープされません。 

エスケープの例:

import "html/template"
...
t, err := template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`)
err = t.ExecuteTemplate(out, "T", "<script>alert('you have been pwned')</script>")

エスケープ後の出力:

Hello, &lt;script&gt;alert(&#39;you have been pwned&#39;)&lt;/script&gt;!