เวอร์ชั่นสั้น!
import re, cgi
tag_re = re.compile(r'(<!--.*?-->|<[^>]*>)')
# Remove well-formed tags, fixing mistakes by legitimate users
no_tags = tag_re.sub('', user_input)
# Clean up anything else by escaping
ready_for_web = cgi.escape(no_tags)
แหล่ง regex: MarkupSafe รุ่นของพวกเขาจัดการเอนทิตี HTML ด้วยในขณะที่อันนี้ไม่ได้
ทำไมฉันไม่สามารถดึงแท็กออกแล้วปล่อยทิ้งไว้ได้?
เป็นเรื่องหนึ่งที่จะป้องกันผู้คนจาก<i>italicizing</i>
สิ่งต่าง ๆ โดยไม่ปล่อยให้i
ลอยไปมา แต่ก็เป็นอีกเรื่องหนึ่งที่จะนำข้อมูลเข้ามาโดยพลการและทำให้ไม่เป็นอันตรายอย่างสมบูรณ์ เทคนิคส่วนใหญ่ในหน้านี้จะปล่อยให้สิ่งต่าง ๆ เช่นความคิดเห็นที่ไม่มีการปิดบัง ( <!--
) และวงเล็บเหลี่ยมที่ไม่ได้เป็นส่วนหนึ่งของแท็ก ( blah <<<><blah
) เหมือนเดิม เวอร์ชัน HTMLParser ยังสามารถใส่แท็กที่สมบูรณ์ได้หากอยู่ในความคิดเห็นที่ไม่มีการปิดบัง
เกิดอะไรขึ้นถ้าแม่แบบของคุณคือ{{ firstname }} {{ lastname }}
อะไร? firstname = '<a'
และlastname = 'href="http://evil.com/">'
จะถูกปล่อยให้ผ่านโดยผู้ลอกแท็กทุกหน้าในหน้านี้ (ยกเว้น @Medeiros!) เพราะพวกเขายังไม่ได้ติดแท็กด้วยตนเอง การแยกแท็ก HTML ปกติออกไม่เพียงพอ
Django's strip_tags
เวอร์ชันที่ปรับปรุงแล้ว (ดูหัวข้อถัดไป) ของคำตอบยอดนิยมสำหรับคำถามนี้ให้คำเตือนต่อไปนี้:
ไม่มีการรับประกันใด ๆ เกี่ยวกับสตริงผลลัพธ์ที่ปลอดภัย HTML ดังนั้นไม่เคยทำเครื่องหมายปลอดภัยผลมาจากการที่โทรโดยไม่ต้องหลบหนีมันเป็นครั้งแรกเช่นกับstrip_tags
escape()
ทำตามคำแนะนำของพวกเขา!
หากต้องการตัดแท็กด้วย HTMLParser คุณต้องเรียกใช้หลายครั้ง
เป็นเรื่องง่ายที่จะหลีกเลี่ยงคำตอบแรกสุดสำหรับคำถามนี้
ดูสตริงนี้ (ที่มาและการสนทนา ):
<img<!-- --> src=x onerror=alert(1);//><!-- -->
ครั้งแรกที่ HTMLParser เห็นจะไม่สามารถบอกได้ว่า<img...>
เป็นแท็ก มันดูเสียดังนั้น HTMLParser จึงไม่กำจัดมัน มันแค่เอาไป<!-- comments -->
ทิ้งคุณไว้
<img src=x onerror=alert(1);//>
ปัญหานี้ได้รับการเปิดเผยต่อโครงการ Django ในเดือนมีนาคม 2014 โดยพื้นฐานของพวกเขาstrip_tags
นั้นเหมือนกับคำตอบแรกของคำถามนี้ เวอร์ชั่นใหม่ของพวกเขาจะรันเป็นลูปจนกว่าจะรันอีกครั้งจะไม่เปลี่ยนสตริง:
# _strip_once runs HTMLParser once, pulling out just the text of all the nodes.
def strip_tags(value):
"""Returns the given HTML with all tags stripped."""
# Note: in typical case this loop executes _strip_once once. Loop condition
# is redundant, but helps to reduce number of executions of _strip_once.
while '<' in value and '>' in value:
new_value = _strip_once(value)
if len(new_value) >= len(value):
# _strip_once was not able to detect more tags
break
value = new_value
return value
แน่นอนว่าไม่มีสิ่งใดที่เป็นปัญหาหากคุณหลีกเลี่ยงผลของstrip_tags()
มัน
อัปเดต 19 มีนาคม 2558 : มีข้อผิดพลาดในรุ่น Django ก่อน 1.4.20, 1.6.11, 1.7.7 และ 1.8c1 เวอร์ชันเหล่านี้สามารถป้อนการวนซ้ำไม่สิ้นสุดในฟังก์ชัน strip_tags () รุ่นที่คงที่จะทำซ้ำข้างต้น รายละเอียดเพิ่มเติมที่นี่
สิ่งที่ดีในการคัดลอกหรือใช้
โค้ดตัวอย่างของฉันไม่ได้จัดการเอนทิตี HTML - รุ่นแพคเกจ Django และ MarkupSafe ทำ
โค้ดตัวอย่างของฉันถูกดึงจากห้องสมุดMarkupSafe ที่ยอดเยี่ยมสำหรับการป้องกันการเขียนสคริปต์ข้ามไซต์ สะดวกและรวดเร็ว (ด้วยความเร็ว C ถึงรุ่น Python ดั้งเดิม) มันรวมอยู่ในGoogle App Engineและใช้โดยJinja2 (2.7 ขึ้นไป) , Mako, Pylons และอื่น ๆ มันทำงานได้อย่างง่ายดายด้วยแม่แบบ Django จาก Django 1.7
strip_tags ของ Django และยูทิลิตี้ html อื่น ๆจากเวอร์ชันล่าสุดนั้นดี แต่ฉันคิดว่ามันสะดวกกว่า MarkupSafe มันมีอยู่ในตัวคุณสามารถคัดลอกสิ่งที่คุณต้องการจากไฟล์นี้
หากคุณจำเป็นต้องตัดแถบเกือบทุกแท็กไลบรารีBleachนั้นดี คุณสามารถบังคับใช้กฎเช่น "ผู้ใช้ของฉันสามารถทำให้สิ่งเป็นตัวเอียง แต่พวกเขาไม่สามารถใช้ iframe
ทำความเข้าใจกับคุณสมบัติของผู้ลอกแท็กของคุณ! ใช้การทดสอบ fuzz กับมัน! นี่คือรหัสที่ฉันใช้ในการทำวิจัยสำหรับคำตอบนี้
เหน็บแนมโน้ต - คำถามนั้นเกี่ยวกับการพิมพ์ไปยังคอนโซล แต่นี่คือผลการค้นหาอันดับต้น ๆ ของ Google สำหรับ "python strip html from string" ดังนั้นนี่คือสาเหตุที่คำตอบนี้ 99% เกี่ยวกับเว็บ
&
) คุณสามารถ 1) ลบออกพร้อมกับแท็ก (มักจะไม่พึงประสงค์และไม่จำเป็นเพราะพวกเขาเทียบเท่ากับข้อความธรรมดา), 2) ปล่อยให้พวกเขาไม่เปลี่ยนแปลง (วิธีการแก้ปัญหาที่เหมาะสมถ้าข้อความที่ถูกปล้นจะย้อนกลับไปในบริบท HTML) หรือ 3 ) ถอดรหัสให้เป็นข้อความธรรมดา (หากข้อความที่ตัดจะถูกนำไปไว้ในฐานข้อมูลหรือบริบทที่ไม่ใช่ HTML อื่น ๆ หรือถ้าเว็บเฟรมเวิร์กของคุณทำการ HTML โดยอัตโนมัติเพื่อหลีกเลี่ยงข้อความของคุณ)