challenge 一部のHTMLタグを通すフィルタ

ユーザが入力した文字列から、一部のタグだけを許可して他をエスケープするコードを書いてください。要件は次のようになります。
  • 通すタグはAとBRとSTRONGのみ。大文字小文字は区別しない。
  • それ以外のタグとして意味を持ちうる文字列は<を&lt;に変換することで無効化する(削除するのではない。>は変換してもしなくてもよい)
  • Aタグのhrefとname以外の属性は削除する。BRやSTRONGの属性はすべて削除する。

このお題はperezvonさんの提案を元にしています。ありがとうございました。 ただ、いきなりだと難しいかと思ったので、肝の部分以外を先に出題しました。このお題は続編で徐々に難しくなっていきます。

追記:属性に<や>が含まれてしまうケースに漏れのある解答が多いようなのでテストケースを追加します。
これは「この出力なら十分」という意味です。この出力の通りでなければいけないという意味ではありません。

<script foo="<script>alert('bar')</script>">alert('foo')</script>
&lt;script foo="&lt;script&gt;alert('bar')&lt;/script&gt;"&gt;alert('foo')&lt;/script&gt;


<script foo="<a href='link'>link</a>">alert('foo')</script>
&lt;script foo="&lt;a href='link'&gt;link&lt;/a&gt;"&gt;alert('foo')&lt;/script&gt;

<a href='www.g>oogle.com'>link</a>

<a href="./www.g%3Eoogle.com">link</a>

Posted feedbacks - diff

なるほど、タグを無効化した場合、属性に含まれる < を放置すると今度はそちらがタグとみなされるということですか。

というわけで再修正パッチです。でもきっとまだあるな・・・
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
--- a.py.orig	Fri Aug 31 16:20:21 2007
+++ a.py	Fri Aug 31 16:20:35 2007
@@ -14,11 +14,12 @@
         elif tag_name.lower() in ('br', 'strong'):
             return combine()
         else:
-            return "&lt;" + m.group(0)[1:]
+            return m.group(0).replace("<", "&lt;")
     return re.compile(r"""<(/?)(\w+)((?:\s*\w+\s*=\s*(["']).+?\4)*)\s*(/?)>""", re.S).sub(repl, html)
 
 def main():
     print filter("""<a href='www.google.com'>link</a> <blink>and</blink> <strong onClick='alert("NG")'>click<br/>me!</strong>""")
+    print filter(""" <z foo='<script>alert("Boo")</script>'>""")
 
 if __name__ == '__main__':
     main()

バグありました… orz
1
2
3
4
5
@@ -15,3 +15,3 @@
            case 'A' : attrs = deleteAttr(attrs); break;
-           default : return all.replace('&', '&amp;').replace('<', '&lt;');
+           default : return all.replace(/&/g, '&amp;').replace(/</g, '&lt;');
          }

Index

Feed

Other

Link

Pathtraq

loading...