
bluemonday: एक तेज़ golang HTML sanitizer (OWASP Java HTML Sanitizer से प्रेरित) जो उपयोगकर्ता द्वारा उत्पन्न सामग्री को XSS से साफ़ करता है
bluemonday Go में कार्यान्वित एक HTML सैनिटाइज़र है। यह तेज़ और अत्यधिक कॉन्फ़िगरेबल है।
bluemonday अविश्वसनीय उपयोगकर्ता द्वारा उत्पन्न सामग्री को इनपुट के रूप में लेता है, और अनुमोदित HTML तत्वों और विशेषताओं की एक अनुमति सूची के विरुद्ध स्वच्छ किए गए HTML को लौटाता है ताकि आप सुरक्षित रूप से अपने वेब पेज में सामग्री शामिल कर सकें।
यदि आप उपयोगकर्ता द्वारा उत्पन्न सामग्री स्वीकार करते हैं, और आपका सर्वर Go का उपयोग करता है, तो आपको bluemonday की आवश्यकता है।
उपयोगकर्ता द्वारा उत्पन्न सामग्री के लिए डिफ़ॉल्ट नीति (bluemonday.UGCPolicy().Sanitize()) इसे बदल देती है:
Hello <STYLE>.XSS{background-image:url("javascript:alert('XSS')");}</STYLE><A CLASS=XSS></A>World
एक हानिरहित में:
Hello World
और यह इसे बदल देता है:
<a href="javascript:alert('XSS1')" onmouseover="alert('XSS2')">XSS<a>
इसमें:
XSS
जबकि अभी भी इसकी अनुमति देता है:
<a href="http://www.google.com/">
<img src="https://ssl.gstatic.com/accounts/ui/logo_2x.png"/>
</a>
ज्यादातर अपरिवर्तित गुज़रने के लिए (इसे एक rel="nofollow" मिला जो उपयोगकर्ता द्वारा उत्पन्न सामग्री के लिए एक अच्छी बात है):
<a href="http://www.google.com/" rel="nofollow">
<img src="https://ssl.gstatic.com/accounts/ui/logo_2x.png"/>
</a>
यह साइटों को XSS हमलों से बचाता है। XSS हमले के लिए कई वैक्टर हैं और जोखिम को कम करने का सबसे अच्छा तरीका उपयोगकर्ता इनपुट को HTML तत्वों और विशेषताओं की ज्ञात सुरक्षित सूची के विरुद्ध स्वच्छ करना है।
आपको हमेशा किसी अन्य प्रसंस्करण के बाद bluemonday चलाना चाहिए।
यदि आप blackfriday या Pandoc का उपयोग करते हैं तो bluemonday को इन चरणों के बाद चलाया जाना चाहिए। यह सुनिश्चित करता है कि आपकी प्रक्रिया में बाद में कोई असुरक्षित HTML शामिल नहीं किया गया है।
bluemonday OWASP Java HTML Sanitizer और HTML Purifier दोनों से काफी प्रेरित है।
अनुमति सूची पर आधारित, आपको या तो अनुमति देने के लिए HTML तत्वों और विशेषताओं (और विशेषताओं के regexp पैटर्न) का वर्णन करने वाली एक नीति बनाने की आवश्यकता है, या अच्छे डिफ़ॉल्ट का प्रतिनिधित्व करने वाली प्रदान की गई नीतियों में से एक का उपयोग करें।
अनुमति सूची वाली नीति को मुख्य Go टीम द्वारा Go net/html लाइब्रेरी में कार्यान्वित एक तेज़ गैर-मान्यकरण, केवल आगे-बढ़ने वाले, टोकन-आधारित पार्सर का उपयोग करके लागू किया जाता है।
हम उम्मीद करते हैं कि हमें अच्छी तरह से स्वरूपित HTML (प्रत्येक लागू खुले तत्व के लिए बंद करने वाले तत्व, सही ढंग से नेस्टेड) प्रदान किया जाएगा और इसलिए हम खराब नेस्टेड या अपूर्ण HTML की मरम्मत पर ध्यान केंद्रित नहीं करते हैं। हम केवल यह सुनिश्चित करने पर ध्यान केंद्रित करते हैं कि जो भी तत्व मौजूद हैं वे नीति अनुमति सूची में वर्णित हैं और विशेषताएँ और लिंक आपके वेब पेज पर उपयोग के लिए सुरक्षित हैं। GIGO लागू होता है और यदि आप इसे खराब HTML खिलाते हैं तो bluemonday इसे फिर से अच्छा बनाने के तरीके का पता लगाने का काम नहीं करता है।
हाँ
हम व्यापक रूप से उपयोग किए जाने वाले और भारी क्षेत्र-परीक्षण किए गए OWASP Java HTML Sanitizer से स्थानांतरित होकर उत्पादन में bluemonday का उपयोग कर रहे हैं।
हम अपने व्यापक परीक्षण सूट (AntiSamy परीक्षणों के साथ-साथ उठाए गए किसी भी मुद्दे के परीक्षण सहित) को पास कर रहे हैं। किसी भी अनसुलझे मुद्दे की जाँच करें कि क्या आपके लिए कुछ बाधा हो सकती है।
हम पुल रिक्वेस्ट और मुद्दों को आमंत्रित करते हैं ताकि हमें यह सुनिश्चित करने में मदद मिल सके कि हम उपयोगकर्ता द्वारा उत्पन्न सामग्री के माध्यम से विभिन्न हमलों के खिलाफ व्यापक सुरक्षा प्रदान कर रहे हैं।
go get github.com/microcosm-cc/bluemonday का उपयोग करके इंस्टॉल करें
फिर इसे कॉल करें:
package main
import (
"fmt"
"github.com/microcosm-cc/bluemonday"
)
func main() {
// Do this once for each unique policy, and use the policy for the life of the program
// Policy creation/editing is not safe to use in multiple goroutines
p := bluemonday.UGCPolicy()
// The policy can then be used to sanitize lots of input and it is safe to use the policy in multiple goroutines
html := p.Sanitize(
`<a onblur="alert(secret)" href="http://www.google.com">Google</a>`,
)
// Output:
// <a href="http://www.google.com" rel="nofollow">Google</a>
fmt.Println(html)
}
हम Sanitize को कॉल करने के तीन तरीके प्रदान करते हैं:
p.Sanitize(string) string
p.SanitizeBytes([]byte) []byte
p.SanitizeReader(io.Reader) bytes.Buffer
यदि आप प्रदर्शन के बारे में जुनूनी हैं, तो p.SanitizeReader(r).Bytes() इनपुट या आउटपुट के किसी भी अनावश्यक कास्टिंग के बिना एक []byte लौटाएगा। हालांकि अंतर इतना नगण्य है कि आपको कभी चिंता करने की आवश्यकता नहीं है।
आप अपनी स्वयं की नीतियां बना सकते हैं:
package main
import (
"fmt"
"github.com/microcosm-cc/bluemonday"
)
func main() {
p := bluemonday.NewPolicy()
// Require URLs to be parseable by net/url.Parse and either:
// mailto: http:// or https://
p.AllowStandardURLs()
// We only allow <p> and <a href="">
p.AllowAttrs("href").OnElements("a")
p.AllowElements("p")
html := p.Sanitize(
`<a onblur="alert(secret)" href="http://www.google.com">Google</a>`,
)
// Output:
// <a href="http://www.google.com">Google</a>
fmt.Println(html)
}
हम दो डिफ़ॉल्ट नीतियां भेजते हैं:
bluemonday.StrictPolicy() जिसे सभी HTML तत्वों और उनकी विशेषताओं को हटाने के समतुल्य माना जा सकता है क्योंकि इसकी अनुमति सूची में कुछ भी नहीं है। उपयोग का एक उदाहरण परिदृश्य ब्लॉग पोस्ट शीर्षक होंगे जहां HTML टैग की बिल्कुल भी उम्मीद नहीं की जाती है और यदि वे हैं तो तत्वों और तत्वों की सामग्री को हटा दिया जाना चाहिए। यह एक बहुत सख्त नीति है।
bluemonday.UGCPolicy() जो उपयोगकर्ता द्वारा उत्पन्न सामग्री के लिए सुरक्षित HTML तत्वों और विशेषताओं का एक व्यापक चयन की अनुमति देता है। ध्यान दें कि यह नीति iframes, object, embed, styles, script, आदि की अनुमति नहीं देती है। उपयोग का एक उदाहरण परिदृश्य ब्लॉग पोस्ट बॉडी होंगे जहां विभिन्न प्रकार के फ़ॉर्मेटिंग की अपेक्षा की जाती है और TABLEs और IMGs की संभावना भी होती है।
नीति बनाने का सार यह निर्धारित करना है कि आपके परिदृश्य के लिए कौन से HTML तत्व और विशेषताएं सुरक्षित मानी जाती हैं। OWASP जोखिमों को समझाने में मदद करने के लिए एक XSS रोकथाम चीट शीट प्रदान करता है, लेकिन मूल रूप से:
script, style, iframe, object, embed, base तत्वों से बचें जो क्लाइंट द्वारा कोड निष्पादित करने या तीसरे पक्ष की सामग्री शामिल करने की अनुमति देते हैं जो कोड निष्पादित कर सकती हैमूल रूप से, आपको यह वर्णन करने में सक्षम होना चाहिए कि आपके परिदृश्य के लिए कौन सा HTML ठीक है। यदि आपको विश्वास नहीं है कि आप अपनी नीति का वर्णन कर सकते हैं तो कृपया bluemonday.UGCPolicy() जैसी शिप की गई नीतियों में से एक का उपयोग करने पर विचार करें।
एक नई नीति बनाने के लिए:
p := bluemonday.NewPolicy()
To add elements to a policy either add just the elements:
p.AllowElements("b", "strong")
Or using a regex:
नोट: यदि कोई तत्व ऊपर दिखाए अनुसार नाम से जोड़ा जाता है, तो कोई भी मैच करने वाला regex अनदेखा कर दिया जाएगा
यह भी अनुशंसा की जाती है कि सुनिश्चित करें कि कई पैटर्न ओवरलैप न हों क्योंकि निष्पादन के क्रम की गारंटी नहीं है और इसके परिणामस्वरूप कुछ नियम छूट सकते हैं।
p.AllowElementsMatching(regex.MustCompile(`^my-element-`))
या किसी विशेषता को जोड़ने के गुण के रूप में तत्व जोड़ें:
// Note the recommended pattern, see the recommendation on using .Matching() below
p.AllowAttrs("nowrap").OnElements("td", "th")
फिर से, यह regex पैटर्न मैच विकल्प का भी समर्थन करता है:
p.AllowAttrs("nowrap").OnElementsMatching(regex.MustCompile(`^my-element-`))
विशेषताओं को या तो सभी तत्वों में जोड़ा जा सकता है:
p.AllowAttrs("dir").Matching(regexp.MustCompile("(?i)rtl|ltr")).Globally()
या विशेषताओं को विशिष्ट तत्वों में जोड़ा जा सकता है:
// Not the recommended pattern, see the recommendation on using .Matching() below
p.AllowAttrs("value").OnElements("li")
यह हमेशा अनुशंसित है कि एक विशेषता को एक पैटर्न से मेल खाने के लिए बनाया जाए। अन्यथा HTML विशेषताओं में XSS बहुत आसान है:
// \p{L} matches unicode letters, \p{N} matches unicode numbers
p.AllowAttrs("title").Matching(regexp.MustCompile(`[\p{L}\p{N}\s\-_',:\[\]!\./\\\(\)&]*`)).Globally()
आप किसी भी समय रुक सकते हैं और .Sanitize() कॉल कर सकते हैं:
// string htmlIn passed in from a HTTP POST
htmlOut := p.Sanitize(htmlIn)
और आप किसी भी मौजूदा नीति को ले सकते हैं और उसका विस्तार कर सकते हैं:
p := bluemonday.UGCPolicy()
p.AllowElements("fieldset", "select", "option")
हालांकि AllowAttrs का उपयोग करके Matching नियम के साथ इनलाइन CSS को संभालना संभव है, सभी इनलाइन CSS को सुरक्षित रूप से संसाधित करने के लिए एक एकल मोनोलिथिक रेगुलर एक्सप्रेशन लिखना एक तुच्छ कार्य नहीं है। ऐसा करने का प्रयास करने के बजाय, आप जिस भी तत्व पर चाहें style विशेषता की अनुमति दे सकते हैं और इनलाइन स्टाइल को नियंत्रित और स्वच्छ करने के लिए स्टाइल नीतियों का उपयोग कर सकते हैं।
यह दृढ़ता से अनुशंसा की जाती है कि आप यह सुनिश्चित करने के लिए Matching (एक उपयुक्त रेगुलर एक्सप्रेशन के साथ), MatchingEnum, या MatchingHandler का उपयोग करें कि प्रत्येक स्टाइल आपकी आवश्यकताओं से मेल खाता है, लेकिन डिफ़ॉल्ट हैंडलर अधिकांश व्यापक रूप से उपयोग किए जाने वाले स्टाइल के लिए प्रदान किए जाते हैं।
Similar to attributes, you can allow specific CSS properties to be set inline:
p.AllowAttrs("style").OnElements("span", "p")
// Allow the 'color' property with valid RGB(A) hex values only (on any element allowed a 'style' attribute)
p.AllowStyles("color").Matching(regexp.MustCompile("(?i)^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$")).Globally()
इसके अतिरिक्त, आप किसी CSS गुण को केवल अनुमत मान पर सेट करने की अनुमति दे सकते हैं:
p.AllowAttrs("style").OnElements("span", "p")
// Allow the 'text-decoration' property to be set to 'underline', 'line-through' or 'none'
// on 'span' elements only
p.AllowStyles("text-decoration").MatchingEnum("underline", "line-through", "none").OnElements("span")
या आप regex पैटर्न मैच के आधार पर तत्व निर्दिष्ट कर सकते हैं:
p.AllowAttrs("style").OnElementsMatching(regex.MustCompile(`^my-element-`))
// Allow the 'text-decoration' property to be set to 'underline', 'line-through' or 'none'
// on 'span' elements only
p.AllowStyles("text-decoration").MatchingEnum("underline", "line-through", "none").OnElementsMatching(regex.MustCompile(`^my-element-`))
यदि आपको अधिक विशिष्ट जाँच की आवश्यकता है, तो आप एक हैंडलर बना सकते हैं जो एक स्ट्रिंग लेता है और दिए गए गुण के मानों को मान्य करने के लिए एक बूल लौटाता है। स्ट्रिंग पैरामीटर को लोअरकेस में बदल दिया गया है और यूनिकोड कोड पॉइंट को बदल दिया गया है।
myHandler := func(value string) bool{
// Validate your input here
return true
}
p.AllowAttrs("style").OnElements("span", "p")
// Allow the 'color' property with values validated by the handler (on any element allowed a 'style' attribute)
p.AllowStyles("color").MatchingHandler(myHandler).Globally()
लिंक सुरक्षित रूप से स्वच्छ करने के लिए कठिन प्राणी हैं और दुर्भावनापूर्ण सामग्री के लिए सबसे बड़े हमले वैक्टरों में से एक भी हैं।
ऐसा करना संभव है:
p.AllowAttrs("href").Matching(regexp.MustCompile(`(?i)mailto|https?`)).OnElements("a")
लेकिन यह आपकी रक्षा नहीं करेगा क्योंकि इस मामले में रेगुलर एक्सप्रेशन एक विकृत मान को कुछ अप्रत्याशित करने से रोकने के लिए अपर्याप्त है।
हम लिंक के साथ सुरक्षित रूप से काम करने के लिए कुछ अतिरिक्त वैश्विक विकल्प प्रदान करते हैं।
RequireParseableURLs यह सुनिश्चित करेगा कि URL Go के net/url पैकेज द्वारा पार्स करने योग्य हैं:
p.RequireParseableURLs(true)
यदि आपने पार्स करने योग्य URL सक्षम किए हैं तो निम्न विकल्प AllowRelativeURLs होगा। डिफ़ॉल्ट रूप से यह अक्षम है (bluemonday एक अनुमति सूची उपकरण है... आपको स्पष्ट रूप से हमें चीजों की अनुमति देने के लिए कहने की आवश्यकता है) और जब अक्षम होता है तो यह सभी स्थानीय और स्कीम रिलेटिव URL को रोक देगा (यानी href="localpage.html", href="../home.html" और यहां तक कि href="//www.google.com" रिलेटिव हैं):
p.AllowRelativeURLs(true)
यदि आपने पार्स करने योग्य URL सक्षम किए हैं तो आप उन स्कीमों (जिन्हें आमतौर पर http और https सोचते समय प्रोटोकॉल कहा जाता है) की अनुमति दे सकते हैं जिनकी अनुमति है। ध्यान रखें कि उपरोक्त विकल्प में रिलेटिव URL की अनुमति देने से एक खाली स्कीम की अनुमति होगी:
p.AllowURLSchemes("mailto", "http", "https")
भले ही आपने पार्स करने योग्य URL सक्षम किए हों या नहीं, आप सभी URL पर एक rel="nofollow" विशेषता को बाध्य कर सकते हैं। यदि यह मौजूद नहीं है तो इसे जोड़ा जाएगा, लेकिन केवल तब जब href मान्य हो:
// This applies to "a" "area" "link" elements that have a "href" attribute
p.RequireNoFollowOnLinks(true)
इसी प्रकार, आप सभी URL पर उनकी rel विशेषता में "noreferrer" रखने के लिए बाध्य कर सकते हैं।
// This applies to "a" "area" "link" elements that have a "href" attribute
p.RequireNoReferrerOnLinks(true)
हम एक सुविधा विधि प्रदान करते हैं जो उपरोक्त सभी को लागू करती है, लेकिन आपको अभी भी URL नियमों को लागू करने के लिए लिंक करने योग्य तत्वों की अनुमति देने की आवश्यकता होगी:
p.AllowStandardURLs()
p.AllowAttrs("cite").OnElements("blockquote", "q")
p.AllowAttrs("href").OnElements("a", "area")
p.AllowAttrs("src").OnElements("img")
लिंक के संबंध में एक अतिरिक्त जटिलता RFC2397 में परिभाषित डेटा URI है। डेटा URI इस प्रारूप का उपयोग करके इमेज को इनलाइन परोसने की अनुमति देता है:
<img src="data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAAAAAAfQ//73v/+BiOh/AAA=">
हमने डेटा URI लिंक के माइमटाइप और उसके बाद बेस64 सामग्री को सत्यापित करने के लिए एक सहायक प्रदान किया है:
p.AllowDataURIImages()
वह सहायक GIF, JPEG, PNG और WEBP इमेज को सक्षम करेगा।
यह ध्यान दिया जाना चाहिए कि डेटा URI लिंक के उपयोग के साथ एक संभावित सुरक्षा जोखिम है। आपको केवल डेटा URI लिंक सक्षम करनी चाहिए यदि आप पहले से ही सामग्री पर भरोसा करते हैं।
हमारे पास उपयोगकर्ता द्वारा उत्पन्न सामग्री से निपटने में मदद करने के लिए कुछ सुविधाएं भी हैं:
p.AddTargetBlankToFullyQualifiedLinks(true)
यह सुनिश्चित करेगा कि एंकर <a href="" /> लिंक जो पूरी तरह से योग्य हैं (href गंतव्य में एक होस्ट नाम शामिल है) उनमें target="_blank" जोड़ा जाएगा।
इसके अतिरिक्त, नीति लागू होने के बाद target="_blank" वाले किसी भी लिंक में rel विशेषता को noopener जोड़ने के लिए समायोजित किया जाएगा। इसका मतलब है कि एक लिंक <a href="//host/path"/> से शुरू हो सकता है और <a href="//host/path" rel="noopener" target="_blank"> पर समाप्त होगा। यह ध्यान रखना महत्वपूर्ण है कि noopener का जोड़ एक सुरक्षा सुविधा है, कोई समस्या नहीं। ब्राउज़रों की एक दुर्भाग्यपूर्ण विशेषता है कि target="_blank" के परिणामस्वरूप खोली गई ब्राउज़र विंडो अभी भी ओपनर (आपका वेब पेज) को नियंत्रित कर सकती है और यह इससे बचाता है। इसकी पृष्ठभूमि यहां पाई जा सकती है: https://dev.to/ben/the-targetblank-vulnerability-by-example
हम नीति निर्माण को सरल बनाने के लिए कुछ सहायक भी बंडल करते हैं:
// Permits the "dir", "id", "lang", "title" attributes globally
p.AllowStandardAttributes()
// Permits the "img" element and its standard attributes
p.AllowImages()
// Permits ordered and unordered lists, and also definition lists
p.AllowLists()
// Permits HTML tables and all applicable elements and non-styling attributes
p.AllowTables()
निम्नलिखित अमान्य हैं:
// This does not say where the attributes are allowed, you need to add
// .Globally() or .OnElements(...)
// This will be ignored without error.
p.AllowAttrs("value")
// This does not say where the attributes are allowed, you need to add
// .Globally() or .OnElements(...)
// This will be ignored without error.
p.AllowAttrs(
"type",
).Matching(
regexp.MustCompile("(?i)^(circle|disc|square|a|A|i|I|1)$"),
)
दोनों उदाहरण एक ही मुद्दा प्रदर्शित करते हैं, वे विशेषताओं की घोषणा करते हैं लेकिन फिर यह निर्दिष्ट नहीं करते कि क्या वे वैश्विक रूप से या केवल विशिष्ट तत्वों (और कौन से तत्व) पर अनुमत हैं। विशेषताएँ एक या अधिक तत्वों से संबंधित होती हैं, और नीति को इसकी घोषणा करने की आवश्यकता है।
हम अभी तक CSS को अनुमति देने और स्वच्छ करने में मदद करने के लिए कोई उपकरण शामिल नहीं कर रहे हैं। जिसका अर्थ है कि जब तक आप एक ही रेगुलर एक्सप्रेशन में भारी काम नहीं करना चाहते (अनुचित), आपको कहीं भी "style" विशेषता की अनुमति नहीं देनी चाहिए।
उसी विषय में, <script> और <style> दोनों को हानिकारक माना जाता है। ये तत्व (और उनकी सामग्री) डिफ़ॉल्ट रूप से प्रस्तुत नहीं किए जाएंगे, और आपको स्पष्ट रूप से p.AllowUnsafe(true) सेट करने की आवश्यकता है। आपको पता होना चाहिए कि इन तत्वों की अनुमति देने से HTML सैनिटाइज़र का उपयोग करने का उद्देश्य विफल हो जाता है क्योंकि आप स्पष्ट रूप से या तो जावास्क्रिप्ट (और कोई भी स्पष्ट रूप से लिखा गया XSS) और CSS (जो JS डालने के लिए DOM को संशोधित कर सकता है) की अनुमति दे रहे होंगे, और इसके अतिरिक्त इस लाइब्रेरी में सीमाओं का मतलब है कि यह नहीं जानता कि HTML मान्य रूप से संरचित है या नहीं और यह इन तत्वों को WhatWG HTML पार्सर मानक में निर्मित कुछ सुरक्षा तंत्रों को बायपास करने की अनुमति दे सकता है।
आपके खराब HTML को ठीक करना bluemonday का काम नहीं है, यह केवल दुर्भावनापूर्ण HTML को पार करने से रोकने का काम है। यदि आपके पास बेमेल HTML तत्व हैं, या तत्वों का गैर-अनुरूप नेस्टिंग है, तो वे बने रहेंगे। लेकिन यदि आपके पास अच्छी तरह से संरचित HTML है तो bluemonday इसे नहीं तोड़ेगा।
bluemonday.UGCPolicy()) लेने की अनुमति देगा जो उनकी 90% आवश्यकताओं को कवर करती है लेकिन उनकी ज़रूरत से अधिक करती है, और उन अतिरिक्त चीजों को हटाने की अनुमति देगा जो वे नहीं चाहते हैं ताकि इसे 100% वही बनाया जा सके जो वे चाहते हैंtable तत्व caption का वंशज नहीं है, colgroup, thead, tbody, tfoot और tr की अनुमति है, और कैरेक्टर डेटा की अनुमति नहीं है)