Archive for ASP.NET tag
Creating RSS feeds in ASP.NET MVC
ASP.NET’s MVC -is the technology that brought me to Microsoft and the west-coast and it’s been fun getting to grips with it these last few weeks.
Last week I needed to expose RSS feeds and checked out some examples online but was very disappointed.
If you find yourself contemplating writing code to solve technical problems rather than the specific business domain you work in you owe it to your employer and fellow developers to see what exists before churning out code to solve it.
The primary excuse (and I admit to using it myself) is “X is too bloated, I only need a subset. I can write that quicker than learn their solution.” but a quick reality check:
- Time – code always takes longer than you think.
- “Bloat” – indicates the problem is more complex than you realize.
- Growth – todays requirements will grow tomorrow.
- Maintenance – fixing code outside your business domain.
- Isolation – nobody coming in will know your home-grown solution.
The RSS examples I found had their own ‘feed’ and ‘items’ classes and implemented flaky XML rendering by themselves or as MVC view pages.
If these people had spent a little time doing some research they would have discovered .NET’s built in SyndicatedFeed and SyndicatedItem class for content and two classes (Rss20FeedFormatter and Atom10FeedFormatter ) to handle XML generation with correct encoding, formatting and optional fields.
All that is actually required is a small class to wire up these built-in classes to MVC.
using System;
using System.ServiceModel.Syndication;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Xml;
namespace MyApplication.Something
{
public class FeedResult : ActionResult
{
public Encoding ContentEncoding { get; set; }
public string ContentType { get; set; }
private readonly SyndicationFeedFormatter feed;
public SyndicationFeedFormatter Feed{
get { return feed; }
}
public FeedResult(SyndicationFeedFormatter feed) {
this.feed = feed;
}
public override void ExecuteResult(ControllerContext context) {
if (context == null)
throw new ArgumentNullException("context");
HttpResponseBase response = context.HttpContext.Response;
response.ContentType = !string.IsNullOrEmpty(ContentType) ? ContentType : "application/rss+xml";
if (ContentEncoding != null)
response.ContentEncoding = ContentEncoding;
if (feed != null)
using (var xmlWriter = new XmlTextWriter(response.Output)) {
xmlWriter.Formatting = Formatting.Indented;
feed.WriteTo(xmlWriter);
}
}
}
}
In a controller that supplies RSS feed simply project your data onto SyndicationItems and create a SyndicationFeed then return a FeedResult with the FeedFormatter of your choice.
public ActionResult NewPosts() {
var blog = data.Blogs.SingleOrDefault();
var postItems = data.Posts.Where(p => p.Blog = blog).OrderBy(p => p.PublishedDate).Take(25)
.Select(p => new SyndicationItem(p.Title, p.Content, new Uri(p.Url)));
var feed = new SyndicationFeed(blog.Title, blog.Description, new Uri(blog.Url) , postItems) {
Copyright = blog.Copyright,
Language = "en-US"
};
return new FeedResult(new Rss20FeedFormatter(feed));
}
This also has a few additional advantages:
- Unit tests can ensure the ActionResult is a FeedResult
- Unit tests can examine the Feed property to examine results without parsing XML
- Switching to Atom format involved just changing the new Rss20FeedFormatter to Atom10FeedFormatter
[)amien
Localizing MVC for ASP.NET views and master pages
Microsoft’s MVC for ASP.NET is still under serious development but at the moment support for localization is a little weak. Here’s one approach that works with the 04/16 source-drop.
LocalizingWebFormViewLocator class
This class helps by trying to identify language-specific versions of views, user controls and master-pages where they exist, falling back to the generic one where necessary.
public class LocalizingWebFormViewLocator : ViewLocator {
public LocalizingWebFormViewLocator() : base() {
ViewLocationFormats = new[] { "~/Views/{1}/{0}.{2}aspx", "~/Views/{1}/{0}.{2}ascx", "~/Views/Shared/{0}.{2}aspx", "~/Views/Shared/{0}.{2}ascx" };
MasterLocationFormats = new[] { "~/Views/{1}/{0}.{2}master", "~/Views/Shared/{0}.{2}master" };
}
protected override string GetPath(RequestContext requestContext, string[] locationFormats, string name) {
string foundView = FindViewLocation(locationFormats, requestContext, name, CultureInfo.CurrentUICulture.Name + ".");
if (String.IsNullOrEmpty(foundView))
foundView = FindViewLocation(locationFormats, requestContext, name, "");
return foundView;
}
protected string FindViewLocation(string[] locationFormats, RequestContext requestContext, string name, string cultureSuffix) {
string controllerName = requestContext.RouteData.GetRequiredString("controller");
foreach (string locationFormat in locationFormats) {
string viewFile = string.Format(CultureInfo.InvariantCulture, locationFormat, name, controllerName, cultureSuffix);
if (HostingEnvironment.VirtualPathProvider.FileExists(viewFile))
return viewFile;
}
return null;
}
}
Using the class
To use the class you must set the ViewLocator on the WebFormViewEngine to a new instance of LocalizingWebFormViewLocator (either in the constructor or in your common controller subclass) and ensure that any master pages are specified on the RenderView calls to ensure the localized version is detected.
public class HomeController : Controller {
public HomeController() {
((WebFormViewEngine)ViewEngine).ViewLocator = new LocalizingWebFormViewLocator();
}
public ActionResult Index() {
return RenderView("Index", "Site");
}
public ActionResult About() {
return RenderView("About", "Site");
}
}
You must also ensure the thread’s current UI culture is set. The easiest way to do this is to specify the following in your web.config file’s system.web section which will pick it up automatically from the user’s browser settings via the HTTP language-accept header.
<globalization responseEncoding="UTF-8" requestEncoding="UTF-8" culture="auto" uiCulture ="auto" />

Then all you need to do is create views and master pages that have the culture name appended between the name and .aspx, e.g:
/Views/Home/Index.aspx (common fall-back for this view)
/Views/Home/Index.ja.aspx (Japanese view)
/Views/Home/Index.en-GB.aspx (British English view)
/Views/Shared/Site.Master (common fall-back for this masterpage)
/Views/Shared/Site.ja.Master (Japanese masterpage)
Caveats
There are some limitations to this solution:
Only primary language is attempted
Only the user’s primary language specified in their browser is attempted despite browsers having a complete list in order of preference. Ideally we would scan down this entire list before giving up but that would need more code and there is the issue of whether scanning for several languages across several folders could be too much of a performance hit.
Specifying the masterpage on RenderView
It would be nice if you didn’t have to specify the masterpage on renderview but if you do not then the ViewLocator never gets called to resolve the actual masterpage address. This may be for backward compatibility within MVC.
Creating files in Visual Studio
Visual Studio 2008 seems to get a little confused if you create a Index.ja.aspx or Site.ja.aspx – whilst the files are created okay the names are not and you will need to adjust the class names to ensure they don’t conflict and make sure the opening declaration on the .aspx file points to the right code-behind page and inherits from the correct name.
Of course the beauty of this approach is you can mix-and-match using dedicated views where required and localising labels in the fall-back view when it isn’t.
[)amien
5 signs your ASP.NET application may be vulnerable to HTML injection
If you don’t encode data when using any of the following methods to output to HTML your application could be compromised by unexpected HTML turning up in the page and modifying everything from formatting though to capturing and interfering with form data via remote scripts (XSS). Such vulnerabilities are incredibly dangerous.
Using MonoRail or Microsoft’s MVC does not make you automatically immune – use {! } in MonoRail’s Brail engine and the HtmlHelpers in Microsoft’s MVC to ensure correct encoding.
Just imagine post.Author contains “><script src=”http://abadsite.com”></script> after an unscrupulous user entered that into a field your application uses and it got into the database. The following typical ASP.NET techniques would leave you open.
1. You use <%= %> or <%# %> tags to output data
Example showing outputting literals with <%= %> :
// Vulnerable
<p>Posted by <%= post.Author %></p>
// Secure
<p>Posted by <%= HttpUtility.HtmlEncode(post.Author) %></p>
2. You use Response.Write
Example showing writing out attributes with Response.Write and String.Format, again post.Author could contain <script>:
// Vulnerable
Response.Write(String.Format("<input type=\"text\" value=\"{0}\" />", post.Author);
// Secure
Response.Write(String.Format("<input type=\"text\" value=\"{0}\" />", HttpUtility.HtmlAttributeEncode(post.Author));
3. You set HRef or Src on HtmlAnchor, HtmlImage or HtmlnputImage controls
In general the HtmlControls namespace are very well behaved with encoding but there is a bug in the code that attempts to adjust the relative url’s for href and src attributes which causes those properties to bypass encoding (I’ve reported this to Microsoft).
Example showing anchor HRef attribute abuse:
// Vulnerable
outputDiv.Controls.Add(new HtmlAnchor() { Text = "Test", HRef = post.Author } );
// Secure
outputDiv.Controls.Add(new HtmlAnchor() { Text = "Test", HRef = HttpUtility.HtmlAttributeEncode(post.Author) } );
4. You set the Text property of WebControls/WebForms
You would imagine the high-level WebForms controls would take care of encoding and you’d be wrong.
Example showing the Label control being so easily taken advantage of:
// Vulnerable
outputDiv.Controls.Add(new Label() { Text = post.Author } );
// Secure
outputDiv.Controls.Add(new Label() { Text = HttpUtility.HtmlEncode(post.Author) } );
The one exception to this is the Text property of input controls – as they put the value into an attribute and therefore call HttpUtility.HtmlAttributeEncode for you.
5. You use the LiteralControl
LiteralControl is a useful control for adding text to the output stream that doesn’t require it’s own tag. It also helpfully, and uncharacteristically, provides a useful constructor. Unfortunately it fails encode the output.
Example showing poor LiteralControl wide open:
// Vulnerable
outputDiv.Controls.Add(new LiteralControl(post.Author));
// Secure
outputDiv.Controls.Add(new LiteralControl(HttpUtility.HtmlEncode(post.Author)));
- Encode data in the database – your contaminated data will be difficult to use elsewhere and will end up double-encoded
- Look for script on submit – you won’t catch every combination and it might prevent valid data
- Trap entry with client-side code – it is trivially bypassed
Just encode the output :)
[)amien
(The samples use .NET 3.5 object initializer syntax for brevity as many affected controls do not have useful constructors)
ASP.NET MVC preview available
The first public preview of Microsoft’s ASP.NET MVC (model view controller) framework is now available.
Download ASP.NET 3.5 Extensions (EXE) (3.7 MB)
Download MVC Toolkit (ZIP) (400 KB)
The project takes cues from Ruby on Rail’s success and looks to address dissatisfaction with the testability and maintainability of WebForms applications and provides an alternative approach that is centered around views, models, controllers with a clear separation of concern and the ability to mock test the individual elements.The official documentation is online and there is a great four-part series over at Scott Guthrie’s blog which covers:
Phil Hack and Rob Conery are both now at Microsoft and working on the framework, they have some interesting things to say on it too:
- Extending to add conventions
- Test-driven development and dependency injection
- Using user interface (HTML) helpers
- Using RESTful architecture
- Using Ajax
A few other people have already written about the subject too:
- Jeffrey Palermo’s podcast interview
- Fredrol Normén on exception handling
- Brad Abrams on creating an RSS feed with LinqToSql
- Dino Esposito on architecture
- MVC Contrib open-source additions & helpers
Most of the examples and many of the routines/helpers fail to encode output which opens them up to HTML and script injection vulnerabilities. Remember to HttpUtility.HtmlEncode output and use Reflector if you’re unsure whether a function is encoding correctly.
The CTP requires Visual Studio 2008 to get the most out if it so either head over to MSDN Subscriber Downloads or grab a 90-day trial edition if you don’t already have it installed.
[)amien
How dangerous is HTML injection?
A few years ago I believed that HTML and SQL injection vulnerabilities were headed for extinction. Thanks to object-relational mapping tools SQL injection continues to die but HTML and script injection vulnerabilities are as popular as ever.
Part of the problem stems from the “back-to-basics” approach to rendering web pages, throwing out classes and controls for string-based libraries (primitive obsession) and helpers which do not encode HTML or even offer a concise simple syntax to do so.
MonoRail was one such project but they took feedback on board and addressed the issue although I was surprised it had got as far as release candidate 2 with such a serious oversight.
Other projects have been less reactive when advised of the problem and I can’t help but wonder if I am not getting the severity of the issue across. This isn’t just an annoyance but a real security problem.
- HttpUtility.HtmlEncode (.NET)
- Server.HtmlEncode (ASP)
- htmlentities/htmlspecialchars (PHP)
- html_escape (Rails)
- {! } (MonoRail Brail)
and your web apps output data then they are likely open to HTML & script injection vulnerabilities.
Vulnerable code often looks like this:
myLabel.Text = Request.Form["Something"];
Response.Write(Request.Cookies["AddedProduct"]);
<%= myDataReader[0] %>
<? php echo get_the_title() ?>
For more ASP.NET examples check out 5 signs your ASP.NET application may be vulnerable to HTML injection.
Let’s start by considering the actors involved:
Visitor to visitor
If your site stores input from an external user (visitor) and displays it to another then you could be exposed to this scenario. Many sites do this although it is not always immediately recognised – an internet banking site does not seem an obvious candidate until you consider that you may put a textual reference on payments made to another person. If you know they use a vulnerable internet banking solution…
A worst-case scenario here would be that one visitor could steal another’s login credentials and exploit whatever rights that might give him – anything from posting messages to stealing funds.
Visitor to staff
Not all sites exchange data between users but if your site collects information from visitors chances are it presents this information to staff. Internal systems used to examine it are often considered less vulnerable which is a mistake. Remember *all* data provided from a user should be considered to be a potential avenue for a dangerous payload, e.g. even the language-accepts or user-agent strings.
When exploited internal systems can reveal information in bulk about the users, the system and the administration accounts used to manage it. Gaining access to these details brings all the privileges those accounts have to offer which can be catastrophic.
Staff to visitor
It is easy to forget that many frauds are perpetuated by people on the inside. A staff member given the ability to present text to the user via a website has the ability to modify any page that the content is presented on which if it includes a login page (perhaps for system status messages) then capturing login details to a server of their own choice is easy.
Security operators with access to reset (but not view) passwords would find this attack particularly enticing given that they do not need to reset the users account and therefore raise any awareness. An insider can perpetuated the fraud and may be in a position to further conceal it within the organisation.
Next steps?
I can envisage a sequence of steps that start with discovery of injectable systems through detection of script-enabled into form capture-and-forward and async logging of passwords through XmlHttp.
Detailing those steps would certainly raise awareness and help developers appreciate the severity of the issue but how do I make sure that information isn’t abused?
Disclosure is a double-edged sword but then you can’t have security through obscurity… I wonder how many crackers/black hackers already utilise these techniques for nefarious means.
.NET developers might like to check out the slides from the Web Application Security talk I gave at the Guernsey Software Developer Forum which demonstrates exploitable, exploits and safe alternatives for preventing HTML and SQL injection.
[)amien