Skip to main content

XSS Terminate

There may eventually be a time when you need to allow people to write some HTML on your site. Maybe you have a bulletin board or something or else possibly you are writing some kind of email app or wiki.

The main problem with this is that you potentially open your site to Cross Site Scripting (XSS) attacks (more info at http://en.wikipedia.org/wiki/Cross-site_scripting). Basically in an XSS attack, someone puts in a little JavaScript in your site via a user input and when someone else looks at the page the first person steals the other's cookies. In fact you can unwittingly open your site to XSS attacks just by forgetting to encode all your user inputted text by using the h() function.

This is essentially a backwards approach to the problem however. What you really want to do is close everything down by default and then make a mental effort to allow it to use HTML. Even then, you may run into the problem of people running script tags.

Enter XSS Terminate. This is a handy little plug in which will basically strip all HTML tags out of any field going to and from the database by default. You can additionally apply either Rails' sanitize method to strip out scripts while allowing some basic HTML tags or else use html5lib_sanitize to strip out the scripts while allowing for normal browser quirks (sanitize requires strict XHTML standards).

In any case, the real reason I am writing this is that the XSS terminate usage instructions contain a couple of errors.

Where the site says

  class Review < ActiveRecord::Base
xss_sanitize :sanitize => [ :body, :author_name]
end
I found this didn't work for me. After some trial and error I found the following fix

  class Review < ActiveRecord::Base
xss_terminate :sanitize => [ :body, :author_name]
end
I also had problems with
class Message < ActiveRecord::Base
xss_terminate :except => [ :body ], :sanitize => [ :title ]
end
instead I did the following

class Message < ActiveRecord::Base
xss_terminate :except => [ :body, :title ]
xss_terminate :sanitize => [ :title ]
end
Basically though you probably don't want to use :except without using :sanitize or :html5lib_sanitize. Ever... And I mean it... Otherwise the next email you get will be from your sysadmin (if you are lucky) or your lawyer (if you are not).

In any case, the next problem is that the HTML elements entered by the user will probably read your default stylesheets. While you may want this, you may actually want the HTML to look kind of clean and distinct from your site (to highlight the fact that it is user generated content).

There is no easy way unfortunately to reset the css in a specific section so I had to search around for a default browser stylesheet online and then manually prefix every element with .text-entry. Because I am a nice guy, I am including it here (just do a text replace on .text-entry to use your own class name).

Enjoy!

.text-entry div,.text-entry dl,.text-entry dt,.text-entry dd,.text-entry ul,.text-entry ol,.text-entry li,.text-entry h1,.text-entry h2,.text-entry h3,.text-entry h4,.text-entry h5,.text-entry h6,.text-entry pre,.text-entry form,.text-entry fieldset,.text-entry input,.text-entry textarea,.text-entry p,.text-entry blockquote,.text-entry th,.text-entry td {
margin:0 !important ;
padding:0 !important ;
background:none !important;
background-color:none !important ;
border:none !important ;
font-family: Arial, Helvetica, sans-serif !important ;
color:#000 !important;
text-transform:none !important;
}
.text-entry table {
border-collapse:collapse;
border-spacing:0;
}
.text-entry fieldset,.text-entry img {
border:0;
}
.text-entry address,.text-entry caption,.text-entry cite,.text-entry code,.text-entry dfn,.text-entry em,.text-entry strong,.text-entry th,.text-entry var {
font-style:normal;
font-weight:normal;
}
.text-entry caption,.text-entry th {
text-align:left;
}
.text-entry h1,.text-entry h2,.text-entry h3,.text-entry h4,.text-entry h5,.text-entry h6 {
font-size:100%;
font-weight:normal;
}
.text-entry q:before,.text-entry q:after {
content:'';
}
.text-entry abbr,.text-entry acronym { border:0;
}

.text-entry address,
.text-entry blockquote,
.text-entry dd, .text-entry div,
.text-entry dl, .text-entry dt, .text-entry fieldset, .text-entry form,
.text-entry h1, .text-entry h2, .text-entry h3, .text-entry h4,
.text-entry h5, .text-entry h6,
.text-entry ol, .text-entry p, .text-entry ul, .text-entry center,
.text-entry dir, .text-entry hr, .text-entry menu, .text-entry pre { display: block }
.text-entry li { display: list-item; margin-left: 10px !important }
.text-entry head { display: none }
.text-entry table { display: table }
.text-entry tr { display: table-row }
.text-entry thead { display: table-header-group }
.text-entry tbody { display: table-row-group }
.text-entry tfoot { display: table-footer-group }
.text-entry col { display: table-column }
.text-entry colgroup { display: table-column-group }
.text-entry td, .text-entry th { display: table-cell }
.text-entry caption { display: table-caption }
.text-entry th { font-weight: bolder; text-align: center }
.text-entry caption { text-align: center }
.text-entry body { margin: 8px }
.text-entry h1 { font-size: 2em; margin: .67em 0 }
.text-entry h2 { font-size: 1.5em; margin: .75em 0 }
.text-entry h3 { font-size: 1.17em; margin: .83em 0 }
.text-entry h4, .text-entry p,
.text-entry blockquote, .text-entry ul,
.text-entry fieldset, .text-entry form,
.text-entry ol, .text-entry dl, .text-entry dir,
.text-entry menu { margin: 1.12em 0 }
.text-entry h5 { font-size: .83em; margin: 1.5em 0 }
.text-entry h6 { font-size: .75em; margin: 1.67em 0 }
.text-entry h1, .text-entry h2, .text-entry h3, .text-entry h4,
.text-entry h5, .text-entry h6, .text-entry b,
.text-entry strong { font-weight: bolder }
.text-entry blockquote { margin-left: 40px; margin-right: 40px }
.text-entry i, .text-entry cite, .text-entry em,
.text-entry var, .text-entry address { font-style: italic }
.text-entry pre, .text-entry tt, .text-entry code,
.text-entry kbd, .text-entry samp { font-family: monospace }
.text-entry pre { white-space: pre }
.text-entry button, .text-entry textarea,
.text-entry input, .text-entry select { display: inline-block }
.text-entry big { font-size: 1.17em }
.text-entry small, .text-entry sub, .text-entry sup { font-size: .83em }
.text-entry sub { vertical-align: sub }
.text-entry sup { vertical-align: super }
.text-entry table { border-spacing: 2px; }
.text-entry thead, .text-entry tbody,
.text-entry tfoot { vertical-align: middle }
.text-entry td, .text-entry th { vertical-align: inherit }
.text-entry s, .text-entry strike, .text-entry del { text-decoration: line-through }
.text-entry hr { border: 1px inset }
.text-entry ol, .text-entry ul, .text-entry dir,
.text-entry menu, .text-entry dd { margin-left: 40px }
.text-entry ol { list-style-type: decimal }
.text-entry ol ul, .text-entry ul ol,
.text-entry ul ul, .text-entry ol ol { margin-top: 0; margin-bottom: 0 }
.text-entry u, .text-entry ins { text-decoration: underline }
.text-entry br:before { content: "\A" }
.text-entry :before, .text-entry :after { white-space: pre-line }
.text-entry center { text-align: center }
.text-entry :link, .text-entry :visited { text-decoration: underline }
.text-entry :focus { outline: thin dotted invert }
.text-entry a {color:blue !important;}
.text-entry a:visited {color:purple !important;}

Comments

skuunk said…
I just wanted to make an update to this article...

It appears that the standard Rails 2 sanitize function is a little heavy handed for use with Yahoo's Rich Text Editor. Yes it allows HTML and strips out any script tags, but it also strips out the style attribute as well.

In any case, replacing it with html5lib_sanitize seems to do with trick...
Anonymous said…
Who knows where to download XRumer 5.0 Palladium?
Help, please. All recommend this program to effectively advertise on the Internet, this is the best program!
Anonymous said…
GrEeTiNgS, www.skuunk.com!
[url=http://cialisgenericoad.pun.pl/ ]vendo cialis online[/url] [url=http://viagragenericons.pun.pl/ ] viagra en espana[/url] [url=http://comprarcialisal.pun.pl/ ] cialis online[/url] [url=http://viagragenericomo.pun.pl/ ]comprar viagra [/url] [url=http://compracialishl.pun.pl/ ]vendo cialis [/url] [url=http://comprarviagrawk.pun.pl/ ]comprar viagra en espana[/url]
Anonymous said…
Very nicce!

Popular posts from this blog

Master of my domain

Hi All, I just got myself a new domain ( http://www.skuunk.com ). The reason is that Blogspot.com is offering cheap domain via GoDaddy.com and I thought after having this nickname for nigh on 10 years it was time to buy the domain before someone else did (also I read somewhere that using blogspot.com in your domain is the equivalent of an aol.com or hotmail.com email address...shudder...). Of course I forgot that I would have to re-register my blog everywhere (which is taking ages) not to mention set up all my stats stuff again. *sigh*. It's a blogger's life... In any case, don't forget to bookmark the new address and to vote me up on Technorati !

Speeding up RSpec

So today I have been looking into getting our enormous battery of tests to run faster. I have yet to find anything that works for Cucumber, but I did find an interesting way to speed up RSpec which is detailed here. https://makandracards.com/makandra/950-speed-up-rspec-by-deferring-garbage-collection Basically, it seems that by not collecting garbage too frequently, you can make your tests run much faster (at the expense of memory management of course). We observed a 30% reduction in the time it takes to run an RSpec test suite. I did try to implement this on Cucumber, however because we need to store much more in memory to set up and tear down our objects, it meant that I kept running out of memory when I wasn't using the default Garbage Collection and the tests took even longer (so, buyer beware). I suppose if you had a small set of features though you might see some benefit.

Elixir - destructuring, function overloading and pattern matching

Why am I covering 3 Elixir topics at once? Well, perhaps it is to show you how the three are used together. Individually, any of these 3 are interesting, but combined, they provide you with a means of essentially getting rid of conditionals and spaghetti logic. Consider the following function. def greet_beatle(person) do case person.first_name do "John" -> "Hello John." "Paul" -> "Good day Paul." "George" -> "Georgie boy, how you doing?" "Ringo" -> "What a drummer!" _-> "You are not a Beatle, #{person.first_name}" end end Yeah, it basically works, but there is a big old case statement in there. If you wanted to do something more as well depending on the person, you could easily end up with some spaghetti logic. Let's see how we can simplify this a little. def greet_beatle(%{first_name: first_name}) do case first_name d