I have a simple forums application, when someone posts any content, i do:
post.Content = Sanitizer.GetSafeHtml(post.Content);
Now, i am not sure if i am doing something wrong, or what is going on, but it does not allow almost no html. Even simple <b></b> is too much for it. So i guess that tool is totally useless.
Now my question: Can anyone tell me how should i sanitize my users inputs so that they can post some images(<img> tags) and use bold emphasis etc?
It seems that many people find the sanitizer rather useless. Instead of using the sanitizer, just encode everything, and decode safe parts back:
private static readonly IEnumerable<string> WhitelistedTags =
new[] { "<b>", "</b>", "<i>", "</i>" };
private static readonly (string Encoded, string Decoded)[] DecodingPairs =
WhitelistedTags
.Select(tag => (Microsoft.Security.Application.Encoder.HtmlEncode(tag), tag))
.ToArray();
public static string Sanitize(string html)
{
// Encode the whole thing
var safeHtml = Microsoft.Security.Application.Encoder.HtmlEncode(html);
var builder = new StringBuilder(safeHtml);
// Decode the safe parts
foreach (var (encodedTag, decodedTag) in DecodingPairs)
{
builder.Replace(encodedTag, decodedTag);
}
return builder.ToString();
}
Please note that it's nearly impossible to safely decode an IMG tag, since there are really simple ways for an attacker to abuse this tag. Examples:
<IMG SRC="javascript:alert('XSS');">
<IMG SRC=javascript:alert('XSS')>
Take a look here for more a thorough XSS Cheat Sheet
This post best describes the issues with the Anti XSS library and provides a good work around that whitelists a set of tags and attributes.
I'm using this solution in my project and it seems to work great.
There is a quite simple way to block the threat by just getting rid of the "dangerous" tags.
string SanitizeHtml(string html)
{
html = System.Web.HttpUtility.HtmlDecode(html);
List<string> blackListedTags = new List<string>()
{
"body", "script", "iframe", "form", "object", "embed", "link", "head", "meta"
};
foreach (string tag in blackListedTags) {
html = Regex.Replace(html, "<" + tag, "<p", RegexOptions.IgnoreCase);
html = Regex.Replace(html, "</" + tag, "</p", RegexOptions.IgnoreCase);
}
return html;
}
With this the user will still see what is within the dangerous script, but it won't harm anything.
Related
All if i send data <test> its getting converted as html tags <test></test> please help!!
public static MvcHtmlString AnchorRowSelection(this HtmlHelper helper, string displayText, string title, string CssClass, string onclick, bool isModernPortal)
{
string className = ".body-row";
// Building anchor tag html
var Anchor = new TagBuilder("a");
// if(!string.IsNullOrWhiteSpace(displayText))
Anchor.InnerHtml = ControlUtilities.EncodeEmptyText(displayText);
if(!string.IsNullOrWhiteSpace(title))
Anchor.Attributes.Add("title", title);
if(!string.IsNullOrWhiteSpace(CssClass))
Anchor.Attributes.Add("class", CssClass);
if(!string.IsNullOrWhiteSpace(onclick))
{
string onclickString = string.Format("Javascript:highliteRowSelection(this, '{0}');{1}", className, onclick);
Anchor.Attributes.Add("onclick", onclickString);
}
return MvcHtmlString.Create(Anchor.ToString(TagRenderMode.Normal));
}
i changed inner html to set inner text but i am facing some other issues
If you want the XML parser not to parse the XML tags in your view you have two options to escape this.
<html><![CDATA[This is <b>bold</b>]]></html>
<html>How to escape <b>bold</b></html>
Escaped text means that the entire HTML block will be one big text node. Wrapping in CDATA tells the XML parser not to parse that section. It may be "easier", but limits your abilities downrange and should only be employed when appropriate; not just because it is more convenient. Escaped markup is considered harmful.
Reference
I am using sitecore 7.2 & I have created pipeline for enclosing tags for single-line Text as below.
public class SingleLineFieldEnclosingTags
{
public void Process(RenderFieldArgs args)
{
if (args.FieldTypeKey != "single-line text" && args.FieldTypeKey != "multi-line text")
return;
args.Result.FirstPart = Helper.WrapInTags(args);
}
}
public static string WrapInTags(RenderFieldArgs args)
{
string keyInParam = args.Parameters.Where(x => x.Key.Contains("enclosingTag")).FirstOrDefault().Key;
string wrappedText = args.Result.FirstPart;
if (IsPageEditorMode)
{
return wrappedText;
}
if (keyInParam != null && keyInParam.Trim().Equals("enclosingTag"))
{
if (args.Parameters.ContainsKey(keyInParam))
{
string[] paramTags = args.Parameters[keyInParam].Split('|').Reverse().ToArray();
foreach (string tag in paramTags)
{
wrappedText = string.Concat("<", tag.Trim(), ">", wrappedText, "</", tag.Trim().Split(' ')[0], ">");
}
if (wrappedText.Contains("enclosingTag"))
{
// remove enclosing tag attribute from tags
wrappedText = Regex.Replace(wrappedText, #"enclosingTag\s*=\""\s*?.*\""", string.Empty, RegexOptions.IgnoreCase);
}
return wrappedText;
}
}
return wrappedText;
}
It is working fine, but problem comes when we edit or save any field then it save it as
<p class="intro">Do you need something specific?</p>
including enclosing tags too. and now in publish mode it display twice, thrice and so one like below.
<p class="intro"></p>
<p class="intro"></p>
<p class="intro"></p>
<p class="intro">Do you need something specific?</p>
<p></p>
<p></p>
<p></p>
I presume you have added this pipeline to Item:Saved. As you have found, publishing actually also creates/saves the item in the web database, the same event is fired on that server and hence the reason you are seeing the repeated tags. Add a check to make sure you are running in the master database in your process method:
public void Process(RenderFieldArgs args)
{
if (!args.Item.Database.Name.Equals("master", StringComparison.InvariantCultureIgnoreCase))
return;
if (args.FieldTypeKey != "single-line text" && args.FieldTypeKey != "multi-line text")
return;
args.Result.FirstPart = Helper.WrapInTags(args);
}
However, you may want to check if your text is already wrapped in the tag you are enclosing in (as well) - use HTMLAgilityPack or CsQuery instead of messing with regular expressions. In a simple scenario such as a single-line text field you could probably just get away with a StartsWith() check instead.
You should consider moving your code to the renderField pipeline instead (more info in this blog post or this one), or make use of the EnclosingTag attribute of the FieldRenderer. This way the tags are added at render time, rather than appearing in the content editor. There is some code in this SO answer I posted previously that you can use to pass the css class as well.
I have some advanced users who need to see the raw XML of a transaction. I thought I could just have a link on the source page (with target="_blank") to a new page that would just output the XML using Response.Write, having set the Content-Disposition header to inline, and Response.ContentType to "text/xml".
That works nicely with FireFox and Chrome, but in IE10, I get the security warning about "Do you want to view only the webpage content that was delivered securely?"
Research shows that this message is displayed when the page contains "mixed content". That is, when some of the content is in "https", and some is in "http". That is not the case in my scenario, as the entire content is just the XML document, which doesn't even contain a reference to "http" in it.
I found several articles about this, and they suggest changing the page to use only https, or changing the IE security settings to "Enable" mixed content without prompting:
http://blog.httpwatch.com/2009/04/23/fixing-the-ie-8-warning-do-you-want-to-view-only-the-webpage-content-that-was-delivered-securely/
http://blogs.msdn.com/b/ieinternals/archive/2009/06/22/https-mixed-content-in-ie8.aspx
http://blog.httpwatch.com/2009/09/17/even-more-problems-with-the-ie-8-mixed-content-warning/
But, again, I have no "http" content on the "page"!
How can I display "raw" XML content in IE without this prompt?
I did this for an internal debugging app i made. It works in IE without any issues/popups. BUT, it's not really "raw XML", but more like xml -> html displayed in a div (still looks like XML though) as plain text. I made it using webapi, and also used angularjs, but you can change the angular to straight jquery.
Not sure if you're only after a straight up raw XML answer, but if you just want to display XML in text form, this should help you or at least give you some inspiration lol:
api action: returns xml through ajax. The webresponse().response = string that contains xml.
public HttpResponseMessage GetResponse(RequestDTO requestDTO)
{
return new HttpResponseMessage()
{
Content = WebResponse(requestDTO).Response
};
}
angular part:
$http.post('api/getresponse', requestData)
.success(function (data) {
$scope.response.xml = data;
});
html part:
<h3>XML Response</h3>
<pre highlight="response.xml" class="xml response"></pre>
Edit
To answer your questions:
"highlight" is a directive, and i think i originally made it because i was going to try and add code highlighting, but never did. But all it does is this:
angular.element(elem).text(value);
equivalent to the $(jquery).text(value); function.
As for the xml/response class, all it does is XDocument.Parse(xml), and return as new StringContent();
edited snippet from my code:
protected ResponseDTO WebResponse(RequestDTO requestDTO)
{
//....
var response = myRequest.GetXmlResponse(webResponse);
return new ResponseDTO()
{
Headers = new StringContent("....");
Response = new StringContent(response.ToString())
};
}
public XDocument GetXmlResponse(HttpWebResponse webResponse)
{
return XDocument.Parse(xmlResponse(webResponse, Encoding.UTF8));
}
the ajax is returned as Content-Type: text/plain; charset=utf-8
Summary
I'm having style issues when flipping master pages via a button event in asp.net 4.0. The new master switches, but the css from the old master remains. I don't understand how this could happen as the styles are defined within the head of the old master, and i can clearly see via the markup the new master is being displayed with whats supposed to be a totally different set of styles. Also, viewing source shows all the new css declarations in the head. How can i get this to "refresh" or "reload"?
Some details
I'm implementing a mobile version of my asp.net site. If a mobile device is detected i set a cookie and switch the master page in the preinit to a mobile friendly one. This works fine:
protected virtual void Page_PreInit(Object sender, EventArgs e)
{
if (IsMobile)
this.Page.MasterPageFile = "m-" + this.Page.MasterPageFile;
}
I have a "full site" button at the bottom that allows you to flip back and forth between the mobile and desktop view. When clicking it, i change the value in the cookie. Then when the page redirects to itself, the value is checked, and it gives the respective masterpage. This also "works", i can tell the right masterpage is rendering via markup. Except the styles from the mobile version remain even when the desktop master is being displayed. I did the redirect thinking it would prevent this.
// desktop/mobile site toggle button click event
protected void viewMobileButton_Click(Object sender, EventArgs e)
{
HttpCookie isMobileCookie = Cookies.snatchCookie("isMobile");
if (bool.Parse(isMobileCookie.Value))
Cookies.bakeCookie("isMobile", "false");
else
Cookies.bakeCookie("isMobile", "true");
Response.Redirect(Request.RawUrl);
}
This is the first time I've done anything like this, and not sure if i'm even going about it the right way, or how to debug from here. Thanks in advance for any help.
Edit
Ok, so i figured out it's related to the JQuery Mobile Scripts. JQuery Mobile has this way of tying pages together. I don't fully understand it, i think they use it for page transitions, and it's preventing my new CSS from registering. When i turn it off, my masterpage flips fine with css included. I'm looking into a way to turn off JQuery Mobile before my redirect. Note sure how though yet.
The problem ended up being related to JQuery Mobile AJAX for page-transitions. JQuery Mobile does not load the head of the document on additional page requests after the first.
So when i'd switch the mobile master to the desktop master, the head of the document wouldn't load to bring in my styles. There are a few way's this can be fixed:
This way just turns off AJAX altogether, and fixes the problem, but then you can't benefit from it:
<form data-ajax="false">
This is a way to do it problematically, but remind you, it will not work via an event after initialization of JQuery Mobile, so again you can't benefit from it:
$.mobile.ajaxEnabled = false;
The above two solutions i support could work if you redirected through a page first if you have to use an onclick event and an event handler.
A better solution is to add rel="external" to the link to tell JQM it's and outgoing link.
<a href="myself.com?mobile=true" rel="external" >
But because i couldn't run some code i wanted to in order to change the cookie, i had to pass a query string parameter, check it on the preinit, then set the cookie which my page also looks at on the preinit and flips the master.
Here's my full solution below in case someone is out there doing the exact same thing. Note because my website is using aliasing, i had to read Request.RawUrl and parse it myself since the Request.QueryString object did not contain the values i passed.
// reusable function that parses a string in standard query string format(foo=bar&dave=awesome) into a Dictionary collection of key/value pairs
// return the reference to the object, you have to assign it to a local un-instantiated name
// will accept a full url, or just a query string
protected Dictionary<string, string> parseQueryString(string url)
{
Dictionary<string, string> d = new Dictionary<string, string>();
if (!string.IsNullOrEmpty(url))
{
// if the string is still a full url vs just the query string
if (url.Contains("?"))
{
string[] urlArray = url.Split('?');
url = urlArray[1]; // snip the non query string business away
}
string[] paramArray = url.Split('&');
foreach (string param in paramArray)
{
if (param.Contains("="))
{
int index = param.IndexOf('=');
d.Add(param.Substring(0, index), param.Substring(++index));
}
}
}
return d;
}
Then i just use my dictionary object to evaluate and rebuild my url with the opposite mobile value, dynamically setting the href on the toggle link. Some code is obviosuly left out, but for perspective, base._iPage.QueryStringParams hold my dictionary object that was returned, and base._iPage.IsMobile is just a bool property i also have via the page interface i use, that all my pages, and user controls, ect, can talk to.
// get the left side fo the url, without querystrings
StringBuilder url = new StringBuilder(Request.RawUrl.Split('?')[0]);
// build link to self, preserving query strings, except flipping mobile value
if (base._iPage.QueryStringParams.Count != 0)
{
if (base._iPage.QueryStringParams.ContainsKey("mobile"))
{
// set to opposite of current
base._iPage.QueryStringParams["mobile"] = (!base._iPage.IsMobile).ToString();
}
int count = 0;
url.Append('?');
// loop through query string params, and add them back on
foreach (KeyValuePair<string, string> item in base._iPage.QueryStringParams)
{
count++;
url.Append(item.Key + "=" + item.Value + (count == base._iPage.QueryStringParams.Count ? "" : "&" ));
}
}
// assign rebuild url to href of toggle link
viewMobileButton.HRef = url.ToString();
}
Then on my pageinit this is where i actually check, first the quesry string, then the cookie, if neither of those are present, i run my mobile detection method, and set a cookie, and my interface bool property for easy access to conditionals that depends on it.
QueryStringParams = base.parseQueryString(Request.RawUrl);
if (QueryStringParams.ContainsKey("mobile") ? QueryStringParams["mobile"].ToLower().Equals("true") : false)
{
Cookies.bakeCookie("isMobile", "true"); // create a cookie
IsMobile = true;
}
else if (QueryStringParams.ContainsKey("mobile") ? QueryStringParams["mobile"].ToLower().Equals("false") : false)
{
Cookies.bakeCookie("isMobile", "false"); // create a cookie
IsMobile = false;
}
else
{
IsMobile = base.mobileDetection();
}
if (IsMobile)
this.Page.MasterPageFile = "m-" + this.Page.MasterPageFile;
}
I've been trying to solve this problem since this morning, and I know I'm missing something obvious here but I can't seem to find it.
We are using an XML file that is published to the server which contains translations of all the standard words, such as 'read more'. It is a page with a component that is localized in the appropriate publication.
In our Razor templates we use the following code below a plain news Summary item which in turn links to the full item.
<a tridion:href="#news.ID" class="more" ><%=DefaultLabels.TranslatedTerm(((HomePage)Page).Location, "read_more")%></a>
Thing is, the server tag works just fine, but gets resolved as
<tridion:ComponentLink runat="server" PageURI="tcm:15-407-64" ComponentURI="tcm:15-1475" TemplateURI="tcm:0-0-0" AddAnchor="false" LinkText="<%= DefaultLabels.TranslatedTerm(((HomePage)Page).Location, "read_more") %>" LinkAttributes=" class="more"" TextOnFail="true"/>
As you might notice, it gets written as plain text on the page (no surprise there because the LinkText parameter is declared as String in the first place according to the liveDocs).
If I take away the
tridion:href
in the first example, and write it as
href
It works fine, the code resolves into a translated string and it's even linked... to nothing more than the TCM ID of the component, not the right page with the full news item on it.
I've tried creating a function in Razor, tried replacing the linkText, tried setting the ComponentLink in the template itself, but to no avail. I feel that it should work with just a minor adjustment to this template's code, but I fail to see it and I've started looking at custom TBB's to handle the code.
Anyone have an idea how to resolve this?
EDIT:
Chris' answer was actually the one I was looking for in this particular situation, but I feel that I should point out that Priyank's function is something that should be regarded as such as well. So thank you both for the help, it made my life somewhat easier now!
I hope this razor function will help you lot. This is very helpful function to render the link tag from the component link or external link.
#helper RenderLink(
dynamic link, // the link to render. Handles components + internal / external links
string cssClass = null, // optional custom CSS class
string title = null // optional link text (default is the title of the component being linked to)
)
{
if(link == null)
{
return;
}
if (title == null)
{
title = link.title;
}
string classAttr = string.IsNullOrEmpty(cssClass) ? "" : " class='" + cssClass + "'";
dynamic href;
string tridionLink = "";
string targetAttr = "";
if (link.Schema.Title == "External Link")
{
href = link.link;
}
else if (link.Schema.Title == "Internal Link")
{
href = link.link;
tridionLink = "tridion:";
}
else
{
href = link;
tridionLink = "tridion:";
}
if(link.target != null)
{
targetAttr = link.target == "New window" || link.target == "Popup" ? " target='_blank'" : "";
}
<a #(tridionLink)href="#href"#classAttr#targetAttr>#title</a>
}
I would suggest not using the default templates for resolving your links, rather output the link yourself something like this:
<tridion:ComponentLink runat="server" PageURI="tcm:15-407-64"
ComponentURI="tcm:15-1475" TemplateURI="tcm:0-0-0"
AddAnchor="false" LinkAttributes=" class="more""
TextOnFail="true">
<%=DefaultLabels.TranslatedTerm(((HomePage)Page).Location, "read_more") %>
</tridionComponentLink>
Better still you might consider outputting TCDL rather than the Taglib/ServerControl