蛇ノ目の記

技術のことも。そうでないことも。

Bleachってなによ

ジャンプで連載してたやつではなく(念のため)

卍解とかもしない(念のため)

仕事で出会ったHTMLサニタイズライブラリなのだけど、日本語の情報がとても少ないのでちょっとまとめたい。

貴重な日本語の情報

www.ianlewis.org

Bleachとは

Bleach — Bleach 2.1.1 20171002 documentation によると、

Bleach is an allowed-list-based HTML sanitizing library

まずHTML sanitizing とはなにか。ググってみると「HTMLエスケープ処理」と出てくる。

例えば、フォームに<script>なんか悪いスクリプト;</script>XSSを試みる入力があったときに、<, >&lt ,&gtに置き換えることで 無効化する。というような感じだろうか。

Bleach can also linkify text safely

とあるので、HTML sanitizingだけでなくテキストを安全にリンクにすることもできる。

http://example.comが入力されたときに、<a href="http://example.com"> とリンクに変換できる、ということか。

applying filters that Django’s urlize filter cannot, and optionally setting rel attributes, even on links already in the text.

Djangoのurlize filterではできないフィルタを掛けたり、既にテキスト内に存在するリンクに属性を設定したりできる。

Bleach is intended for sanitizing text from untrusted sources.

信頼できないソースのサニタイズのためとあるので、ユーザに入力されたテキストが対象と考えてよさそう。

基本的な使い方

https://bleach.readthedocs.io/en/latest/#basic-use

>>> import bleach

>>> bleach.clean('an <script>evil()</script> example')
u'an &lt;script&gt;evil()&lt;/script&gt; example'

>>> bleach.linkify('an http://example.com url')
u'an <a href="http://example.com" rel="nofollow">http://example.com</a> url

上は、なんか悪いスクリプトサニタイズして無害化している例。

下はテキスト内のURLをリンク化している例。テキストフォームに入力された内容を、HTMLにして表示する掲示板のようなものと考えるのがいいのかな。

今回は仕事で扱ったリンク化をメインにする。

bleach.clean()

http://bleach.readthedocs.io/en/latest/clean.html#sanitizing-text-fragments

前述の通り、今回のメインはリンク化なのでざっくりと。

悪意のあるHTMLを綺麗にする

bleach.clean(text, tags=[u'a', u'abbr', u'acronym', u'b', u'blockquote', u'code', u'em', u'i', u'li', u'ol', u'strong', u'ul'], attributes={u'a': [u'href', u'title'], u'acronym': [u'title'], u'abbr': [u'title']}, styles=[], protocols=[u'http', u'https', u'mailto'], strip=False, strip_comments=True)

パラメータ

  • text(str) - 綺麗にするテキスト
  • tags(list) - 許可するタグのリスト。デフォルトはbleach.sanitizer.ALLOWED_TAGS
  • attributes(list) - 許可する属性。リストまたは辞書。デフォルトはbleach.sanitizer.ALLOWED_ATTRIBUTES
  • styles(list) - 許可するCSSスタイルのリスト。デフォルトはbleach.sanitizer.ALLOWED_STYLES
  • protocol(list) - 許可するリンクのプロトコル。デフォルトはbleach.sanitizer.ALLOWED_PROTOCOLS
  • strip(bool) - 許可していない要素を除去するか否か
  • strip_comments(bool) - HTMLコメントを除去するか否か

許可するタグと属性はセットなこともあると思うので、例えばattributes

ALLOWED_ATTRIBUTES = {
        'a': ['href', 'title', 'rel'], 
         . . . 
}

という辞書としたとき、tags

ALLOWED_TAGS = ALLOWED_ATTRIBUTES.keys()

とするのもよさそう。

bleach.linkify()

http://bleach.readthedocs.io/en/latest/linkify.html#linkifying-text-fragments

テキストからURLやメールアドレスを探してリンク化する。

bleach.linkify(text, callbacks=[<function nofollow>], skip_tags=None, parse_email=False)

パラメータ

  • text - リンク化するテキスト
  • callbacks(list) - タグの属性を調節するコールバック関数のリスト。デフォルトではbleach.linkifier.DEFAULT_CALLBACKS
  • skip_tags(list) - リンク化したくないタグのリスト。例えば、<pre>タグ内を飛ばしたい場合は['pre']とする。
  • parse_email(bool) - メールアドレスをリンク化するか否か

戻り値

  • リンク化したテキストをunicodeで返す

bleach.linkify()callbacksでは属性の設定や削除、置き換えができる。

http://bleach.readthedocs.io/en/latest/linkify.html#callbacks-for-adjusting-attributes-callbacks

属性を設定してみる

属性の設定を仕事で使ったので、そのあたりを書いてみる。

title属性とtarget属性を設定してみる

import bleach

def set_title(attrs, new=False):
    attrs[(None, 'title']) = 'my title'
    return attrs

def set_target(attrs, new=False):
    attrs[(None, 'target']) = '_blank'
    return attrs

callbacks = bleach.DEFAULT_CALLBACKS + [set_title] + [set_target]

html = 'abc http://example.com def'

html_linkify = bleach.linkify(html, callbacks = callbacks)

これによってリンク化したテキスト

abc <a href="http://example.com" rel="nofollow" target="_blank" title="my title">http://example.com</a> def

が得られる。

bleach.DEFAULT_CALLBACKS はデフォルトの属性設定コールバック関数でrel=nofollowを設定する (rel=nofollowを指定するとクローラーがリンク先を認識しなくなる)。

 

公式ドキュメントではbleach.linkify.Linkerを使っているので、それについて。

http://bleach.readthedocs.io/en/latest/linkify.html#setting-attributes

たくさんのテキストに同じリンク化の設定を適用したいときに便利そう。

パラメータ

  • callbacks(list) - タグの属性を調節するコールバック関数のリスト。デフォルトではbleach.linkifier.DEFAULT_CALLBACKS
  • skip_tags(list) - リンク化したくないタグのリスト。例えば、<pre>タグ内を飛ばしたい場合は['pre']とする。
  • parse_email(bool) - メールアドレスをリンク化するか否か
  • url_re(re) - URLの正規表現
  • email_re(re) - メールアドレスの正規表現

url_reとかemail_reにマッチするテキストだけリンク化ができる。

まとめ

ざっくりと。

Bleach

  • HTMLから悪意のある要素を取り除いて綺麗にできる

  • テキスト中のURLやメールアドレスをリンク化できる