Bleachってなによ
ジャンプで連載してたやつではなく(念のため)
卍解とかもしない(念のため)
仕事で出会ったHTMLサニタイズライブラリなのだけど、日本語の情報がとても少ないのでちょっとまとめたい。
貴重な日本語の情報
Bleachとは
Bleach — Bleach 2.1.1 20171002 documentation によると、
Bleach is an allowed-list-based HTML sanitizing library
まずHTML sanitizing
とはなにか。ググってみると「HTMLエスケープ処理」と出てくる。
例えば、フォームに<script>なんか悪いスクリプト;</script>
とXSSを試みる入力があったときに、<
, >
を<
,>
に置き換えることで
無効化する。というような感じだろうか。
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 <script>evil()</script> 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
bleach.linkify.Linker
たくさんのテキストに同じリンク化の設定を適用したいときに便利そう。
パラメータ
- 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やメールアドレスをリンク化できる